父类引用指向子类对象是java多态的核心形态,编译时按父类接口检查,运行时执行子类重写方法;仅非static、非private、非final的实例方法参与多态,字段和静态方法“看左边”,子类特有方法需先instanceof校验再向下转型。

父类引用指向子类对象,不是类型“变”了,而是用统一的父类视角去操作不同子类实例——编译时按父类接口检查,运行时自动执行对应子类重写的方法。这是Java多态落地最核心、最常用的形态。
向上转型:自动、安全、日常可见
写 Animal a = new Dog(); 就是向上转型。JVM在堆上创建完整的Dog对象,只是把它的地址存进一个声明为Animal类型的变量里。这个过程无需强制转换,因为Dog天然“是”Animal(is-a关系)。
- 编译器只允许你通过 a 调用Animal中声明过的方法,比如 eat() 或 sound()
- 如果Dog重写了 sound(),运行时就会执行Dog版本,输出“汪汪汪”
- 哪怕后续新增 Tiger 类并重写 sound(),原有使用Animal引用的代码完全不用改
哪些东西不参与多态?要特别注意
多态只对**非static、非private、非final的实例方法**生效。字段和静态方法永远“看左边”,也就是只认引用变量的声明类型。
- Animal a = new Dog(); a.name → 取的是Animal类里定义的name字段,不是Dog里的同名字段
- Animal.sleep() → 调用的是Animal类的静态方法,不会因为new的是Dog就换成Dog.sleep()
- 子类中新增的特有方法,比如 Dog.bark(),通过Animal引用直接调用会编译报错
需要调子类特有功能?先判断再转型
当业务逻辑确实依赖子类独有能力(如让狗叫、让鸟飞),不能硬转,必须加类型校验:
- 用 if (a instanceof Dog) 确认运行时类型确实是Dog
- 再写 Dog d = (Dog) a; 安全向下转型
- 之后才能调用 d.bark()
- 跳过instanceof直接强转,一旦a实际是Cat,运行时立刻抛 ClassCastException
真实场景中怎么用才自然?
多态的价值不在语法炫技,而在解耦与扩展。典型用法有两个:
- 方法参数统一化:定义 void feed(Animal a),传入Dog、Cat、Tiger都合法,内部调a.eat()自动适配
-
集合统一管理:List
animals = new ArrayList(); animals.add(new Dog()); animals.add(new Cat()); 遍历时用for-each调sound(),每只动物各响各的
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











