多态
1.再论向上转型
在第七章的时候知道,对象既可以作为它自己本身的类型使用,也可以作为它的基类使用。而这种把对某个对象的引用视为对基类的引用成为向上转型。下面举个列子:
for example
public class Instrument {
public void play() {
System.out.println("Instrument.play()");
}
}
public class Wind extends Instrument {
public void play() {
System.out.println("wind.play()");
}
}
public class Brass extends Instrument{
public void play() {
System.out.println("Brass.play()");
}
}
public class Music {
public static void tune(Instrument i) {
i.play();
}
public static void main(String[] args) {
Wind flute = new Wind();
Brass brass = new Brass();
tune(brass);
tune(flute);
}
result
Brass.play()
wind.play()
tune 方法接受一个Instrument的引用但是我们赋予的是Wind和Brass的引用。但是运行结果确实是我们想要的,实现此现象的是Java的绑定机制。
2.方法调用的绑定
将一个方法调用用同一个方法主题关联起来称作绑定。若程序执行前绑定称作前期绑定 (面向过程的语言默认的绑定方式)。但是向上转型用到是 后期绑定 ,它的含义是在运行的时候根据对象的类型进行绑定,也称作 动态绑定,运行时绑定 。Java中除了static方法和final方法(private属于final方法)之外,其他所有方法都是后期绑定——他会自动发生。
3.协变返回类型
在JavaSE5添加了协变返回类型,它表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类。
for example
public class Grain {
public String toString() {
return "Grain";
}
}
public class Wheat extends Grain {
public String toString() {return "Wheat";}
}
public class Mill {
Grain process() {return new Grain();}
}
public class WheatMill extends Mill{
Wheat process() {return new Wheat();}
}
public class CovariantReturn {
public static void main(String[] args) {
Mill m = new Mill();
Grain g = m.process();
System.out.println(g);
m = new WheatMill();
g = m.process();
System.out.println(g);
}
}
result
Grain
Wheat
4.用继承做设计
学习了多态之后,看似所有的东西都可以继承。但是更好的方式是选择组合,组合不会强制我们的程序设计进入继承的层次结构中,而且更加灵活,因为它可以动态的选择类型。
public class Actor {
public void act() {}
}
public class HappyActor extends Actor{
public void act() {System.out.println("HayypActor");}
}
public class SadActor extends Actor{
public void act() {System.out.println("SadActor");}
}
public class Stage {
private Actor actor = new HappyActor();
public void change() {actor = new SadActor();}
public void performPlay() {actor.act();}
}
public class Transmogrify {
public static void main(String[] args) {
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
}
这里Stage对象包含一个Actor的引用,而Actor被初始化为HappyActor对象,多态既然可以在运行时于另一个不同的对象绑定起来,所以SadActor对象的引用可以在actor中被替代。之后performPlay也被替代,这种设计模式称为 状态模式。
5.向下转型和运行时类型识别(RTTI)
由于向上转型会丢失具体的类型信息,所以我们就想通过向下转型——也就是在继承层次中向下移动,应该能获取类型的信息。在某些程序设计语言中,我们必须执行一个特殊的操作来获得安全的向下转型,但是在Java中,所有的转型都会得到检查,即使是加括弧形式的类型转换。如果类型错误会返回ClassCastException(类型转换异常)。这种在运行期间对类型检查的称为"运行时类型识别"。