应避免类层级过深,关键在于每层需有不可替代的语义价值和稳定契约;三层以内可接受,超两层须确认中间层是否承载所有子类共有的长期不变抽象,否则改用组合或接口;只对真实is-a关系使用继承,能力应通过接口声明;父类须能用“x是y”准确描述,否则拆解;警惕为复用而继承;用接口+default方法替代中间抽象类;将中间层转为组合策略;禁止父类越界承担子类细节。

避免类层级过深,关键不是限制继承次数,而是让每一层都有不可替代的语义价值和稳定契约。三层以内可接受,但超过两层就必须追问:中间层是否真的承载了所有子类共有的、长期不变的抽象?如果不是,就该用组合或接口替代。
只对真实 is-a 关系使用继承
继承表达“是什么”,不是“能做什么”或“用什么实现”。比如 Dog 是 Animal,合理;但 Order 是 Exportable 不成立——Order 能导出,不代表它“是”一种导出物。这类能力应通过接口(Exportable)声明,由 Order 实现,而非拉长继承链。
- 检查每个父类:能否用一句话准确说出“X 是 Y”的自然语言关系?不能,则考虑拆解
- 警惕“为了复用而继承”:Vehicle 继承 Machine 再继承 Device,往往只是因为想复用 init() 方法,实际语义断裂
- 把“有行为”和“是类型”分开——前者用
implements,后者才用extends
用接口+default方法替代中间抽象类
当多个不相关类需要共享某项逻辑(如日志、校验、序列化),不要硬造一个共同父类,而是定义接口并提供 default 方法。Java 8+ 支持在接口中封装通用实现,既避免继承污染,又支持多实现。
- 例如:
Loggable接口带default void log(String msg),Cat、Report、User 都可直接实现,无需共祖 - 接口聚焦能力契约,default 方法只封装稳定、无状态的通用逻辑,不涉及字段或复杂流程
- 比抽象类更轻量,且类可同时实现多个此类接口,解决单继承限制
把中间层转为组合策略
若已有三层结构(如 Animal → Mammal → Dog),但 Mammal 的职责开始模糊(比如混入持久化或 UI 相关逻辑),说明它已越界。此时应将“哺乳特征”等正交关注点抽成独立组件,由 Dog 持有,而非继承。
- 把
Mammal中的suckle()等核心行为封装为MammalBehavior接口,Dog通过字段持有其实例 - 构造时注入,便于测试替换(比如模拟幼犬喂养失败场景)
- 原
Mammal类可降级为工具类或彻底移除,继承链回归为Animal → Dog
禁止父类越界承担子类细节
每层抽象类只负责本层契约,不预设下层实现方式。常见错误是 Mammal 里写数据库操作,或 Payment 抽象类里硬编码微信支付参数——这会让所有子类被迫继承无关逻辑。
- 抽象类只封装共性状态(如
id、createdAt)和模板骨架(如doProcess()调用preCheck()和postNotify()) - 易变逻辑(校验规则、通知渠道)必须定义为接口,由子类或外部注入实现
- 父类方法尽量用
final修饰,或整个类声明为final,从源头封住不当继承
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











