java运行时多态的核心是父类引用指向子类对象,如animal a = new dog();编译期检查声明类型,运行时动态绑定重写方法,实现解耦、开闭原则与依赖倒置。

这是Java运行时多态最典型、最实用的表现形式:用父类类型声明变量,却用子类构造器创建对象,比如 Animal a = new Dog();。它不是类型转换的技巧,而是面向抽象编程的落地方式——代码只依赖约定(父类/接口),具体行为由实际对象决定。
它怎么工作:编译期检查 + 运行时绑定
编译器只认左边声明的类型(Animal),所以你只能调用 Animal 中定义的方法;但 JVM 在运行时会查看右边真实对象(Dog),如果该方法被重写,就执行子类版本。这个过程叫动态方法调度,仅对非 static、非 private、非 final 的实例方法生效。
- Animal a = new Dog(); a.sound() → 执行 Dog.sound()
- a.name → 访问的是 Animal 类中的 name 字段(字段不参与多态)
- a.sleep() → 调用 Animal.sleep()(静态方法绑定在编译期)
它为什么有用:解耦与扩展的实际价值
不用改一行已有逻辑,就能接入新功能:
- 方法参数用父类类型:feed(Animal pet) 可接收 Dog、Cat、Bird,无需重载或 if-else
- 集合统一管理:List
animals = Arrays.asList(new Dog(), new Cat()); 遍历时直接 animals.forEach(Animal::sound) - 替换实现零感知:List
list = new ArrayList(); 换成 LinkedList 只需改这一行,上层代码完全不动
它不能做什么:边界必须清楚
父类引用是一扇有框的窗,只能看到父类公开的“风景”:
- 子类独有的方法(如 Dog.bark())无法直接调用,编译报错
- 子类新增字段(如 Dog.loyalty)不可见
- 同名字段访问取父类值,哪怕子类也定义了同名字段
- 要调子类特有能力?先用 instanceof 判断,再安全向下转型
它支撑的不只是语法:是设计原则的日常体现
这不是为了写得“高级”,而是让代码符合工程规律:
- 开闭原则:新增 Cat 类,原有 feed() 和遍历逻辑全都不用动
- 依赖倒置:业务层依赖 Animal 抽象,不依赖 Dog 或 Cat 具体实现
- 策略模式基础:不同支付方式(WechatPay、Alipay)都实现 Payment 接口,统一用 Payment pay = ... 切换行为
- 测试友好:单元测试中可传入轻量 MockAnimal,绕过真实网络或数据库











