父类引用指向子类对象是向上转型,编译看声明类型、运行看实际类型;仅非static非private非final的实例方法参与多态,字段、静态方法、构造器等均“看左边”;向下转型需instanceof校验以防classcastexception。

父类引用指向子类对象,本质是用统一的父类视角操作不同子类实例——编译时按声明类型检查,运行时按实际类型执行方法。这不是对象“变了”,而是引用的访问权限和行为绑定方式发生了变化。
向上转型:自动、安全、日常必需
写 Animal a = new Dog(); 就是向上转型。JVM 在堆上创建完整的 Dog 对象,只是把它的地址存进一个声明为 Animal 类型的变量里。
- 无需强制转换,Java 自动完成,因为 Dog “是” Animal(is-a 关系)
- 通过 a 只能调用 Animal 中定义的方法(如 eat()、sound())
- 若 Dog 重写了 sound(),运行时仍执行 Dog 版本,输出“汪汪汪”
- 字段和静态方法不参与多态:a.name 取的是 Animal 的 name 字段;Animal.sleep() 调用的是 Animal 的静态方法
向下转型:需校验、有风险、不能跳步
想调用子类特有方法(如 Dog.bark()),必须先确认类型再转型,否则运行时抛 ClassCastException。
- 语法必须显式: Dog d = (Dog) a;
- 必须先用 instanceof 判断:if (a instanceof Dog) { Dog d = (Dog) a; d.bark(); }
- Java 14+ 支持模式匹配写法:if (a instanceof Dog d) { d.bark(); },一次完成判断与赋值
- 若 a 实际是 Cat 或纯 Animal 实例,强转会失败
哪些东西不参与多态?关键要分清
多态只对满足条件的实例方法生效,其他成员一律“看左边”(即引用的声明类型):
- ✅ 参与多态:非 static、非 private、非 final 的实例方法(靠动态绑定)
- ❌ 不参与多态:字段(访问哪个字段取决于引用类型)、静态方法(调用哪个 sleep() 看左边)、构造器、私有方法
- ❌ 子类特有方法:通过父类引用直接调用会编译报错,必须向下转型后才能使用
为什么这样设计?核心是解耦与扩展
这种机制让代码能面向抽象编程,而不是具体实现:
- 方法参数用 Animal 类型,传入 Dog、Cat、Bird 都可以
- 集合如 List
可统一存放各种动物,遍历时调用 sound() 自动走各自逻辑 - 新增 Tiger 类并重写 sound(),原有使用 Animal 引用的代码完全不用改
- 转型只改变引用的“视角”,对象本身的运行时类型始终不变
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











