聚合是“我用你”,组合是“我就是你的一部分”;聚合中整体不new部分对象、部分可共享且独立存在,组合中整体内部new部分对象、部分不可共享且生命周期依附整体。

聚合和组合的本质区别就一句话
聚合是“我用你”,组合是“我就是你的一部分”——关键看 new 谁来调、生命周期谁管。
怎么写代码一眼看出是聚合还是组合
看整体类里有没有对部分类的 new 调用:
- 聚合:整体类不 new 部分对象,只通过构造函数或 setter 接收外部传入的引用,比如
public Department(Listmembers) - 组合:整体类在内部直接
new部分对象,比如this.engine = new Engine();写在Car构造函数里 - 聚合支持共享:同一个
Employee实例可被多个Department引用;组合不行,Engine一旦被Car持有,就不能再塞进另一辆Car - 聚合对象销毁时,仅清空引用(如
members.clear()),部分对象仍存活;组合中,整体 GC 后,部分对象若无其他引用,自然被回收
常见误判场景:关联 ≠ 聚合,但聚合一定是关联
很多人把“类里有个引用”就当成聚合,这是错的。真正构成聚合,必须满足语义上的“整体-部分”且部分可独立存在:
-
Teacher持有Student引用?→ 大概率只是普通 关联(教学关系临时、双向、无结构归属) -
ClassRoom持有List并长期管理学籍?→ 才算升级为 聚合(学生是班级的组成部分,但可转班、休学、退学) -
Order持有OrderItem列表?→ 很可能是 组合,因为订单取消时,所有条目应逻辑失效,且OrderItem不该脱离Order单独存在
最容易踩的坑:把聚合写成组合,或反过来
典型错误是“以为用了 List 就是聚合”,结果在构造函数里偷偷 new 了:
立即学习“Java免费学习笔记(深入)”;
class Department {
private List members;
public Department() {
this.members = new ArrayList<>(); // ❌ 这是组合倾向!成员由自己创建
this.members.add(new Employee("张三")); // 更错:连外部注入都绕过了
}
}
正确聚合写法:
class Department {
private List members;
public Department(List members) { // ✅ 外部传入,不 new
this.members = members;
}
public void addEmployee(Employee e) { // ✅ 只增引用,不接管生命周期
this.members.add(e);
}
}
真实项目里,这种混淆会导致内存泄漏(组合对象被意外强引用)、测试困难(无法 mock 部分对象)、模块解耦失败——聚合本该让 Employee 服务能独立部署和替换,结果被硬编码锁死在 Department 里。










