父类引用指向子类对象是多态唯一有效方式,体现为接口引用+具体实现(如list list = new arraylist();),支撑开闭原则、策略模式与依赖倒置,仅允许调用父类声明的方法。

父类引用指向子类对象,不是语法技巧,而是多态真正起作用的唯一方式。它让代码只依赖“能做什么”,而不是“谁来做的”。比如 Animal a = new Dog(); —— 变量类型是 Animal,实际跑的是 Dog 的逻辑。
它到底在代码里怎么体现
这不是特殊写法,而是日常开发中随处可见的惯用模式:
-
List
list = new ArrayList(); —— 接口引用 + 具体实现 - Runnable task = () -> System.out.println("run"); —— 函数式接口也是同一原理
- Payment pay = new WechatPay(); —— 支付模块用抽象类型承接具体实现
为什么非得这样写,不能直接 new 子类
直接写 Dog d = new Dog(); 看似简单,但一扩展就卡住:
- 加个 Cat,所有用 Dog 的地方都要改类型、改方法调用
- 测试时想换 MockDog,就得动入参或重构签名
- 业务逻辑和具体实现绑死,比如支付写死 WechatPay pay = new WechatPay();,接入支付宝就得重写业务层
它怎么支撑真实项目演进
这不是理论概念,而是工程落地的关键基础设施:
- 新增子类(如新动物、新支付渠道)无需修改已有调用逻辑 —— 开闭原则自然成立
- 不同算法封装成子类,统一用父类引用切换行为 —— 策略模式水到渠成
- 业务模块只依赖 Payment、Animal 这类抽象 —— 符合依赖倒置,高层不依赖低层
- 单元测试可传入轻量 Mock 子类,绕过数据库、网络等外部依赖
它能干啥,不能干啥
父类引用是个“安全视窗”,只暴露契约定义的部分:
- ✅ 调用父类声明、且被子类重写的方法 → 运行时自动执行子类版本
- ✅ 访问父类的 public / protected 字段(但应尽量避免,推荐封装)
- ❌ 调用子类独有的方法(如 Dog.bark())→ 编译报错,除非显式向下转型
- ❌ 访问子类新增字段 → 编译不通过
- ❌ 静态方法、final 方法、private 方法 → 不参与多态,绑定发生在编译期
说到底,它强制你面向契约编程:只关心“约定好的能力”,不纠缠“某个具体怎么做”。











