Within HAS-A relationships, how do composition and aggregation differ in terms of ownership and lifecycle?
answer
- Composition = strong/exclusive; aggregation = weak/shared
- Destroy whole → part dies? yes=composition, no=aggregation
- Created internally (composition) vs injected (aggregation)
- Filled diamond vs hollow diamond in UML
- Both are HAS-A; difference is lifecycle + sharing
basics
~20 sBoth are HAS-A. Composition is strong ownership: the part can't live without the whole, and when the whole is destroyed, so is the part (a House HAS rooms). Aggregation is weak: the part can exist independently and may be shared (a Team HAS players who outlive the team).
solid answer
~60 sComposition and aggregation are two flavors of the HAS-A relationship that differ in ownership strength and lifecycle. Composition is a strong, exclusive 'whole-part' relationship: the part has no meaningful existence outside its owner, the owner typically creates the part internally, and when the owner is garbage-collected the part goes with it. A House and its Rooms, or an Order and its private LineItems, are composition. Aggregation is a weaker association: the contained object can exist on its own, is usually passed in from outside, and may be shared by several owners. A Team aggregates Players who exist before, after, and independently of the team; a Department aggregates Employees. In code the tell is where the part comes from and who can reach it: composition usually means the owner constructs the part and never leaks the reference; aggregation means the reference is injected and the part survives the owner. In UML, composition is the filled diamond and aggregation the hollow diamond. The distinction guides defensive copying, cascade-delete decisions, and how you reason about object lifetimes.
code
java · 12 lines// Composition: House owns its Rooms (created internally, not shared)
class Room {}
class House {
private final List<Room> rooms = List.of(new Room(), new Room());
}
// Aggregation: Team holds Players that live independently
class Player {}
class Team {
private final List<Player> players;
Team(List<Player> players) { this.players = players; } // injected, shareable
}go deeper
Can give the textbook examples — House/Room (composition, part dies with whole) and Team/Player (aggregation, part lives on) — and state that both are HAS-A.
Explains the deciding questions (lifecycle binding, who creates the part, shareability) and recognizes that both compile to a field; the difference is design intent, not syntax.
Connects the distinction to concrete engineering consequences: defensive copying for composed mutables, cascade-delete/orphan-removal in persistence, and threading implications of shared aggregated objects.
Treats it as a modeling spectrum and reasons about where to draw the boundary for a given domain, the cost of getting ownership wrong (shared mutable state, leaked lifecycle), and how the choice ripples into persistence, concurrency, and API contracts.
## Two strengths of HAS-A Every HAS-A (one object holding another) sits somewhere on a spectrum of **ownership strength**. The two named points on that spectrum are **composition** (strong) and **aggregation** (weak). Both are 'has-a' — the difference is *how tightly the lifetime and existence of the part are bound to the whole*. ### Composition — strong, exclusive ownership In **composition**, the contained object (the **part**) is owned **exclusively** by the container (the **whole**) and cannot meaningfully exist without it. Three signals characterize it: 1. **Lifecycle binding:** the part is created when the whole is created and dies when the whole dies. Destroy the `House` and its `Room`s cease to exist. 2. **Exclusivity:** the part belongs to exactly one whole; it is not shared. 3. **Encapsulation:** the whole typically constructs the part itself and never hands the reference out. ```java class Room { } class House { // House creates and exclusively owns its Rooms private final List<Room> rooms = List.of(new Room(), new Room()); } // when the House is unreachable, the Rooms become unreachable too ``` Because Java has garbage collection, 'destroying the part' happens automatically: once the `House` is unreachable and there is no *other* reference to a `Room`, that `Room` becomes eligible for GC as well. Composition is the relationship behind defensive copying — if a composed part is mutable, the owner copies it on the way in and out so no outside code can tamper with something it conceptually owns. ### Aggregation — weak, shared association In **aggregation**, the contained object can **exist independently** of the container and is often **shared**. Signals: 1. **Independent lifecycle:** the part is created elsewhere, outlives the whole, and is usually **passed in** (injected) rather than created internally. 2. **Sharing allowed:** the same part may be referenced by several wholes. ```java class Player { } class Team { private final List<Player> players; Team(List<Player> players) { this.players = players; } // players come from outside } // deleting the Team does NOT delete the Players; they live on, maybe in another Team ``` A `Player` exists before joining a `Team`, can belong to multiple teams, and survives the team's disbandment. That is aggregation. ### The deciding questions - **'If I destroy the whole, should the part be destroyed too?'** Yes → composition. No → aggregation. - **'Where does the part come from?'** Created internally → leans composition. Injected from outside → leans aggregation. - **'Can the part be shared by more than one owner?'** No → composition. Yes → aggregation. ### UML notation Both are drawn as a diamond on the *whole* end of the line. **Composition = filled (black) diamond**; **aggregation = hollow (white) diamond**. A plain line with no diamond is a generic **association**. ### Why it matters in practice - **Defensive copying:** composed mutable parts should be copied in/out to preserve exclusive ownership; aggregated shared parts are intentionally *not* copied. - **Cascade semantics:** in persistence (e.g. JPA), composition maps to cascade-delete / orphan removal; aggregation does not cascade. - **Reasoning about lifetimes & threading:** a shared (aggregated) object may be touched by multiple owners and may need synchronization; an exclusively composed object does not. Note: the composition/aggregation line is a **modeling judgment**, not a Java keyword. Both compile to 'a field holding a reference.' The difference lives in *who creates the part, who else can reach it, and what happens to it when the owner goes away.*
- Is the composition-vs-aggregation distinction enforced by the Java compiler?No. Both are just a field holding a reference, so they compile identically. The distinction is a design/modeling judgment about ownership and lifecycle — captured in UML, defensive-copying choices, and persistence cascade rules — not in any Java keyword.
- How does the distinction influence JPA persistence mapping?Composition typically maps to cascade = ALL with orphanRemoval = true so deleting the owner deletes the parts; aggregation maps to a relationship without delete-cascade so the referenced entities survive independently.
Composition: a human and their heart — the heart doesn't survive on its own and belongs to one body. Aggregation: a university and its visiting professors — they existed before, may teach elsewhere, and remain after the term ends.
saying these in an interview costs you the question
- Claiming Java has a keyword for composition vs aggregation — there isn't one; it's a modeling distinction.
- Saying composition allows sharing the part across owners — that's aggregation; composition is exclusive.
- Asserting an aggregated part dies with its owner — aggregated parts have independent lifecycles.