Course contents

Association, aggregation and composition

Association, aggregation and composition defined by lifecycle and ownership, written in Java (Order, Team, Doctor), with multiplicity, navigability, UML diamonds, what the garbage collector sees, and the LLD interview angle.

PremiumOften askedLesson14 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: a house, a football club and a clinic
  2. Under the hood: what each one looks like in Java
  3. Real world: the garbage collector doesn't know about ownership
  4. Advanced: edge cases interviewers probe
  5. How to say it in the interview

🔗 What are association, aggregation and composition?

They are three strengths of the "has-a" relationship between objects. Association means two objects know about each other and work together, like a Doctor and a Patient. Aggregation is a whole that groups parts which can live on without it, like a Team and its Players. Composition is a whole that owns its parts outright, like an Order and its OrderLines: delete order ORD-1001 and its three lines have no reason to exist.

Interviewers ask this in two places. In a core Java round, it's a quick check that you can define the terms precisely and say what decides which one you have (hint: lifecycle and ownership, not the syntax). In a low-level design round, it's everywhere: the moment you draw a class diagram for a parking lot or a food-delivery app, the interviewer reads your arrows and diamonds and asks "who owns this?" and "what happens to these when that's deleted?".

What you’ll learn

  • Define association, aggregation and composition by lifecycle and sharing, not by syntax
  • Write composition in Java that holds: the whole creates its parts and leaks nothing mutable
  • Draw the UML correctly: hollow vs filled diamond at the whole, multiplicity like 1..*, navigability arrows
  • Keep bidirectional associations in sync, or replace them with an association class like Appointment
  • Explain why the GC knows only reachability, so ownership in Java is a discipline you enforce
  • Use these words to drive lifecycle questions in an LLD round

For this lesson, we'll focus on what each relationship means in UML and in plain English, how each one looks in Java code, directionality and multiplicity, how Java's garbage collector sees (and doesn't see) ownership, and how to use all of this in an LLD interview.

Below the line (out of scope)

  • Is-a vs has-a, and why to prefer composition over inheritance: covered in Inheritance vs composition
  • Copying object graphs safely: covered in Deep copy vs shallow copy
  • JPA mapping annotations in depth (we mention cascade and orphanRemoval only as a bridge)

The 30-second answer

All three are has-a relationships, ordered by how tightly the lifecycles are bound. Association is the general "uses or knows" link with independent lifecycles: a doctor and a patient. Aggregation is a whole-part link where parts are shared and outlive the whole: a team and its players, drawn with a hollow diamond at the whole. Composition is exclusive ownership where the whole creates, controls and destroys its parts: an order and its lines, drawn with a filled diamond. Java syntax is the same for all three, a field holding a reference. The difference is the contract you enforce: who creates the part, whether references to it escape, and whether it's deleted with the whole.

Interview radar

Asked very often: Expect definitions of association, aggregation and composition, the correct UML diamond, and the lifecycle rule behind each term. Senior rounds probe: Strong rounds test multiplicity, navigability, bidirectional consistency, association classes and the fact that Java fields do not encode ownership. Production angle: This connects to cascade deletes, orphan rows, heap leaks from leaked references and object graphs that serialize or recurse forever.

01Picture it first: a house, a football club and a clinic

A house and its rooms is composition. The rooms are built as part of the house, belong to exactly one house, and when the house is demolished, the rooms go with it. A football club and its players is aggregation. The club groups them, but players existed before they signed and will play for another club after. A doctor and a patient is plain association. They meet, they know each other, neither owns the other, and either can exist without the other.

UML gives each one its own line ending, and the diagram below is the notation you'll draw in an interview.

Fig. 1

UML notation for three relationships: Doctor to Patient as a plain association line with many-to-many multiplicity, Team to Player with a hollow diamond at Team for aggregation, and Order to OrderLine with a filled diamond at Order for composition, each with a short meaning on the right

UML notation for three relationships: Doctor to Patient as a plain association line with many-to-many multiplicity, Team to Player with a hollow diamond at Team for aggregation, and Order to OrderLine with a filled diamond at Order for composition, each with a short meaning on the right

Notice three things:

  • The diamond sits at the whole, never at the part. Hollow means shared, filled means owned.
  • Multiplicity goes at each end: 1 order has 1..* lines; each line belongs to exactly 1 order. A composed part can belong to at most one whole at a time.
  • An arrowhead on the line marks navigability: which side can reach the other in code. No arrowheads usually means "not specified" or bidirectional.

There's also a weaker cousin you'll sometimes draw: dependency, a dashed arrow, for "uses temporarily", such as a method parameter (checkout.pay(gateway)) that's never stored in a field.

02Under the hood: what each one looks like in Java

Java has no owns or shares keyword. In all three cases, you write a field that holds a reference. The relationship lives in how you create, expose and release that reference. Let's write each one properly.

The diagram below separates the three relationships by the two questions that matter most in code: sharing and lifecycle.

Fig. 2

A lifecycle map contrasts association as independent uses links, aggregation as a shared whole-part link with a hollow diamond, and composition as exclusive owned parts with a filled diamond and delete cascade

A lifecycle map contrasts association as independent uses links, aggregation as a shared whole-part link with a hollow diamond, and composition as exclusive owned parts with a filled diamond and delete cascade

Composition: Order owns its OrderLines

Try it yourself first

Before reading on: list three things Order must do in code so that its lines are truly owned and can't be changed or kept alive by outsiders.

public final class Order {
    private final String id;
    private final List<OrderLine> lines = new ArrayList<>();

    public Order(String id) { this.id = id; }

    public void addLine(String sku, int quantity, BigDecimal unitPrice) {
        lines.add(new OrderLine(sku, quantity, unitPrice));   // the whole creates its parts
    }

    public List<OrderLine> lines() { return Collections.unmodifiableList(lines); }

    public BigDecimal total() {
        return lines.stream().map(OrderLine::subtotal).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public record OrderLine(String sku, int quantity, BigDecimal unitPrice) {
        public OrderLine {
            if (quantity <= 0) throw new IllegalArgumentException("quantity must be positive");
        }
        BigDecimal subtotal() { return unitPrice.multiply(BigDecimal.valueOf(quantity)); }
    }
}

var order = new Order("ORD-1001");
order.addLine("SKU-1", 2, new BigDecimal("499.00"));
order.addLine("SKU-7", 1, new BigDecimal("1299.00"));
System.out.println(order.total());   // prints: 2297.00
order.lines().clear();               // throws UnsupportedOperationException

Notice how ownership is enforced:

  • The whole creates the parts. Callers pass data (sku, quantity, price), not OrderLine objects they might keep and mutate.
  • Nothing mutable escapes. The list is exposed read-only, and OrderLine is an immutable record, so handing out a line is harmless.
  • The part makes no sense alone. OrderLine is nested inside Order, so even its name says "this belongs to an order".

Aggregation: Team groups Players

final class Player {
    private final String name;
    Player(String name) { this.name = name; }
    @Override public String toString() { return name; }
}

final class Team {
    private final String name;
    private final Set<Player> squad = new LinkedHashSet<>();
    Team(String name) { this.name = name; }

    void sign(Player p)    { squad.add(p); }       // part created elsewhere, passed in
    void release(Player p) { squad.remove(p); }    // removing does not destroy the player
    Set<Player> squad()    { return Set.copyOf(squad); }
}

Player virat = new Player("Virat");
Team rcb = new Team("RCB");
Team india = new Team("India");
rcb.sign(virat);
india.sign(virat);                       // the same Player object in two teams
rcb = null;                              // the team is gone...
System.out.println(india.squad());       // prints: [Virat]  ...the player isn't

The structural difference from Order is small but decisive: the part is created outside and passed in, it can sit in more than one whole, and the whole's API talks about signing and releasing, never deleting.

Association: Doctor and Patient

Association has no whole and no part. A doctor treats many patients and a patient sees many doctors (many-to-many). If both sides need to navigate to the other, the association is bidirectional, and you must keep both sides in sync:

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Real world: the garbage collector doesn't know about ownership
  • Advanced: edge cases interviewers probe
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicObject relationships: interview questions & scenarios
Further reading (6)