一,对象的多态
①,一个对象的编译类型和运行类型可以不一致。
②,编译类型在定义对象时,就确定了,不能改变。
③,运行类型是可以变化的。
④,编译类型看定义时=号的左边,运行类型看=号的右边。
二,多态的向上转型
①,本质:父类的引用指向了子类的对象。
②,语法:父类类型 引用名=new 子类类型();
③,特点:编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限),
不能调用子类中特有成员。
最终运行效果看子类的具体实现。
在测试类运行时,系统会先在运行类型中寻找在父类中共有的方法,如果运行类型中找不到共有的方法时,系统则会掉头去找编译类型中要寻找的方法,所以是先在运行类型寻找,再到编译类型寻找。
源代码:测试类
package poly_practice; public class Test { public static void main(String[] args) { Animal animal=new Dog(); //向上转型 animal.cry(); animal.look(); System.out.println(animal.a); Dog dog=(Dog) animal; //向下转型 dog.cry(); dog.shout(); System.out.println(dog.a); } }
父类Animal:源代码
package poly_practice; public class Animal { public int a=10; public void cry() { System.out.println("动物叫唤。。"); } public void look(){ System.out.println("小狗在看树.."); } }
子类Dog:源代码
package poly_practice; public class Dog extends Animal { public int a=20; public void cry(){ System.out.println("小狗汪汪叫。。"); //共有属性 } public void shout(){ System.out.println("小狗在乱叫。。"); //特有属性 } }
如上图,在子类中存在有方法的重写cry方法,父类中也有cry方法,为共有的方法,而dog是运行类型,所以在测试类中的向上转型中的animal.cry();代码运行时,系统会先到子类的dog中看看有没有cry方法,发现有,则运行Dog中的cry方法,所以最终的显示结果的第一条会是小狗汪汪叫。。,测试类的下一行代码是animal.look();,同样,系统会在子类的dog中寻找看看有没有这个look方法,发现没有,则再到编译类型即父类中去寻找,发现look方法在父类中,则输出小狗在看树..
三,多态的向下转型
①,语法:子类类型 引用名=(子类类型) 父类引用:
②,只能强转父类的引用,不能强转父类的对象。
③,要求父类的引用必须指向的是当前目标类型的对象。
④,可以调用子类类型中所有的成员。
如上图中的源代码块引用,测试类中的注释向下转型,这个时候转型了的对象引用dog就可以访问到子类dog的特有方法shout();它的访问顺序也是现在子类的dog中看看有没有要输出的方法,如果子类中有,就直接输出,不再往下看,如果没有,则往下找到父类中的方法,看有没有目标方法。这时父类中有子类没有的look方法,所以在向下转型中添加一个dog.look();,系统会先在子类中查找,发现没有,则往下到父类中查找,发现有,就直接输出小狗在看树..
四,属性的重写问题
①,属性没有重写之说,属性的值看编译类型。
例如源代码:上图中的块引用测试类中有写到,在向上转型的那一步后,输出了一句System.out.println(animal.a);,因为向上转型的那一步中编译的是Animal animal=new Dog();,编译类型是Animal,所以输出语句时,直接查看animal父类中的属性a的值就可以了,也就是直接输出animal中的属性a的值10,而不会像查找重写的方法那样,现在运行类型中查看一遍,如果没有,再找编译类型。
接着在向下转型中,那一步的代码是Dog dog=(Dog) animal;,所以编译类型就是dog,所以在执行System.out.println(dog.a);时,就直接输出Dog类中的属性a的值20即可。
五,instanceof 比较操作符,用于判断对象的运行类型是否为比较类型的类型或者子类型。
如下图源代码:创建一个AA父类,BB子类,在测试类中创建一个对象BB,使用bb去引用,那么bb的运行类型就是BB,BB是比较类型AA的子类,所以输出结果为true,如果创建一个AA对象,使用aa去引用这个AA对象,再用aa instanceof AA,则aa的运行类型是AA,AA是比较类型AA的类型,所以输出结果还是true。
package poly_practice; public class Test { public static void main(String[] args) { BB bb=new BB(); AA aa=new AA(); System.out.println(bb instanceof AA); } } class AA{} class BB extends AA{}