菜鸡的Java笔记 第二十四 - java 接口的基本定义
1.接口的基本定义以及使用形式
2.与接口有关的设计模式的初步认识
3.接口与抽象类的区别
接口与抽象类相比,接口的使用几率是最高的,所有的设计几乎都是围绕着接口进行的
但是要想把接口彻底弄明白,需要很长一段时间
接口是一种特殊的类,但是在接口里面的组成与类不同,比类的组成部分简单,主要由抽象方法和全局常量所组成
而接口使用 interface 关键字来定义
范例:定义一个接口
interface A{ // 定义了一个接口
public static final String MSG = "Hi";
public abstract void ptint();
}
public class Interface{
public static void main(String args[]){
// 无法实例化,但是可以调用
System.out.println(A.MSG);
}
}
在以后不管学习到系统类库的使用还是自己写代码的时候,接口里面的主要组成(98%)都是抽象方法
当一个接口定义完成之后,需要遵循如下的步骤进行接口的使用
接口一定要定义子类,子类利用 implements 关键字来实现(实现这个词可以理解为继承)接口,一个子类可以同时实现多个接口
秒杀抽象类的单继承局限,一个抽象类只能够被一个子类所继承
接口的子类(如果不是抽象类)那么必须覆写接口中的全部抽象方法
接口的对象利用子类对象的向上转型进行实例化操作
范例:使用接口
interface A{// 定义了一个接口
public static final String MSG = "Hi";
public abstract void ptint();
} interface B{
public abstract void fun();
}
class X implements A,B{ // 此时的X子类同时实现了B和B两个父接口
public void ptint(){
System.out.println("*******");
}
public void fun(){
System.out.println(MSG);
}
}
public class Interface{
public static void main(String args[]){
X x = new X();// 实例化子类对象
A a = x; // 子类为父接口实例化
B b = x; // 子类为父接口实例化
a.ptint();
b.fun();
}
}
/*
结果
********
Hi
*/
但是这个时候会有这样一种比较神奇的操作
细节:在进行转型的处理之中,真正有用处的不是这个父类(或是父接口),而是在于 new 的子类上
既然 X 属于两个父接口的共同子类,那么一旦是使用了这个子类实例化的接口对象就表示可以进行父接口的强制转换
范例:神奇的操作
interface A{// 定义了一个接口
public static final String MSG = "Hi";
public abstract void ptint();
} interface B{
public abstract void fun();
}
class X implements A,B{ // 此时的X子类同时实现了B和B两个父接口
public void ptint(){
System.out.println("*******");
}
public void fun(){
System.out.println(MSG);
}
}
public class Interface{
public static void main(String args[]){
A a = new X(); // X子类为父接口A 实例化
B b = (B)a;// 理解不了的操作
b.fun();
}
}
//结果:
B和A鸟关系都没有但是可以转换,因为X是子类
注意:关于接口的组成描述
接口里面在定义的时候就已经明确的给出了开发要求:抽象方法和全局常量,所以一下两种接口的定义从本质上讲是完全一样的
完整定义: 简化定义:
interface A{// 定义了一个接口 interface A{// 定义了一个接口
public static final String MSG = "Hi"; String MSG = "Hi";
public abstract void ptint(); void ptint();
} }
如果在定义接口方法的时候没有使用 public ,那么本质上也不是 default 权限,而默认就是 public
interface A{// 定义了一个接口
String MSG = "Hi";
void ptint();
}
class X implements A{ // 此时的X子类同时实现了B和B两个父接口
void ptint();
}
public class Interface{
public static void main(String args[]){ }
}
//结果:(出错:X中的 ptint()无法实现A中的 ptint(),正在尝试分配更低的访问权限:以前为 public)
很多时候为了防止一些开发者概念不清晰,所以以后建议在定义接口的时候永远都写上 public ,但是一般都不会去写 abstract
现在程序之中出现有类,抽象类,接口,这几者之间的联系就需要注意好了
一个普通类如果要实现接口又要求继承抽象类,则一定采用 extends 继承抽象类,再 implements 实现接口
格式:
class 子类 extends 抽象类 implements 接口1,接口2...{}
范例:观察子类的多继承
interface A{// 定义了一个接口
String MSG = "Hi";
public void ptint();
}
abstract class B{
public abstract void fun();
}
class X extends B implements A{ // 此时的X子类同时实现了B和B两个父接口
public void ptint(){}
public void fun(){}
}
public class Interface{
public static void main(String args[]){ }
} 另外除了以上的结构之外,一个抽象类还可以直接实现接口
范例:抽象类实现接口
interface A{// 定义了一个接口
String MSG = "Hi";
public void ptint();
}
abstract class B implements A{//这个时候抽象类有两个抽象方法
public abstract void fun();
}
class X extends B { // 此时的X子类同时实现了B和B两个父接口
public void ptint(){}
public void fun(){}
}
public class Interface{
public static void main(String args[]){ }
}
现在一定要知道,抽象类可以实现接口,但是反过来,接口可不能够继承抽象类,但是一个接口却可以使用 extends 关键字继承多个父接口
范例:接口多继承
interface A{// 定义了一个接口
public void ptintA();
}
interface B{
public void ptinB();
}
interface C extends A,B{// C 是A与B的子接口
public void ptintB();
}
class X implements C{
public void ptintA(){}
public void ptintB(){}
public void ptinC(){}
}
public class Interface{
public static void main(String args[]){ }
}
虽然接口本身只能够有抽象方法和全局常量,但是内部的结构是不受到限制的,那么也就是说一个接口的内部可以继续定义内部类,内部抽象类,内部接口
如果一个内部接口上使用了 static 定义,那么这个内部接口就属于外部接口
范例:使用 static定义内部接口
interface A{
static interface B{
public void ptint();
}
}
class X implements A.B{
public void ptint(){}
}
public class Interface{
public static void main(String args[]){ }
}
总之对于接口的使用可以发现有如下几点:
接口避免了单继承的局限,一个子类可以实现多个接口
接口中的权限统一为 public ,方法都是抽象方法,90%的情况下接口中很少定义全局常量
所有的内部类结构都不受到定义语法的限制,static 定义的内部接口就是一个外部接口
实际开发中接口的三个使用原则:
定制操作标准
表示一种能力
将服务器端的远程方法视图提供给客户端
*/
/* 接口的实际应用-- 标准
现实生活中对于接口这个名词应该不陌生例如:USB,PCI,VGA,HDMI,DVI等接口
以USB为主,描述一下接口的实际作用
范例:首先要定义出的就是接口
interface USB{
public void start();
public void stop();
}
public class Interface{
public static void main(String args[]){ }
}
不管什么样的USB设备只要一连接到电脑上,那么就需要默认执行固定的操作
范例:电脑上提供有支持USB的操作标准插入点
interface USB{
public void start();
public void stop();
}
class Computer{ // 电脑
public void plugin(USB usb){
usb.start();
usb.stop();
}
}
public class Interface{
public static void main(String args[]){ }
}
不管有多少设备,电脑的 plugin() 方法里面只要接收的是USB接口实例,那么操作的步骤就是固定的
范例:定义USB 的子类
interface USB{
public void start();
public void stop();
}
class Computer{ // 电脑
public void plugin(USB usb){
usb.start();
usb.stop();
}
}
class Flash implements USB {
public void start(){
System.out.println("开始使用U盘进行操作");
}
public void stop(){
System.out.println("U盘停止工作");
}
}
// 定义键盘
class Keyboard implements USB {
public void start(){
System.out.println("开始使用键盘操作");
}
public void stop(){
System.out.println("键盘停止工作");
}
}
public class Interface{
public static void main(String args[]){ }
}
现在的子类是按照严格的操作标准使用着
范例:程序调用处
interface USB{
public void start();
public void stop();
}
class Computer{ // 电脑
public void plugin(USB usb){
usb.start();
usb.stop();
}
}
class Flash implements USB {
public void start(){
System.out.println("开始使用U盘进行操作");
}
public void stop(){
System.out.println("U盘停止工作");
}
}
// 定义键盘
class Keyboard implements USB {
public void start(){
System.out.println("开始使用键盘操作");
}
public void stop(){
System.out.println("键盘停止工作");
}
}
public class Interface{
public static void main(String args[]){
Computer c = new Computer();
c.plugin(new Flash());//传递U盘对象
c.plugin(new Keyboard());// 传递键盘对象
}
}
此时如果有了接口标准,即便有几千万个子类,也是可以在一个接口上使用的,所以接口是定义标准
如果说的再高级一点 :接口可以连接两个不同的层
工厂设计模式的关键在于:对接口使用隐藏接口的具体子类
*/
/* 接口的应用--工厂设计模式(Factory,背)
下面首先编写一段简单的代码,来观察一下为什么会存在有工厂设计模式
范例:观察程序定义
interface Fruit{// 水果
public void eat();//吃
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃水果");
}
}
public class Interface{
public static void main(String args[]){
Fruit f = new Apple();
f.eat();
}
}
代码没有语法错误,但是有一个设计上的缺失,如果说现在假设Fruit 增加了一个子类, 并且主类想使用这个子类
interface Fruit{// 水果
public void eat();//吃
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果");
}
}
class Cherry implements Fruit{
public void eat(){
System.out.println("吃樱桃");
}
}
public class Interface{
public static void main(String args[]){
Fruit f = new Cherry();
f.eat();
}
}
此时发现如果要扩充程序却影响了客户端的执行,这样的设计就非常的不好了,那么如果想要解决这个问题,则可以参考JAVA可移植性
实现原理:
不可移植性:程序→操作系统:
可移植性:程序→JVM→操作系统:
范例:可以在客户端与接口之间引入一个中间层
面试题:请编写一个Factory程序
interface Fruit{// 水果
public void eat();//吃
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果");
}
}
class Cherry implements Fruit{
public void eat(){
System.out.println("吃樱桃");
}
}
class Factory{
public static Fruit getlnstance(String className){ // 直接取得接口实例
if("apple".equals(className)){
return new Apple();
}else if("cherry".equals(className)){
return new Cherry();
}else{
return null;
}
}
}
public class Interface{
public static void main(String args[]){ // 为了方便模拟化调用
Fruit f = Factory.getlnstance(args[0]);
if(f != null){
f.eat();
}
}
}
执行苹果操作: java Interface apple
执行樱桃操作: java Interface cherry
如果现在要想增加新的子类,那么不需要修改客户端,直接修改工厂类即可
代理设计模式的核心结构:真实主题是负责核心操作,而这个核心操作如果要想正常完成功能,就必须有代理主题来负责辅助功能实现
*/
/* 接口的应用--代理设计模式(Proxy,背)
所谓的代理结构指的是在接口上的一种应用,一个接口一个核心的操作主题
但是在整个操作的过程之中,如果只依靠核心的操作主题是无法完成所需要功能的,那么需要有一个代理的主题
代理主题完成所以的与核心主题有关的概念
范例:
interface Subject{// 核心操作主题
public void get();//核心操作
}
class RealSubject implements Subject{
public void get(){
System.out.println("大爷取回了被强行霸占的钱");
}
}
class ProxySubject implements Subject{
private Subject subject;// 代理的真实主题
public ProxySubject(Subject subject){
this.subject = subject;
}
public void prepar(){
System.out.println("追讨前的准备.........");
}
public void get(){
this.prepar();
this.subject.get();// 真实主题的讨债
this.destroy();
}
public void destroy(){
System.out.println("追讨完后的首尾:掩埋......");
}
} public class Interface{
public static void main(String args[]){ // 为了方便模拟化调用
Subject sub = new ProxySubject(new RealSubject());
sub.get();
}
}
*/
/* 抽象类与接口的区别(面试题)
到现在为止已经学习过了这么几个概念:抽象类,类,对象,接口,这些概念从开发上来讲什么关系呢?
所有类的抽象使用的就是接口,而且接口避免了单继承局限
面试题:请解释抽象类与接口的区别
区别 | 抽象类 | 接口 |
定义关键字 | abstract class | interface |
组成 | 属性,常量,抽象方法,构造方法,普通方法 | 抽象方法与全局常量 |
权限 | 可以使用各种权限 | 只能够 public |
子类实现 | 利用 extends 关键字可以继承一个抽象类 | 利用 implements 关键字可以实现多个接口 |
关系 | 抽象类可以实现多个接口 | 接口不能继承抽象类,接口却可以利用 extends 关键字实现接口的多继承 |
对象实例化 | 依靠子类对象的向上转型实现抽象类或接口 | 对象的实例化操作 |
设计模式 | 模版设计模式 | 工厂设计模式,代理设计模式 |
操作局限 | 单继承局限 | 没有单继承局限 |
通过以上的几点比较可以发现,抽象类与接口实际上都可以限制子类必须要覆写的方法要求,但是由于抽象类本身存在有单继承局限
所以在日后开发过程之中,如果发现抽象类与接口都可以同时使用的时候,优先考虑接口,而抽象类在实际的应用中往往是作为接口与普通类之间的过度累使用
总结
1.接口利用 interface 关键字定义,接口中定义方法的情况居多
2.接口利用对象向上转型实现接口对象的实例化操作,调用的方法是每个子类所覆写的方法
3.接口应用:标准(连接不同的两种类),工厂设计模式,代理设计模式
菜鸡的Java笔记 第二十四 - java 接口的基本定义的更多相关文章
- 菜鸡的Java笔记 第二十八 - java 包的定义
包的主要作用以及定义 包的导入操作 系统常见的开发包 jar 程序命令 包的定义 在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...
- 菜鸡的Java笔记 第二十六 - java 内部类
/* innerClass 从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的 讲解它的目的第一个是为了解释概念 ...
- 菜鸡的Java笔记 第二十九 - java 单例设计模式
SingleCase 单例设计模式 1.单例设计模式的特点 2.多例设计模式的特点 内容 单例设计模式 现在如果说有这么一个程序类 class S ...
- 菜鸡的Java笔记 第二十二 - java 对象多态性
本次只是围绕着多态性的概念来进行讲解,但是所讲解的代码与实际的开发几乎没有关系,而且多态一定是在继承性的基础上才可以操作的, 而本次将使用类继承的关系来描述多态的性质,实际的开发中不会出 ...
- “全栈2019”Java多线程第二十四章:等待唤醒机制详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java笔记(十四) 并发基础知识
并发基础知识 一.线程的基本概念 线程表示一条单独的执行流,它有自己的程序计数器,有自己的栈. 1.创建线程 1)继承Thread Java中java.lang.Thread这个类表示线程,一个类可以 ...
- Linux 笔记 - 第二十四章 配置 Tomcat
一.前言 Tomcat 是 Apache 软件基金会(Apache Software Foundation)Jakarta 项目中的核心项目,由 Apache.Sun 和其他一些公司及个人共同开发.使 ...
- Java笔记(二十四)……集合工具类Collections&Arrays
Collections 集合框架的工具类,方法全部为静态 Collections与Collection的区别 Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法 Collect ...
- 菜鸡的Java笔记 第二十五 wrapperClass 包装类
wrapperClass 包装类 1.包装类的特点 2.装箱与拆箱操作 3.数据转型处理 内容 Object 类可以接收 ...
随机推荐
- 【C++ Primer Plus】编程练习答案——第9章
1 // chapter09_golf.h 2 3 #ifndef LEARN_CPP_CHAPTER09_GOLF_H 4 #define LEARN_CPP_CHAPTER09_GOLF_H 5 ...
- 题解 [PA2019]Trzy kule
link Description 对于两个长度为 \(n\) 的 \(01\) 串 \(a_1,a_2,\dots,a_n\) 和 \(b_1,b_2,\dots,b_n\),定义它们的距离 \(d( ...
- bzoj1858SCOI 序列操作 (线段树)
题目大意: 给定一个长度为n的01序列为,现在有m种操作 \(0\ a\ b\) 把\([a,b]\)的数全部修改为0 \(1\ a\ b\) 把\([a,b]\)的数全部修改为1 \(2\ a\ b ...
- 分布式应用开发 | SpringBoot+dubbo+zookeeper实现服务注册发现 | 远程服务调用
前言 通过新建两个独立服务--提供者.消费者,模拟两个独立分布的应用,通过使用dubbo+zookeeper来实现远程服务调用. 目录 项目搭建 provider-server consumer-se ...
- python中函数里面冒号和函数后面的箭头是什么含义
函数里参数后的冒号其实是参数的类型建议,但是只是建议,就算你不按约定传也不会报错.而后面的箭头,则是函数返回值的类型建议.
- PAT (Basic Level) Practice (中文)1026 程序运行时间 (15分)
1026 程序运行时间 (15分) 要获得一个 C 语言程序的运行时间,常用的方法是调用头文件 time.h,其中提供了 clock() 函数,可以捕捉从程序开始运行到 clock() 被调用时所耗费 ...
- 4.19——数组双指针——26. 删除有序数组中的重复项 & 27. 删除有序数组中的重复项II & 80. 删除有序数组中的重复项 II
第一次做到数组双指针的题目是80: 因为python的List是可以用以下代码来删除元素的: del List[index] 所以当时的我直接用了暴力删除第三个重复元素的做法,大概代码如下: n = ...
- FastAPI 学习之路(五十四)startup 和 shutdown
我们在实际的开发中呢,总会遇到这样的场景,我们想在启动或者终止的时候,做一些事情,那么应该如何实现呢,其实也是很简单.fastapi提供了这样的操作. 那么我们看下具体是怎么实现的呢 app = Fa ...
- Python课程笔记(九)
本次课程主要学习了Excel和JSON格式的一些读写操作.课程代码 一.Excel数据读写操作 1.安装模块 pip install xlrd pip install xlwt 网不好可以采用三方库: ...
- 简单易懂讲IO
流式 IO 是传统 IO,通过构造输入输出流,讲信息从一个地方读取,输出到另一个地方.常见的有读取文件以及写入文件. 基本 API 流失 IO 基本可以分为两个门派,一个以 InputStream 和 ...