
java 允许将子类对象赋值给父类引用(如 base b = new derived();),这是基于继承关系的合法向上转型,体现了面向对象的核心特性——多态;但父类引用只能调用其自身声明的方法,无法访问子类新增成员。
java 允许将子类对象赋值给父类引用(如 base b = new derived();),这是基于继承关系的合法向上转型,体现了面向对象的核心特性——多态;但父类引用只能调用其自身声明的方法,无法访问子类新增成员。
在 Java 中,Base b = new Derived(); 这一行代码看似“反直觉”,实则完全符合语言设计原则:它不是类型转换错误,而是向上转型(Upcasting)——一种隐式、安全且无需强制转换的类型提升操作。其根本依据是 Liskov 替换原则(LSP):子类对象可 anywhere 替代父类对象,而不破坏程序正确性。
✅ 为什么编译器不报错?
因为 Derived 是 Base 的子类,new Derived() 创建的对象天然具备 Base 的所有公开接口(方法签名与可见性)。编译器仅检查静态类型(compile-time type):变量 b 声明为 Base 类型,因此只要右侧表达式能提供 Base 或其子类实例,即视为类型兼容。
Base b = new Derived(); // ✅ 合法:向上转型,编译器自动允许
此时,b 的静态类型是 Base,运行时类型是 Derived。方法调用遵循 动态绑定(Dynamic Method Dispatch):
- b.show() 实际执行的是 Derived.show()(因 show() 被重写),体现多态;
- 但可调用的方法集合严格受限于 Base 类的声明——即只有 Base 中定义或继承的方法才可通过 b 访问。
❌ 子类新增方法不可通过父类引用调用
若 Derived 新增了 poo() 方法:
class Derived extends Base {
public void show() { /* ... */ }
public void poo() { System.out.println("take a poo"); } // ✨ 新增方法
}
则以下代码编译失败:
Base b = new Derived(); b.show(); // ✅ OK —— Base 中声明了 show() b.poo(); // ❌ 编译错误:Cannot resolve method 'poo()' in 'Base'
原因:编译器以 b 的静态类型 Base 为准进行符号解析,而 Base 类中不存在 poo() 方法签名,故拒绝编译。
? 如何访问子类特有方法?
需显式向下转型(Downcasting),并确保运行时类型匹配(否则抛出 ClassCastException):
Base b = new Derived();
if (b instanceof Derived) {
Derived d = (Derived) b; // 安全向下转型
d.poo(); // ✅ 现在可以调用
}
⚠️ 注意:向下转型存在风险,务必配合 instanceof 检查,避免运行时异常。
? 总结要点
- 向上转型(Parent p = new Child();)是安全、隐式、编译期允许的,是多态的基础;
- 方法调用取决于运行时对象的实际类型(动态绑定),但可调用的方法集由静态类型决定;
- 父类引用无法访问子类新增字段或方法——这保障了类型安全性与 API 封装性;
- 若需使用子类特有功能,应优先考虑设计抽象方法、接口契约或组合模式,而非频繁向下转型。
理解这一机制,是掌握 Java 继承、多态与面向对象设计的关键起点。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











