Java多态目的是:降低程序耦合度,提升程序扩展性,基础是向上转型(子->父,自动类型转换)和向下转型(强制类型转换,要加强制类型转换符)(引用方面最好说向上向下,自动和强制用在基本数据类型),但都需要有继承关系。
Animal a= new Cat();//重写的方法
a.move()//输出猫走猫步,因为底层对象是一个猫。
父类型的引用允许指向子类型的对象,也就是多态的含义。
编译阶段,静态绑定父类的方法。
运行阶段,动态绑定子类型对象的方法。多种状态。
a.catchMouse;//子类特有方法
编译报错,因为编译阶段是静态,编译期在父类字节码文件中寻找catchmouse方法,但此方法只在子类中存在。假如可以过编译关的话,那么可以运行,但根本无法过编译语法关。
还想达成目的就要向下强制转换–目的就是使用子类特有方法。
Cat b =(Cat)a;
a.catchMouse();
编译通过
但是例如
Animal c = new Bird();
Cat d = (Cat)c;
无法强制转换,因为编译器检测到c这个引用是animal类型,与cat存在继承关系,所以可以向下转型,可以编译,但在运行阶段,堆内存实际创建的是bird对象,无法将bird转化成cat,有类转化异常classcastexception导致无法运行。
How to avoid it?
利用instanceof符号来判断。
例如
if(c instanceof Cat){
Cat d = (Cat)c;
d.catchMouse();
表示如果c是一个Cat,再进行向下强制类型转换。instanceof符号可在运行时动态判断引用指向的对象的类型,并且只有true和false两种返回值。所以要保持向下转型时用instanceof运算符进行判断的习惯。
But,why?
因为当分工合作时,方法中用到的参数是Animal,然而参数并不由自己生成,我们无从得知Animal到底是Cat还是Bird,为了避免程序异常终止,我们只能人工预防。
回到开始,我们为什么用到多态?
假设一个场景,主人一开始养了一只狗,有feed方法。
public void feed(Dog dog){
dog.eat();
}
如果后来主人更换了宠物,就需要新增一个方法
public void feed(Cat cat){
Cat.eat();
}
不仅增加代码出错的概率,也不符合编写程序的规范–七大规范之一OCP,对扩展开放,对修改关闭。但如果我们事先编写一个Animal类 ,使Dog和Cat都继承自Animal。
pulic class Animal{
public void eat(){
}
public class Cat extends Animal{
}
这样,调用方法时代码就变成`
public void feed(Animal animal){//实际上是Animal animal = new Dog()/new Cat()
//编译器发现是Animal类,去Animal类中寻找eat方法,找到了运行就会通过,到了运行时会根据底层实际的对象类型自动调用到该类型的方法
animal.eat();
还有一个问题,为什么不直接把Pet定义成Object?接受万物?但如果定义为Object,就没有了eat方法,需要强制向下转型才能使用了,就是失去共同性,反而导致程序更加复杂。