父类引用指向子类对象是Java多态的核心实践方式,需满足继承/实现关系、子类重写父类非私有非静态方法、父类声明指向子类实例三个条件;成员变量访问看引用类型(左边),方法调用看实际对象类型(右边);向下转型须用instanceof校验以避免ClassCastException。

父类引用指向子类对象是Java多态的核心实践方式,关键不在“能不能写”,而在于“怎么用得安全、清晰、可扩展”。它不是语法炫技,而是为了解耦、复用和应对变化。
明确多态成立的三个硬性条件
缺一不可,否则编译报错或运行异常:
- 存在继承关系(class Son extends Father)或实现关系(class Dog implements Animal)
- 子类重写了父类的非私有、非静态方法(只有重写的方法才能在运行时动态绑定)
- 声明父类类型变量,实际指向子类实例(Father f = new Son();)——这叫向上转型,自动完成
变量访问与方法调用的行为差异
这是最容易混淆的点:成员变量看“左边”,成员方法看“右边”。
- 访问成员变量:编译期就决定,只认引用类型(左边)。例如 Father f = new Son(); System.out.println(f.age); 输出的是 Father.age 的值,哪怕 Son 自己定义了同名 age
- 调用成员方法:运行期才决定,实际执行子类重写后的方法。例如 f.show(); 会输出 Son.show() 的内容(前提是 show() 在 Son 中被 @Override)
向下转型必须加安全校验
从父类引用回到子类对象(如 Son s = (Son) f;)不是自动的,属于向下转型,有风险:
- 若 f 实际指向的不是 Son 类型(比如是 Daughter 或纯 Father),强转会抛出 ClassCastException
- 正确做法是先用 instanceof 判断:
if (f instanceof Son) {
Son s = (Son) f;
s.specificMethod(); // 调用子类特有方法
}
实战中推荐的典型用法
避免裸写转型,把多态价值真正落地:
- 作为方法参数:写一个 void feed(Animal a),传入 new Dog() 或 new Cat() 都能运行,且各自执行自己的 eat() 行为
-
作为集合元素类型:用 List
存不同动物,遍历时统一调用 move(),无需 if-else 判断类型 - 返回值多态:工厂方法 Animal create(String type) 根据参数返回 Dog 或 Cat,调用方只需按 Animal 使用,不关心具体构造细节

















