1.协变返回类型
- 表示子类中被覆盖的方法可以返回父类方法的返回类型的某种子类类型。
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 { /** * 重写父类的process方法,可以看到返回类型改成了Grain的子类了,它是一个新方法吗,不是, * 这就是协变返回类型,覆盖方法可以返回父类返回方法类型的子类 在这里 * WheatMill是Mill的子类,process()为WheatMill重写Mill的方法, * Mill中的返回类型是Grain,WheatMill的返回类型是Wheat,Wheat是Grain的子类 * * Java SE5 之前的版本将强制process的覆盖方法返回Grain,而不能返回其子类型Wheat, * 协变类型可以 */ Wheat process() { return new Wheat(); } } public class CovariantReturn { public static void main(String[] args) { Mill m = new Mill(); // 这儿的g是Grain类型的引用,而mill的process方法返回的也是Grain对象 Grain g = m.process(); System.out.println(g); m = new WheatMill(); g = m.process(); System.out.println(g); } }
2.is-a和is-like-a
- is-a 是一个的关系:这是一种纯粹的继承关系,即父类中有多少方法,子类中重写多少方法,不能自己扩展方法。
- is--like-a 像是一个的关系:可以重写相应的方法,也可以扩展相应的一些方法,比较灵活。
- is-like-a的关系有一个问题,比如List list = new ArrayList(); 那么list这样一个引用只能调用List中有的,ArrayList中有的或没有的方法,不能调用ArrayList中扩展的方法。
这种情况下必须知道确切的类型才能访问ArrayList中所扩充的方法。也就引出了下面的向下转型。
3.向下转型与运行时类型识别
- 与向上转型相反,是往继承图向下移动。
- 向上转型会丢失方法,而向下转型会获得方法
- JAVA 是重类型的语言,所有的转型都会得到检查,即使进行一次普通的括弧形式的类型转换,在进入运行期是仍然会对其进行检查,以便确保得到我们希望的那种类型。
否则就会抛出ClassCastException 异常。
父类引用访问子类的扩展方法,必须进行向下转型才能获取到。/** * is-like * is-like-a * 向下转型 * @date 2016-8-20 下午12:28:32 */ class Useful{ public void f(){} public void g(){} } class MoreUseful extends Useful{ public void f(){} public void g(){} public void u(){} public void v(){} public void w(){} } public class RTTI { public static void main(String[] args) { Useful[] x = { new Useful(), new MoreUseful() }; x[0].f(); //向下转型 获取方法 ((MoreUseful) x[1]).v(); } }
总结
- 用继承表达行为间的差异(各个子类是不同的),用字段表示状态上的变化()。
- 多态可能伴随着继承的存在,但也可能是public 方法 或protect 方法 因为多个类中可能有相同的public方法,这就需要运行时判断是调用哪一个类中的方法了。但大多数是继承。
- 多态是动态绑定:即在程序运行期间方法调用与方法所在类中的主体相关联并执行其中代码,在运行前无法知道这个方法在哪个类中。
- 多态是一种不能单独来看待的特性,相反它只能作为类关系“全景”中的一部分,与其他部分协同工作。
- 少用继承,多用组合,协同作战。