多态可以是客户端使用统一的接口执行不同的行为。统一的接口是因为继承类都覆盖了基类方法,从而为自己定义了单独的行为。“向上转型”(upcasting,将继承类对象赋给基类对象的一种行为)和动态编译能够确定执行哪段代码。如下:
class Shape{
void draw(){
System.out.println("Shape.draw()");
}
}
class Circle extends Shape{
void draw(){
System.out.println("Circle.draw()");
}
}
public class PolyTest{
public static void f(Shape s){
s.draw();
}
public static void main(String[] args){
Circle c=new Circle();
f(c);
}
}
运行结果:
Circle.draw()
从上面的代码可以看到,无论载main函数里面生成什么对象Circle、triangle等,只要交给void f(Shape s)函数去办就可以了,它知道应该调用哪一段代码,即产生正确的行为,多代使得我们代码量减少而且容易扩展。
如果在构造器调用多态的函数,那么就容易产生一些问题,如下所示:
class Glyph{
void draw(){System.out.println("Glyph.draw()");};
Glyph(){
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius=1;
RoundGlyph(int r){
radius=r;
System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);
}
void draw(){
System.out.println("RoundGlyph.draw(),radius="+radius);
}
}
public class PolyConstructors{
public static void main(String[] args){
new RoundGlyph(5);
}
}
运行结果为:
Glyph() before draw()
RoundGlyph.draw(),radius=0
Glyph() after draw()
RoundGlyph.RoundGlyph(),radius=5
因为 new RoundGlyph(5)会先调用基类的构造器,所以第一句结果没问题,而基类的构造起调用了draw()方法,这个时候产生了多态,即实际调用继承类的draw()方法,但是为什么打印的是radius=0呢?为什么不是radius=5或编译通不过,radius没有定义?编译确实没有出问题,原来初始化最开始一步并不是调用基类的构造函数,而是将分配给对象的存储空间初始化为零,也就是说radius在调用基类构造函数之前就已经初始化了,只是初始化值为0。所以输出结果为radius=0。这个输出结果并不是我们所希望的,所以编写构造起时记住一个原则:尽可能简单使对象进入正常状态,如果可以的话,避免调用其他方法。当然调用基类的final方法和private方法是安全的。