继承的初始化顺序
- 初始化父类再初始化子类
- 先执行初始化对象中的属性,再执行构造方法中的初始化
引用类型转换
- 向上类型转换(隐式/自动类型转换)是从小类型到大类型的转换。这种用法叫做“父类引用指向子类对象”,指的是定义一个父类的引用,而它实际指向的是子类创建的对象,如下例。
Animal animal = new Dog(); //自动类型提升,向上类型转换
- 向下类型转换(强制类型转换),是大类型到小类型的转换。
Animal animal = new Animal();//自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
可见向下转换存在溢出的风险。我们可以用instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题。
【示例】
Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
上面代码中的向下类型转换是存在一定风险的。例如说我把父类应用转换成了cat类型的引用,虽然我强制把这个类型进行转换,但是毕竟我这个引用指向的是一个dog对象,显然它没有办法转换成cat对象,根本就是不同类型的对象。
Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
Cat cat = (Cat)animal;
虽然编译器没有检查出这个错误,但是当程序真正运行的时候会发现程序会有问题。因为我们真正开辟的运行空间是dog类型,程序运行的时候发现两个类型不匹配是不能进行类型转换的,所以出现了以下异常。
此时我们可以用instanceof运算符,来解决引用对象的类型:
Dog dog = new Dog();
Animal animal = dog(); //自动类型提升,向上类型转换
Dog dog2 = (Dog)animal; //向下类型转换,强制类型转换
if(animal instanceof Cat){
Cat cat = (Cat)animal; //1.编译时cat类型 2.运行时dog类型
}else{
System.out.println("无法进行类型转换");
}
向上引用之后调用子类还是父类的方法?
class A ...{
public String show(D obj)...{
return ("A and D");
}
public String show(A obj)...{
return ("A and A");
}
}
class B extends A...{
public String show(B obj)...{
return ("B and B");
}
public String show(A obj)...{
return ("B and A");
}
}
class C extends B...{}
class D extends B...{}
问题:以下输出结果是什么?
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
答案
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
在这里看结果1、2、3还好理解,从4开始就开始糊涂了,对于4来说为什么输出不是“B and B”呢?
首先我们先看一句话:当超类对象引用变量引用子类对象时,如果子类重写了父类方法,向上造成后调用的是子类方法;子类没有重写父类方法,向上造型后调用的是父类方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
首先我们分析5,a2.show(c),a2是A类型的引用变量,所以this就代表了A,a2.show(c),它在A类中找发现没有找到,于是到A的超类中找(super),由于A没有超类(Object除外),所以跳到第三级,也就是this.show((super)O),C的超类有B、A,所以(super)O为B、A,this同样是A,这里在A中找到了show(A obj),同时由于a2是B类的一个引用且B类重写了show(A obj),因此最终会调用子类B类的show(A obj)方法,结果也就是B and A。同理可以得出其他输出的原因。