关键在于避免子类依赖父类内部实现:禁止父类构造器调用可重写方法;用final封装核心逻辑,private工具方法,private字段+protected访问器;警惕自调用链中可覆盖点;优先组合而非继承。

关键在于不让子类被迫依赖父类的内部实现细节。封装的本质是隐藏怎么做,只暴露能做什么;一旦子类必须知道父类“怎么实现”才能正确重写方法,封装就已受损。
别在父类构造器里调用可重写方法
这是最危险的场景之一:父类构造过程中,子类字段还没初始化,此时调用被重写的方法,极易触发 null 或默认值错误。
- 父类构造器中避免直接调用任何可能被子类重写的方法(如 init()、setup() 等)
- 若需初始化钩子,改用 final 方法封装逻辑,再由子类通过 safeInit() 这类明确命名的 protected 方法参与
- 或者把初始化拆到构建完成后的显式 setup() 调用中,避开构造阶段
限制可重写范围,用 final 和访问控制收口
不是所有方法都该开放重写——父类应主动声明哪些行为“不可定制”,哪些“仅限受控扩展”。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 明确不希望被覆盖的方法,一律加 final 修饰(比如核心流程控制方法)
- 工具类方法优先设为 private,避免被子类误用或误重写
- 字段全部声明为 private,提供 protected 的 getter/setter(而非直接暴露字段),让子类通过契约接口访问状态
警惕自调用链中的可覆盖点
父类公开方法内部调用另一个可被重写的方法,会导致子类重写后逻辑悄然改变,且难以察觉。
立即学习“Java免费学习笔记(深入)”;
- 例如 addAll() 内部调用 add(),而 add() 是 public/protected —— 子类重写 add() 后,addAll 行为就变了
- 解决方案:将 add() 改为 private 工具方法,或提取为 final 模板方法 + abstract hook
- 更稳妥的做法是把这类组合逻辑下沉为 final 方法,只留少数 clearly-named abstract 方法供子类实现
慎用继承,优先考虑组合
当复用需求大于 is-a 关系时,继承容易引发语义失配和接口污染(比如 Stack 继承 Vector 后不得不暴露 removeElementAt())。
- 把父类作为成员变量持有,显式委托调用(Delegation),边界清晰、职责分明
- 组合天然规避了对父类内部实现的依赖,也更容易做 mock 和单元测试
- 配合接口定义能力契约,比继承更灵活、更安全

















