父类显式向子类强转的思考
1. 起因
看到一道面试题:
public class Animal {
private String name = "animal_name";
public void getName() {
System.out.println(name);
}
public void setName() {
name = "aaa";
}
public void eat() {
System.out.println("animal_eat");
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("dog_eat");
}
public static void main(String[] args) {
// 流程1
Animal animal_1 = new Dog();
Dog dog = (Dog) animal_1;
dog.setName();
animal_1.getName();
// 流程2
Animal animal_2 = new Animal();
Dog d = (Dog) animal_2;
d.eat();
}
}
答案是:输出aaa后报错。
2. 个人思考
- 流程1(引用类型 和 实例对象类型)
1)父子间的继承关系很好懂,子类重写eat方法,继承name属性和get set方法。
2)内存空间,在堆中创建Dog的实例对象,栈中保存Animal类型的引用,指向堆中的Dog实例。
3)编译期时,会检查引用类型和实例对象类型是否正确。举例,
Dog dog = (Dog) animal_1;
编译器相信dog
引用 确实 指向了真实的Dog
实例,但是在编译期无法证实,于是检查animal_1
的引用类型和dog引用类型 的父子关系。Dog类型和Animal类型的继承关系会通过编译,而下面示例不会通过,因为String类型和Animal类型不存在继承,
String dog_str = (String) animal_1;
4)运行时期,检查引用类型和实例类型是否正确。
animal_1d
实例类型确实是Dog,只是它的引用类型是Animal(多态)。于是dog
引用指向了animal_1d
实例。
- 流程2
Animal animal_2 = new Animal();
Dog d = (Dog) animal_2;
1)animal_2
实例对象类型和引用类型都是Animal。
2)编译器在编译期相信 d
的引用指向了真实的Dog类型(但实际上不是),随后检查d
的引用类型与 animal_2
的引用类型, 能够进行强转,编译期通过。
3)运行期检查animal_2
的实例对象类型是Animal,抛出ClassCastException
3. instansof
显式类型向下强转前,使用instanceof进行实例判断:
public class Dog extends Animal{
//...略
public static void main(String[] args) {
Animal animal_1 = new Dog();
if (animal_1 instanceof Dog) {
Dog dog = (Dog) animal_1;
dog.setName();
animal_1.getName();
}
Animal animal_2 = new Animal();
if (animal_2 instanceof Dog) {
Dog d = (Dog) animal_2;
d.eat();
}
}
}
参考链接:
标签:强转,animal,子类,Dog,dog,Animal,类型,父类,public From: https://www.cnblogs.com/moyu1011/p/17153607.html