合理继承需满足is-a关系、支撑多态、需要契约约束;优先组合优于继承;继承链不超过两层;善用密封类限制扩展;注意构造器调用顺序与访问修饰符设计。

设计合理的 Java 继承结构,核心是让“继承”真正服务于语义和行为,而不是为了省几行代码。它不是层级越深越好,也不是能用就用——关键看是否满足 is-a 关系、是否支撑 多态需求、是否需要 契约约束。
只在语义清晰时才用继承
继承表达的是“是一种”的关系,不是“有一个”或“用得上”。比如:
- 合理:Student 是 Person,ElectricCar 是 Car,Bird 是 Animal —— 这些有稳定、公认、不可逆的分类逻辑
- 不合理:Logger 是 File(其实是“记录到文件”,属于 has-a),或者 Button 是 Drawable(应优先用接口实现)
如果把“能复用方法”当成继承理由,大概率会掉进“紧耦合+难测试”的坑。Oracle 官方明确建议:组合优于继承。
控制深度,一般不超过两层
三层及以上继承链(A → B → C → D)会明显增加理解成本和维护风险:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 构造器调用顺序复杂,子类字段可能在父类方法中被提前访问,引发 NPE
- 中间层修改一个 protected 方法,下游所有子类行为都可能意外改变
- 调试时难以追踪方法实际执行路径,尤其是多级重写后
更稳妥的做法是:用 接口 + 默认方法 提供通用能力(如 Flyable.fly()),或用 装饰器模式 动态增强(如 BufferedInputStream 包装 FileInputStream)。
善用密封类限制可扩展范围
Java 17 引入的 sealed class 是对继承边界的精准控制:
- 声明
sealed class Shape permits Circle, Rectangle, Triangle,就表示只有这三个类能继承 Shape - 避免 public 抽象类被任意类随意继承,也比 final 类更灵活
- 配合
permits和non-sealed,可在限定范围内保留扩展性
适合领域模型中明确有限子类型的场景,比如订单状态、消息类型、协议版本等。
注意构造与访问修饰符的设计细节
很多继承问题其实出在初始化和可见性上:
- 父类构造器里不要调用 可能被子类重写的方法,否则子类字段尚未初始化就执行了重写逻辑
- 避免 public 字段 —— 它让子类直接依赖父类实现细节,破坏封装
- protected 成员可被子类访问,但要清楚:它既是便利,也是责任边界;private 成员虽不继承,但可通过 protected getter 提供受控访问
- 若父类没有无参构造器,子类必须显式写
super(...),否则编译失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










