为何将子类对象赋值给父类引用时编译器不报错?附代码疑问
Java父类引用指向子类对象的核心问题解答
基础代码示例
class Base { public void show() { System.out.println("Base class show() method called"); } } class Derived extends Base { public void show() { System.out.println("Derived class show () method called"); } } public class Main { public static void main(String[] args) { Base b = new Derived();// 为何Java允许创建子类对象并赋值给父类引用 b.show(); // 父类如何持有并使用子类的引用 } }
问题1:父类引用为何能指向子类对象?父类是如何持有并使用子类引用的?
这是Java多态的核心特性:子类本质是父类的特殊类型(Derived is a Base),所以父类引用可以安全指向子类对象。
内存层面,new Derived()创建的是完整子类对象,包含父类所有属性和方法。父类引用b只是限制了可访问的成员范围——它只能识别父类定义的方法/属性,但运行时会根据对象实际类型(而非引用类型)调用子类重写的实现(比如show()方法),这就是动态绑定。
问题2:子类新增方法后,父类引用能否访问该方法?
先看对应代码示例:
class Derived extends Base { public void show() { System.out.println("Derived class show () method called"); } public void poo() { System.out.println("take a poo"); } } public class Main { public static void main(String[] args) { Base b = new Derived(); b.show(); b.poo(); // 该行代码会编译报错 } }
答案是不能。父类引用b的编译类型是Base,编译器只会检查Base类中是否存在poo()方法——显然不存在,因此直接编译失败。
如果要调用子类新增方法,需先将父类引用强制类型转换为子类类型:
((Derived) b).poo(); // 可正常调用
转换前建议用instanceof检查类型,避免ClassCastException:
if (b instanceof Derived) { ((Derived) b).poo(); }
问题3:为何Java允许将子类引用赋值给父类,且无警告或错误?
这完全符合面向对象设计原则:
- 里氏替换原则:子类必须能替换父类的所有使用场景,这是继承的核心要求。既然子类是父类的扩展,用父类引用指向子类对象是安全的,不会破坏程序正确性。
- 多态的基础:这种赋值是实现多态的前提——允许用统一的父类接口处理不同子类对象,比如用
List引用指向ArrayList或LinkedList,无需关心具体实现,提升代码扩展性与复用性。 - 类型安全:编译器会校验子类与父类的继承关系,确保赋值操作类型安全,因此无需警告或错误。
内容的提问来源于stack exchange,提问作者Goutham
相关产品推荐
相关产品推荐

