继承不必然破坏封装,但不当使用会架空其保护意图;应避免暴露protected字段、构造器调用可重写方法,优先组合替代继承,并利用密封类分层控制扩展性。

继承本身不必然破坏封装,但不当使用会直接架空封装的保护意图——关键在于子类是否能绕过父类设定的状态约束,或迫使父类暴露本不该公开的实现细节。
警惕“受控访问”变成“自由穿透”
封装的核心是维护对象内部的合法状态。一旦子类可以无约束地修改父类字段、重写关键校验逻辑,或通过protected成员直接干预内部流程,封装就形同虚设。
- 避免在父类中暴露
protected字段,尤其涉及业务不变量(如余额、状态码);宁可用protected方法封装操作,且方法内保留校验 - 父类构造器中不要调用可被子类重写的方法——否则子类可能在自身字段初始化前就被执行,引发NPE或状态错乱
- 若父类提供
setXXX()方法,需明确它是否允许任意值;否则应改用语义化动作方法,如confirmPayment()而非setStatus(3)
用组合替代继承,守住封装边界
当“is-a”关系不稳固,或子类只需复用部分行为时,强行继承会倒逼父类开放过多内部细节以供子类定制,本质是把封装责任转嫁给调用方。
- 优先考虑将共用逻辑提取为独立组件,由父类和子类共同持有(例如:订单状态机、金额计算引擎)
- 用接口定义能力契约,而非靠继承传递字段和
protected方法。子类实现接口,内部自行管理状态,不共享父类数据结构 - Spring生态中大量采用组合:比如
JdbcTemplate不继承DataSource,而是持有一个——它只依赖接口,不侵入数据模型
密封类 + 非密封子类:分层控制开放程度
Java 17+ 的密封类机制,让封装与继承不再非此即彼。你可以明确限定谁可以继承,同时允许特定子类成为扩展入口,既防滥用,又保弹性。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 核心领域模型(如
Order、Account)声明为sealed,只允许预设的几个子类继承 - 其中某个子类(如
RefundableOrder)标记为non-sealed,供业务模块按需扩展,但不会影响基础订单的状态规则 - 这样,父类的不变量仍在自己体内守卫,而扩展性由可控的子类层次承担
重构信号:当继承开始倒逼父类妥协
以下迹象说明继承正在侵蚀封装:
- 父类不断添加
protected字段或空方法(如beforeSave()),只为满足某个子类的定制需求 - 子类重写方法后必须手动调用
super.xxx()才能维持基础逻辑,稍有遗漏就破坏一致性 - 测试父类行为时,必须用子类实例才能覆盖全部路径——说明父类已无法独立保证自身正确性
此时不是该修子类,而是该重新评估:这段逻辑是否本就不该放在继承链里?

















