第五章 接口与多态
一、接口
接口
与抽象类一样都是定义多个类的共同属性
使抽象的概念更深入了一层,是一个“纯”抽象类,它只提供一种形式,并不提供实现
允许创建者规定方法的基本形式:方法名、参数列表以及返回类型,但不规定方法主体
也可以包含基本数据类型的数据成员,但它们都默认为static和final
1.接口的作用与语法
接口的作用
- 是面向对象的一个重要机制
- 实现多继承,同时免除C++中的多继承那样的复杂性
- 建立类和类之间的“协议”
- 把类根据其实现的功能来分别代表,而不必顾虑它所在的类继承层次;这样可以最大限度地动态绑定,隐藏实现细节
- 实现不同类之间的常量共享
与抽象类的不同
接口允许我们在看起来不相干的对象之间定义共同行为

接口的语法
声明格式为:**[接口修饰符] interface 接口名称 [extends 父接口名]{ …//方法的原型说明或静态常量}**
接口的数据成员一定要赋初值,且此值将不能再更改,允许省略final关键字
接口的方法必须是“抽象方法”,不能有方法体,允许省略public及abstract关键字
[public] interface 接口名称 [extends 父接口名列表] {
[public][static][final] 数据类型 成员变量名=常量;
……
[public][abstract] 返回值的数据类型 方法名(参数表);
……
[public|private] static返回值的数据类型 方法名(参数表) {
方法体
}
……
[public| private] default返回值的数据类型 方法名(参数表) {
方法体
}
……
▫ }
2.实现接口
接口的实现
接口不能用new运算符直接产生对象,必须利用其特性设计新的类,再用新类来创建对象
利用接口设计类的过程,称为接口的实现,使用implements关键字
语法如下:public class 类名称 implements 接口名称{//接口方法体,数据}
- 必须实现接口的所有方法
- 来自接口的方法必须声明成public

对象转型
对象可以被转型为其所属类实现的接口类型

声明接口类型的变量,并用它来访问对象

3.多重继承
Java的设计以简单实用为导向,不允许一个类有多个父类
但允许一个类可以实现多个接口,通过这种机制可实现多重继承
一个类实现多个接口的语法如下:
[类修饰符] class 类名称 implements 接口1,接口2,…{… …}
4.接口的扩展
接口可通过扩展的技术派生出新的接口
- 原来的接口称为基接口或父接口
- 派生出的接口成为派生接口或子接口
派生接口不仅可以保有父接口的成员,同时也可加入新成员以满足实际问题的需要
实现接口的类也必须实现此接口的父接口
接口扩展的语法:interface 子接口的名称 extends 父接口的名称1,父接口的名称2,…{… …}
二、塑性
塑性
又称为类型转换
方式:隐式(自动)类型转换;显示(强制)类型转换
1.塑性的概念
塑性的对象包括
- 基本数据类型
- 将值从一种形式转换成另一种形式
- 引用变量
- 将对象暂时当成更一般的对象来对待,并不改变其类型
- 只能被塑性为
- 任何一个父类类型;对象所属的类实现的一个接口;被塑性为父类或接口后,再被塑性回其本身所在的类

隐式的类型转换
基本数据类型
- 相容类型之间存储容量低的自动向存储容量高的类型转换
引用变量
- 被塑性成更一般的类
Employee emp;emp = new Manager();//将Manager类型的对象直接赋给Employee类的引用变量,系统会自动将Manage对象塑性为Employee类
- 被塑性为对象所属类实现的接口类型
Car Jetta = new Car();Insurable item = jetta;
显示(强制)的类型转换
基本数据类型

引用变量:还原为本来的类型

将emp强制塑性为本来的类型
2.塑性的应用
赋值转换
- 赋值号右边的表达式类型或对象转换为左边的类型
方法调用转换
- 实参的类型转换为形参的类型
算术表达式转换
- 算数混合运算时,不同类型的项转换为相同类型再进行运算
字符串转换
- 字符串连接运算时,如果一个操作数为字符串,一个操作数为数值型,则会自动将数值型转换为字符串
当一个类对象被塑性为其父类后,它提供的方法会减少
塑性本质就是用不同引用指向同一个对象
- 引用类型本身,决定了可以访问的成员。这是编译时决定的。

Review

3.方法的查找
如果在塑型前和塑型后的类中都提供了相同的方法,如果将此方法发送给塑型后的对象,那 么系统将会调用哪一个类中的方法?
- 实例方法的查找
- 类方法的查找
实例方法的查找
从对象创建时的类开始,沿类层次向上查找

instanceof
引用变量能否被塑性的关键,是被引用的对象是否可以作为该引用类型进行操作
类似的,instanceof的判断也基于类似的原理
instanceof除了可用于类之外,还可以用于接口和数组。
- null对任何类型判断instanceof的结果都为false
类方法的查找
总是在引用变量声明时所属的类中进行查找(编译时确定)

三、多态的概念
多态
是指不同类型的对象可以响应相同的消息
从相同的基类派生出来的多个类型可被当作同一种类型对待,可对这些不同的类型进行同样的处理,由于多态性,这些不同派生类对象响应同一方法时的行为时有所差别的
例如
- 所有的Object类的对象都响应toString()方法
- 所有的BankAccount类的对象都响应deposit()方法
1.多态的目的
所有的对象都可被塑性为相同的类型,响应相同的消息
使代码变得简单且容易理解
是程序具有很好的“扩展性”
一个例子
绘图
在每个子类中都声明同名的draw()方法

2.绑定的概念
指将一个方法调用同一个方法主体连接到一起
根据绑定时期的不同,可分为
- 早期绑定:程序运行之前执行绑定
- 晚期绑定:也叫作“动态绑定”或“运行期绑定”;基于对象的类别,在程序运行时执行绑定
编译时无法知道s数组元素的具体类型,运行时才能确定类型,所以是动态绑定
在主方法的循环体中,每次随机生成指向一个Circle、Square或者 Triangle的引用
四、多态的应用
技术基础
- 向上塑封技术:一个父类的引用变量可以指向不同的子类对象
- 动态绑定技术:运行时根据父类引用变量所指对象的实际类型执行相应的在子类方法,从而实现多态性

二次分发,即对输出消息的请求被分发两次
五、构造方法与多态
构造方法与其他方法是有区别的
构造方法并不具有多态性,但仍然非常有必要理解构造方法如何在复杂的分级结构中随同多态性一同使用的情况
1.构造方法的调用顺序
调用基类的构造方法。这个步骤会不断重复下去,首先被初始化的是分级结构的根部,然后是下一个派生类,等等。直到抵达最深一层的派生类。
按声明顺序调用成员初始化模块
调用派生构造方法
子类不能直接存取父类中声明的私有数据成员,super.toString调用父类Ball的toString方法输出类Ball中声明的属性值

2.构造方法中的多态方法
在构造方法内调用准备构造的那个对象的动态绑定方法
- 会调用位于派生类里的一个方法
- 被调用方法要操纵的成员可能尚未得到正确的初始化
- 可能造成一些难于发现的程序错误
定义构造方法的注意事项
- 用尽可能少的动作把对象的状态设置好
- 如果可以避免,不要调用任何方法
- 在构造方法内唯一能够安全调用的是在基类中具有final基础的那些方法(也适用于private方法,它们自动具有final属性),这些方法不能被覆盖,所以不会出现上述潜在的问题
六、内部类
在另一个类或方法的定义中定义的类
可访问其外部类中的所有数据成员和方法成员
可对逻辑上相互联系的类进行分组
对于同一个包中的其他类来说,能够隐藏
可非常方便的编写事件驱动程序
声明形式
- 命名的内部类:可在类的内部多次使用
- 匿名内部类:可在new关键字后声明内部类,并立即创建一个对象
假设外层类名为Myclass,则该类的内部类名为
- Myclass$c1.class (c1为命名的内部类名)
- Myclass$1.class (表示类中声明的第一个匿名内部类)
外部类的方法可以返回内部类的引用变量

内部类实现接口
可以完全不被看见,而且不能被调用
可以方便实现“隐藏实现细则”。你所能得到的仅仅是指向基类或者接口的一个引用
方法中的内部类
在方法内定义一个内部类
- 为实现某个接口,产生并返回一个引用
- 为解决一个复杂问题,需要建立一个类,而又不想它为外界所用
作用域中的内部类
匿名的内部类
七、本章小结
本章内容
- 接口作用及语法
- 塑性的概念及应用
- 多态的概念及引用
- 构造方法的调用顺序及其中的多态方法
- 内部类的有关知识
本章要求
- 理解接口、塑性、多态的概念并能熟练应用
- 熟练掌握构造方法的调用顺序,理解编写时需要注意的问题
- 掌握内部类的语法结构及其应用场合
Review
