在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。
多态通过分离做什么和怎么做,从另一角度将接口和实现分离开来。多态不但能改善代码的组织结构和可读性,还能够创建可扩展的程序--即无论在项目最初创建时还是在需要添加新功能时都可以“生长”的程序。
对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用,这种把对某个对象的引用视为对其基类型的引用的做法被称为向上转型。
动态绑定
将一个方法调用同一个方法主体关联起来被称作绑定,若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。而后期绑定是在运行时根据对象的类型进行绑定,后期绑定也叫做动态绑定或运行时绑定。
缺陷:域与静态方法
多态是运行期针对对象的调用行为,所以要注意静态编译在运行前的表现。比如field,当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态的。
class Super {
public int field = 0;
public int getField() { return field; }
}
class Sub extends Super {
public int field = 1;
public int getField() { return field; }
}
public class FieldAccess {
public statuc void main(String[] args) {
Super sup = new Sub(); // upcast
sup.getField(); // get super field
}
}
从静态编译的角度,导出类中接口扩展部分不能被基类访问。
Java中除了static方法和final方法(private方法属于final方法)之外,其他所有方法都是后期绑定,前者与对象无关,后者隔离了继承。
协变返回类型
Java中添加了协变返回类型,它表示在导出类的被覆盖方法可以返回基类方法的返回类型的某种导出类型。就是多态方法支持返回值也是继承关系,导出类方法返回值也可以是导出类,这个返回值继续调用又是另外一个多态。
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(); }
}
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);
}
}
向下转型
神似基本类型类型转换。
在Java语言中,所有转型都会得到检查,即使我们只是进行一次普通的加括弧形式的类型转换,在进入运行期时仍然会对其进行检查,以便保证它的确是我们希望的那种乐行,如果不是会返回ClassCastException,这种在运行期间对类型进行检查的行为称作“运行时类型识别”。如果是牛马不相及的编译期会识别出来,这里指的还是有继承关系的场景。