接口
飞机、鸟和超人不能归于一个类属,但是具备有相同的特性:会飞的。所以引入了一个新概念叫做接口,可以用于规范实现接口的类中必须实现接口中抽象方法。接口可以理解为一种契约
使用关键字
interface
定义接口
接口不能直接使用,必须有对应的实现类
通过接口定义变量,使用具体类的实例,进行调用
引入接口的目的在于隔离实现
使用接口而不是使用具体的类,则可以实现在实现接口的多个具体实现类之间进行更换
,
例如定义出超人类
什么是接口
在
Java
中不直接支持多继承,因为会出现调用的不确定性,所以
Java
将多继承机制进行改良,在
Java
中变成了多实现。一个类可以实现多个接口,一个接口可以继承多个接口
接口是一种特殊的抽象类,接口只能被
abstract
或者
public
修饰
没有构造器方法
没有属性,只能定义常量
可以包含抽象方法,也可以没有抽象方法
接口中的方法只能被
public
、
default
、
abstract
、
static
修饰
1.一般情况下接口中只定义抽象方法
2.定义的方法默认为公开的抽象方法
抽象方法必须在实现类中提供实现
可以使用
default
关键字给抽象方法提供默认实现,有默认实现的方法在实现类中可以重新定义,也
可以不重新定义
接口允许多重继承
一个类在继承另一个类的同时,还可以实现多个接口
允许一个类实现多个接口
,
但是每个接口的抽象方法都必须提供实现,否则是抽象类。提供的实现也可以是继承
接口的出现避免了单继承的局限性,这样定义
C
接口则拥有
A+B
的所有定义,可以使用
A
和
B
接口以及父类D
声明变量类型,直接
new T
。但是约束时,用谁声明变量编译器系统识别就是谁这种类型,也就意味只能调用识别类型中的方法,不能调用其他方法
声明接口的语法
如果定义
public
接口,则规则和定义
public
类一致,要求接口名称和文件名称一致
外部的接口只能使用
public
、默认这两个范围限定词;如果定义内部接口则可以使用
4
大范围限定
词
接口实际上提供了同一的操作界面(方法),如果是
JDK1.8-
版本则一个方法也不实现,等待某类
或某几个类去实现它的方法【接口中的所有方法必须是抽象的】。如果使用的是
JDK1.8+
允许使用
default
在接口中定义默认实现,这个实现允许在实现类中重新定义覆盖
default
默认方法实现使用的限制
接口中没有属性,只能定义常量,它提供一些常量,实现它的类可以共享这些常量
接口可以给出访问控制符,用
public
修饰的是公共接口,到处可见;如果定义接口没有范围限定
词,则只能在同包中访问
接口中只能定义常量和抽象方法
接口中只能定义公共的常量,接口中的属性默认是
public static final
类型的,必须是
public static
final
类型的
接口中只能定义公共的抽象方法
,
只有在
JDK1.8+
中可以使用
default
关键字定义方法实现。接口中
的方法默认是
public abstract
类型的,而且必须是
public abstract
类型的。只有在
JDK1.8+
中可以
使用default
关键字定义方法默认实现,同时允许在实现类中覆盖重新定义
接口不能被实例化,只能通过实现类所实现,但是可以用于声明变量的类型。
接口 变量名
=new
实现接口类
()
;
接口没有构造函数
接口中的抽象方法必须在非抽象子类中提供实现,这个实现可以是继承来的
一个类实现接口的语法
接口抽象方法的默认修饰符为
public
,在实现接口时必须用
public
关键字在方法头上说明
一个接口可以被多个子类实现。一个子类还可以实现多个接口
类实现接口
一个类在实现某接口的抽象方法时,必须使用完全相同的方法头
public
如果一个类实现多接口,用逗号隔开
如果一个类实现了声明相同方法的两个接口,则被多个接口共用
类在实现接口时可以定义它自己的附加成员,这也是最常见的形式
如果一个类不完全实现接口的所有方法,必须把类定义成
abstract
类型的类,任何继承该类的子类
必须实现该接口
接口中常量
可以为多个接口的实现类共享常量
只需在接口中定义并赋值,此后不能再修改
在类中说明是接口的实现类,就可以使用该接口的常量了
一个对象往往有多重身份
1.Java
中一个子类只能继承一个父类 (不能表示)
2.java
中一个类可以实现多个接口。
(
可以表示
)
3.通过继承和运行时多态的双重机制,可以定义一个被很多不同却相关的对象类型的运用的一致的接口
4.维持抽象接口,甚至不需要重新编译,就可以调用新类的实例
接口的特殊特征
1.一个类只能有一个父类!
2.一个类可以实现多个接口!
3.一个接口可以继承多个接口
接口的作用
1.
统一访问
2.解耦 通过接口可以隔离具体实现
解耦就是 在使用者 和 实现者 之间没有关系。 无论实现者如何改变实现,对于使用者使用不会变化
象类的异同点[重点]
1.相同点:都是不断向上抽取而来的
2.不同点:
抽象类需要被继承,而且只能单继承
接口需要被实现,而且可以多实现
3.抽象类中可以定义抽象方法和非抽象方法,子类继承后可以直接使用非抽象方法
4.接口中可以定义抽象方法和
default
方法,抽象方法必须由子类去提供实现;
JDK1.8+
中允许接口中的方法有默认实现,实现类中可以直接使用默认实现,允许覆盖定义
5.抽象类的继承是
is a
关系,在定义该体系的基本共性内容
6.接口的实现是
like a
关系,在定义体系额外功能
7.接口中只能定义常量,而且必须被初始化,抽象类中可以定义属性,允许在声明时直接初始化,也可以不初始化,同时允许定义常量
如何使用接口
一般使用接口隔离具体实现,可以将类之间的相互依赖变为类对接口的依赖。例如出差类和会飞的东西是通过会飞的接口进行隔离,这样不管出差类需要修改或者会飞的东西需要修改,都不会相互影响
如果一组相关的类中有公共的方法和特殊的方法,可以使用抽象类,在抽象类中固化公共的方法【算法骨架】,而无需具体子类重复实现;但是在抽象类中无法实现的方法可以延迟到子类中再实现。例如排序器BubbleSorter
,其中抽象类
BubbleSorter
固化了所使用的冒泡排序算法,而将无法实现的
bigger
比较算法延迟到BubbleSorter
的子类
PigSorter
中实现,同时
PigSorter
中也不需要重新定义排序算法
最佳软件开发实践:先定义接口规范调用方法,在使用抽象类实现接口定义公共方法,最后再定义具体子类实现所有的方法
接口和抽象类的使用场景
从设计层面看,抽象类体现继承关系
is a
,它主要描述类的从属关系或者父子关系,抽象类和它的派生类之间是典型的IS-A
关系,即子
is a
父。
interface
可以多实现,而且不要求实现者和
interface
定义在概念本质上是一致的,仅仅是实现了
interface
定义的契约而已。它主要描述的是类型间的行为合同,接口和它的实现类之间是典型的
CANDO关系,即子
can do
父。
为什么接口需要默认方法
在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。
内部类
一个类或者接口定义在另外一个类后者接口的内部
将一个类定义置入另一个类定义中,这就叫作
“
内部类
”
1.内部类之外的类称为外部类
2.内部类的名称必须区别于它所在的外部类,和其它类之间没有要求
3.内部类可以访问其外部类的所有变量和方法
4.
外部类不能直接访问内部类的实现细节
5.
内部类比外部类多了
private/protected/static
三个修饰符,这三个修饰符不能用在外部类上
6.非静态内部类不能拥有静态成员
内部类的作用
内部类提供更好的封装
内部类可以直接访问外部类的私有成员
外部类不能直接访问内部类的成员,需要构建内部类对象才能访问
匿名内部类适合用于创建仅仅使用一次使用的类
内部类相关的设计
分析事物时发现该事物描述还有事物,而且这个事物还在访问被描述事物的内容
例如牛和牛腿
如果一个事物离开另外一个事物后则没有任何意义,这种情况下建议使用内部类,不允许其他类访
问
内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名
.this
内部类分类
在
Java
中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
内部类实际拥有外部类的一个引用,在构造函数中将外部类的引用传递进来。
非静态内部类
基础语法:
protected class
B1
{}
//
静态内部类是
protected static class B1{}
非静态内部类的特点:
和其他类一样,它只是定义在外部类中的另一个完整的类结构
1.可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
关
2.可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以
继承父类的静态成员,而且可以声明静态常量。
3.可以使用
abstract
修饰,因此它也可以被其他类继承
4.可以使用
final
修饰,表示不能被继承
5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和
$
符号。
和外部类不同的是,它可以允许四种权限修饰符:
public
,
protected
,缺省,
private
1.外部类只允许
public
或缺省的
还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的
在外部类的静态成员中不可以使用非静态内部类哦
1.就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样
在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象
1.因此在非静态内部类的方法中有两个
this
对象,一个是外部类的
this
对象,一个是内部类的
this
对象
在创建非静态内部类对象时,一定要先创建起相应的外部类对象
在任何非静态内部类中,都不能有静态数据、静态方法或者又一个静态内部类
1.注意内部类的可见性范围限制
2.访问方法:直接访问外部类中内部类中的成员
3.外部类
.
内部类
in=new
外部类
().new
内部类
();
4.in.
内部类方法
();
5.注意内部类的可见性范围限制
静态内部类
静态内部类的特点:
和其他类一样,它只是定义在外部类中的另一个完整的类结构
1.
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
关
2.可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员
3.可以使用
abstract
修饰,因此它也可以被其他类继承
4.可以使用
final
修饰,表示不能被继承
5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和
$
符号。
和外部类不同的是,它可以允许四种权限修饰符:
public
,
protected
,缺省,
private
外部类只允许
public
或缺省的
只
可以在静态内部类中使用外部类的
静态成员
在静态内部类中不能使用外部类的非静态成员哦
在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象
如果在内部类中有变量与外部类的静态成员变量同名,可以使用
“
外部类名
."
进行区别
静态内部类中,可以有静态数据、静态方法或者又一个静态内部类
静态内部类中,也可以有非静态数据、非静态方法或者又一个非静态内部类
静态内部类中,不能访问外部类的非静态成员,这是由
Java
语法中【静态方法不能直接访问非静态
成员】所限定
局部内部类
可以将内部类定义在一个方法或者一个代码块内
局部内部类的特点:
和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构
1.可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
关
2.可以在局部内部类中声明属性、方法、构造器等结构,
但不包括静态成员,除非是从父类继承
的或静态常量
3.可以使用
abstract
修饰,因此它也可以被同一个方法的在它后面的其他内部类继承
4.可以使用
final
修饰,表示不能被继承
5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、
$
符号、编号。
这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
和成员内部类不同的是,它前面不能有权限修饰符等
局部内部类如同局部变量一样,有作用域
局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法
局部内部类中还可以使用所在方法的局部常量,即用
final
声明的局部变量
6.JDK1.8
之后,如果某个局部变量在局部内部类中被使用了,自动加
final
注意:局部内部类需要先定义后使用,不能是先使用后定义
匿名内部类
匿名内部类就是内部类的简写格式
匿名内部类的前提是必须继承或者实现一个外部类或者接口
1.匿名内部类由于没有名字,所以它没有构造函数
2.如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数
3.不能定义静态成员
匿名内部类的使用场景
当方法参数是接口类型时,而且接口中的方法不超过三个
,
可以用匿名内部类作为实际参数进行传递
匿名内部类的使用限制
1.匿名内部类不能是抽象的
2.匿名内部类不能定义构造器,默认和父类相似的构造器
3.JDK1.8-
要求给局部内部类、匿名内部类访问的局部变量必须使用
final
修饰,从
JDK1.8
开始这个现实被取消了,但是默认是final
的(不能修改
)
内部类的使用场景和好处
每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个
(
接口的
)
实现,
对于内部类都没有影响。内部类使得多继承的解决方案变得完整
方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏
方便编写事件驱动程序
方便编写线程代码。