继承应严格用于真正的is-a关系,如manager是employee;避免将has-a(car是engine)或违反里氏替换原则(square是rectangle)的关系误用继承;优先采用组合实现行为复用,确保设计可控、扩展安全。

避免滥用继承,关键不是“少用”,而是“用得对”。核心在于判断关系是否成立、设计是否可控、扩展是否安全。
先确认是不是真正的 is-a 关系
继承只适用于语义上清晰的“是一个”关系。比如:
• Manager 是 Employee → 合理
• Car 是 Engine → 错误(这是 has-a,该用组合)
• Square 是 Rectangle → 表面合理,但违反里氏替换原则(修改 width 会意外改变 height),实际不可靠
如果把两个类强行拉进继承链,只是为了复用一两个方法,那大概率是误用。
优先考虑组合而非继承
当目标是复用行为或能力时,组合通常更灵活、更解耦:
- 用接口定义能力(如 PaymentStrategy、Logger),通过构造器或 setter 注入具体实现
- 子类不依赖父类的字段和内部逻辑,父类改动不会意外破坏子类
- 运行时可替换行为(比如从 AlipayStrategy 切到 WechatStrategy),继承做不到这点
Java 标准库也倾向组合:Collections 工具类封装操作,而不是让 ArrayList 继承一个“可排序容器”。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
检查父类是否真正为继承而设计
不是所有类都欢迎被继承:
- 看源码:是否有 protected 方法、template method 模式(如
execute()调用doExecute()) - 看文档或注解:是否明确标注
@MustOverride或 “designed for extension” - 看修饰符:父类是 final,或关键方法是 private/final → 暗示不鼓励继承
盲目继承 String、LocalDateTime 这类 final 类,编译直接失败;继承 AbstractList 却忽略其内部状态约定,JDK 升级后可能出 bug。
警惕继承带来的隐性风险
继承不只是代码复用,它绑定了生命周期和契约:
- 父类构造器调用链不可控:若父类构造中调用了可被重写的方法,子类字段可能尚未初始化就被访问
- protected 字段暴露实现细节:子类直接读写父类 protected 成员,等于把封装撕开一道口子
- 重写 toString()、equals() 忘记 super 调用 → 日志丢失关键信息、集合操作异常
这些不是理论问题,而是线上 ClassCastException、空指针、行为不一致的常见源头。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










