java继承的核心是严格建模is-a关系,要求子类是父类真实、自然、可替换的特化类型;判断标准为:自然语言可说通、行为可安全替换(liskov原则)、传递性成立但不可逆;常见误用是将has-a混淆为is-a;不满足is-a时应优先选用组合或接口。

Java 继承的核心不是“能复用就继承”,而是严格服务于 is-a(是一种) 的语义建模。它要求子类在现实逻辑和行为契约上,必须是父类的一个**真实、自然、可替换的特化类型**。
判断 is-a 是否成立:三看标准
不能靠字段相似或方法名字一样来决定,要回归常识和语义:
- 自然语言可说通:能脱口而出“X 是一种 Y”,且不别扭、不强行解释。例如:“哈士奇是一种狗”✅,“订单是一种用户”❌。
- 行为可安全替换(Liskov 替换原则):任何使用父类对象的地方,换成子类对象后,程序逻辑不变、结果合理。比如 Bird 有 fly(),若 Ostrich extends Bird 却让 fly() 抛异常或空实现,就破坏了契约,说明“鸵鸟是一种会飞的鸟”这个 is-a 不成立。
- 传递性成立但不可逆:本科生 → 学生 → 人,那么本科生 → 人 ✅;但反过来,“人 → 学生” ❌——父类绝不能因为子类存在而反向继承。
常见误用:把 has-a 当成 is-a
这是最典型的滥用,本质混淆了“拥有关系”和“分类关系”:
- User has a Order → 应在 User 类中定义 private Order order 字段,而不是让 User extends Order。
- Car has an Engine → Engine 应作为 Car 的成员变量,而非父类。
- 所有 POJO 都继承 BaseEntity 只为共享 id 字段 → 这是“共用字段”,不是“是一种基实体”。更合适的是提取公共字段到 DTO 工具类,或用接口定义通用能力(如 Identifiable)。
is-a 成立时,继承才真正有价值
只有满足 is-a,继承才能支撑起清晰的领域模型和稳健的多态:
- 抽象出共性:Animal 定义 eat()、sleep(),Dog 和 Cat 分别继承并实现自己的版本,语义统一、扩展自然。
- 支持多态调度:List
animals = Arrays.asList(new Dog(), new Cat()); animals.forEach(Animal::eat); —— 调用逻辑不依赖具体类型,正因 Dog is-a Animal。 - 约束设计边界:Java 单继承强制你思考“这个类最本质的、不可拆分的类别身份是什么?”,避免把职责杂糅进一个继承链。
替代方案比继承更常用
现实中多数复用需求并不满足 is-a,这时应优先考虑:
- 组合(has-a):通过成员变量持有其他对象,灵活、低耦合。
- 接口(can-do):定义能力契约,如 Flyable、Payable,类可自由实现多个,表达“能做什么”,而非“是什么”。
- 默认方法 + 接口:Java 8+ 允许接口提供 default 实现,兼顾契约与复用,又不破坏 is-a 的纯洁性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











