Stage 2: Object-oriented programming, lesson 10 of 15

IS-A and HAS-A: association, aggregation and composition

Intermediate3 min read@since 16Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

Objects relate to each other in two basic ways:

  • IS-A: inheritance or implementation. A Dog IS-A Animal; an ArrayList IS-A List.
  • HAS-A: one object holds a reference to another. HAS-A comes in three strengths, from loose to tight:
  1. Association: objects know or use each other, and each lives independently. A Doctor treats Patients; a Student attends Courses. It can be one-to-one, one-to-many or many-to-many.
  2. Aggregation: a whole–part association where the parts can exist on their own and may be shared. A Department has Employees; close the department and the employees still exist.
  3. Composition: a strong whole–part relationship. The part belongs to exactly one whole and lives and dies with it. An Order has OrderLines; delete the order and its lines are gone.

In Java all three look like fields. The difference is ownership and lifecycle: who creates the part, whether it can be shared, and what happens to it when the whole goes away.

Example

Java
// Association: uses another object; no ownership
class Doctor {
    Prescription treat(Patient patient) { return new Prescription(patient.id(), "Rest"); }
}

// Aggregation: holds parts that exist independently (created elsewhere, can move on)
class Department {
    private final List<Employee> employees = new ArrayList<>();
    void hire(Employee e) { employees.add(e); }          // the employee existed before
    void letGo(Employee e) { employees.remove(e); }        // and keeps existing after
}

// Composition: creates and owns its parts; they die with it
class Order {
    private final List<OrderLine> lines = new ArrayList<>();
    void addItem(String sku, int qty) { lines.add(new OrderLine(sku, qty)); }   // created inside
    List<OrderLine> lines() { return List.copyOf(lines); }                      // never hand out the internals
}
record OrderLine(String sku, int qty) {}
The same distinction in JPA
@Entity
class Order {
    // Composition: lines are saved and deleted with the order
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderLine> lines = new ArrayList<>();
}

@Entity
class Department {
    // Aggregation: employees outlive the department, so no cascading delete
    @OneToMany(mappedBy = "department")
    private List<Employee> employees = new ArrayList<>();
}

Common mistake

Calling every HAS-A relationship "composition". Ask who owns the part's lifecycle: if the part can outlive or be shared by the whole, it's aggregation.

Under the hood

In UML, association is a plain line, aggregation a hollow diamond on the whole's side and composition a filled diamond. Composition is also an encapsulation tool: because the Order owns its lines, it should never return its internal list (return a copy or an unmodifiable view), or outside code could change the order behind its back.

Check yourself

An Order creates its OrderLines, and they're deleted when the order is deleted. What relationship is this?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of OOP in practice.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.