父类引用指向子类对象是利用继承实现多态的核心机制,需满足继承关系、方法重写、向上转型三前提;访问变量看引用类型,调用方法看实际类型;需子类特有功能时须先instanceof校验再向下转型。

父类引用指向子类对象,本质是利用继承关系实现多态,核心不是“能不能写”,而是“怎么用得安全、清晰、可扩展”。它让代码更灵活,也更容易应对后续新增子类的需求。
必须满足的三个前提
缺一不可,否则编译失败或运行出错:
- 存在明确的继承或实现关系(如 class Dog extends Animal 或 class FileLogger implements Logger)
- 子类重写了父类的非私有、非静态、非 final 方法(只有重写的方法才能在运行时动态调用)
- 声明时用父类类型,实际创建子类实例(Animal a = new Dog();),这叫向上转型,Java 自动完成,无需强制转换
访问变量和调用方法的行为不同
这是最容易踩坑的地方:
- 访问成员变量时,看的是引用类型(左边):即使子类定义了同名字段,a.name 取的仍是 Animal.name 的值
- 调用成员方法时,看的是实际对象类型(右边):只要 Dog 重写了 makeSound(),执行 a.makeSound() 就一定调用 Dog.makeSound()
需要调用子类特有功能?先校验再转型
父类引用不能直接访问子类独有的方法或字段。若确实需要,必须向下转型,但必须加安全判断:
- 错误写法:Dog d = (Dog) a; —— 若 a 实际指向的是 Cat,立刻抛 ClassCastException
- 正确写法:if (a instanceof Dog) { Dog d = (Dog) a; d.bark(); }
- Python 中虽无显式转型,但同样建议用 isinstance(a, Dog) 判断后再调用特有方法
典型使用场景
不是为了炫技,而是解决真实问题:
- 统一处理一批不同类型的对象(如 List
shapes = Arrays.asList(new Circle(), new Rectangle()); ,遍历调用 draw()) - 框架设计中预留扩展点(如日志模块定义 Logger 接口,用户可自由实现 ConsoleLogger、FileLogger,主逻辑只依赖接口)
- 避免大量 if-else 判断类型(用多态替代条件分支,更易维护)










