继承是is-a关系,组合是has-a关系;设计上优先选组合,因其更灵活、安全、易维护:继承支持向上转型和多态但破坏封装,组合依赖接口、运行时可替换且符合单一职责原则。

直接说核心:继承是is-a关系,组合是has-a关系;设计上优先选组合,不是因为它不能做继承的事,而是它更灵活、更安全、更易维护。
语义和关系本质不同
继承表达“是一个”——比如 Dog extends Animal,狗是一种动物,天然具备动物的共性行为(如呼吸、进食),也适合向上转型实现多态。
组合表达“有一个”或“由……组成”——比如 Car 类里持有一个 Engine 对象:private Engine engine;,车不是引擎,但车包含引擎。这种关系不涉及类型强绑定,也不支持用 Engine 引用指向 Car。
复用方式与封装性差异
继承属于“白盒复用”:子类能直接访问父类的非私有成员,甚至重写方法,但这也意味着父类内部实现细节对子类可见,一旦父类逻辑调整(比如修改 protected 方法的行为),所有子类都可能被动受影响。
立即学习“Java免费学习笔记(深入)”;
组合是“黑盒复用”:整体类只依赖部件类的公开接口,不关心其内部怎么实现。哪怕把 Tire 换成 SmartTire,只要接口一致,Car 完全无感,封装性更强。
灵活性与可维护性对比
继承在编译期就固定了父子关系,无法动态更换;而组合的对象可以在运行时替换(比如通过 setter 注入不同策略对象),天然适配策略模式、依赖注入等现代设计思想。
Java 只支持单继承,过度使用继承容易导致类层次臃肿、职责混乱,甚至违反单一职责原则。组合则没有这类限制,一个类可以持有多个不同类型部件,职责清晰、扩展自由。
面试时怎么收尾才显专业
可以补充一句:“《Effective Java》第16条明确建议‘Favor composition over inheritance’。实际项目中,我们通常先问一句——这个新类和已有类之间,到底是‘是’的关系,还是‘用’的关系?如果是后者,组合几乎总是更优解。”


















