八、多态
8.1 再论向上转型
对某个对象的引用视为其基类型的引用的做法称向上转型。
8.1.1 忘记对象类型
定义一个只接收基类对象为参数的方法,而调用的时候用它子类对象去传即可
8.2 转机
传的参怎么知道父类引用指向的是那个子类对象而不是那个子类对象。
8.2.1 方法调用绑定
将一个方法调用同一方法主体关联起来被称作绑定。
若在程序执行前进行绑定(编译器和连接程序实现),叫做前期绑定。这也是无法知道是哪个子类对象的关键
运行时根据对象的类型进行绑定叫做后期绑定(也称动态绑定或运行时绑定)。即编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,并加以调用。
java中除了static和final方法之外,其他方法都是后期绑定
8.2.2 产生正确的行为
几个子类重写了父类的方法,调用方法的时候总能区分出调用的哪个子类。
8.2.3 可扩展性
可添加新方法,可重写父类方法。
8.2.4 缺陷:“覆盖”私有方法
只有非private方法才可能被覆盖,子类与父类那只能是不同方法。
public Class Father{
private void f(){
print("private f()");
}
}
public Class Son extends Father{
public void f(){
print("public f()");
}
public static void main(String[] args){
Father fa = new Son();
fa.f();
}
}
//output
//private f()
8.2.5 缺陷:域与静态方法
相同变量名父类引用获得的是父类的变量,所以通常将变量都定义为private
静态方法与类关联,不与单个对象相关联
8.3 构造器和多态
8.3.1 构造器的调用顺序
1.调用基类构造器
2.按声明顺序调用成员初始化方法
3.调用导出类构造器
8.3.2 继承与清理
一般子对象通常会留给垃圾回收器进行处理
若遇到确实需要清理的为新类创建dispose()方法。由于继承,如果有其他作为垃圾回收一部分特殊清理动作,必须在导出类中覆盖dispose()方法,当覆盖被继承类的dispose()方法,务必要调用基类版本dispose()方法(super.dispose()),否则清理动作不会发生。
8.3.3 构造器内部的多态方法行为
class Glyph{
void draw(){
print("Glyph.draw()");
}
Glyph(){
print("Glyph() before draw()");
draw();
print("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
print("RoundGlyph.RoundGlyph().radius="+radius);
}
void draw(){
print("RoundGlyph.draw(),radius="+radius);
}
}
class PolyConstructors{
public static void main(String[] args){
new RoundGlyph();
}
}
//output
Glyph() before draw()
RoundGlyph.draw(),radius= 0
Glyph() after draw()
RoundGlyph.RoundGlyph().radius= 5
其他事物发生前都会将分配给对象存储空间初始化成二进制的0
8.4 协变返回类型
导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型。
定义为子类重写父类方法时,返回类型可以是父类返回类型的子类。
class Grain{
public String toString(){
return "Grain";
}
}
class Wheat extends Grain{
public String toString(){
return "Wheat";
}
}
class Mill{
Grain process(){
return new Grain();
}
}
class WheatMill extends Mill{
Wheat process(){
return new Wheat();
}
}
8.5 用继承进行设计
继承覆写方法实现多态。
8.5.1 纯继承于扩展
纯继承:指的是导出类与基类有着同样的方法,基类可接收发送给任何导出类的任何消息,因为二者有完全相同接口。只需导出类向上转型
扩展:就是在这些方法之外新增扩展几个方法。
8.5.2 向下转型与运行时类型识别
子类引用,父类对象强转即向下转型。
向下转型为对类型进行检查ClassCastException(类转型异常)