Aggregation in Java – HAS-A Relationship Explained
Aggregation is a HAS-A relationship in which one object (the whole) holds references to other objects (the parts), but the parts can exist independently of the whole. A department has employees, yet employees continue to exist if the department is closed, and one employee may belong to several departments.
Aggregation is one of the three forms of object association, alongside plain association and composition. This tutorial explains all three with examples and shows when HAS-A is a better design than inheritance.
1. Association, Aggregation and Composition
Objects relate to each other in increasingly strong ways:
| Relationship | Meaning | Ownership / life cycle | Example |
|---|---|---|---|
| Association | Objects use or know each other | None | Doctor – Patient |
| Aggregation (weak HAS-A) | Whole contains parts | Parts live independently and can be shared | Department – Employee |
| Composition (strong HAS-A) | Whole owns parts | Parts are created by and die with the whole | Order – OrderLine, House – Room |
In UML diagrams, aggregation is drawn with a hollow diamond on the whole's side, and composition with a filled diamond.
2. Aggregation Example
import java.util.ArrayList;
import java.util.List;
public class AggregationDemo {
// Part: exists independently of any Department
static class Employee {
final String name;
Employee(String name) { this.name = name; }
public String toString() { return name; }
}
// Whole: HAS-A list of employees, but does not own their life cycle
static class Department {
final String name;
private final List<Employee> members = new ArrayList<>();
Department(String name) { this.name = name; }
void add(Employee e) { members.add(e); }
void remove(Employee e) { members.remove(e); }
public String toString() { return name + " " + members; }
}
public static void main(String[] args) {
Employee asha = new Employee("Asha"); // created outside the department
Employee ravi = new Employee("Ravi");
Department backend = new Department("Backend");
Department platform = new Department("Platform");
backend.add(asha);
backend.add(ravi);
platform.add(asha); // the same employee can belong to two departments
System.out.println(backend);
System.out.println(platform);
backend = null; // department dissolved...
System.out.println("Asha still exists: " + asha + ", member of " + platform);
}
}
Backend [Asha, Ravi] Platform [Asha] Asha still exists: Asha, member of Platform [Asha]
- Employees are created outside the department and passed in.
- The same
Employeeobject is shared by two departments. - Discarding a department does not destroy its employees.
3. Composition Example
In composition, the whole creates and controls its parts. Here an order's lines are created inside the order and cannot be reached or shared from outside:
import java.util.ArrayList;
import java.util.List;
public class CompositionDemo {
// Composition: the Order creates and owns its lines; they cannot exist alone
static class Order {
private final String id;
private final List<Line> lines = new ArrayList<>();
Order(String id) { this.id = id; }
void addLine(String product, int qty, double price) {
lines.add(new Line(product, qty, price)); // created by the whole
}
double total() { return lines.stream().mapToDouble(Line::amount).sum(); }
// The part type is private: nobody outside can create or share a Line
private record Line(String product, int qty, double price) {
double amount() { return qty * price; }
}
public String toString() { return "Order " + id + ": " + lines.size() + " lines, total " + total(); }
}
public static void main(String[] args) {
Order order = new Order("A-17");
order.addLine("Keyboard", 1, 2499);
order.addLine("Mouse", 2, 799);
System.out.println(order);
// When the order is discarded, its lines go with it
}
}
Order A-17: 2 lines, total 4097.0
Typical signs of composition: the whole creates the parts itself, the part type is often private or nested, and parts are never handed out for reuse.
4. Plain Association
The weakest relationship: objects interact, often only through method parameters, without one containing the other:
public class AssociationDemo {
// Plain association: objects use each other, no ownership at all
static class Doctor {
final String name;
Doctor(String name) { this.name = name; }
void treat(Patient p) { System.out.println("Dr. " + name + " treats " + p.name); }
}
static class Patient {
final String name;
Patient(String name) { this.name = name; }
}
public static void main(String[] args) {
Doctor d = new Doctor("Mehta");
Patient p1 = new Patient("Asha"), p2 = new Patient("Ravi");
d.treat(p1);
d.treat(p2);
}
}
Dr. Mehta treats Asha Dr. Mehta treats Ravi
5. HAS-A vs IS-A
| Aspect | Inheritance (IS-A) | Aggregation / composition (HAS-A) |
|---|---|---|
| Java mechanism | extends / implements | A field referencing another object |
| Coupling | Tight: subclass depends on parent internals | Loose: uses only the part's public API |
| Flexibility | Fixed at compile time | Parts can be swapped at run time |
| Reuse | Inherits everything | Exposes only what the whole chooses |
| Example | Car extends Vehicle | Car has an Engine |
The guideline "favour composition over inheritance" applies here: if you cannot honestly say "X is a Y", use a HAS-A relationship. See Inheritance.
6. When to Use Aggregation
- The parts have meaning on their own (employees, students, products in a catalogue).
- Parts may be shared between several wholes.
- Parts are created elsewhere, for example loaded from a database or injected by a framework.
In Spring applications, a service holding references to injected repositories is aggregation: the container, not the service, owns their life cycle.
7. Summary
- Aggregation is a weak HAS-A relationship: the whole references parts that live independently.
- Composition is a strong HAS-A relationship: the whole creates and owns its parts.
- Association is the general "uses / knows" relationship.
- Prefer HAS-A over IS-A when the relationship is not a true specialisation.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is aggregation in Java?
A HAS-A relationship where one object contains references to other objects that can exist independently of it.
Q2. What is the difference between aggregation and composition?
In aggregation, parts live independently and can be shared. In composition, the whole owns its parts, and they are created and destroyed with it.
Q3. What is the difference between association and aggregation?
Association is any relationship between objects. Aggregation is a specific association with a whole-part meaning, where the whole holds the parts.
Q4. What is a HAS-A relationship?
A relationship where one class has a field referring to another class, such as a Car having an Engine. It covers aggregation and composition.
Q5. Is aggregation better than inheritance?
For HAS-A relationships, yes: it is more flexible and less coupled. Inheritance is right only for genuine IS-A relationships.
Q6. How is aggregation implemented in Java?
With a field (or collection field) that references objects created elsewhere and passed in through a constructor or method.
Q7. Give a real-life example of aggregation.
A university and its professors, a playlist and its songs, or a team and its players: the parts exist independently of the whole.
Q8. Give a real-life example of composition.
A house and its rooms, an order and its order lines, or a human and their heart: the parts have no independent life.
Q9. How are aggregation and composition shown in UML?
Aggregation uses a hollow diamond at the whole's end of the line; composition uses a filled diamond.
Q10. Is aggregation a one-way relationship?
Usually. The whole references the parts; parts may or may not reference the whole, depending on the design.
Q11. Does Java have keywords for aggregation or composition?
No. Both are design concepts expressed through fields. The difference lies in who creates and owns the referenced objects.
Q12. Can an object be part of multiple aggregates?
Yes. That is a characteristic of aggregation, like an employee belonging to several project teams.
Q13. What does garbage collection have to do with composition?
When a composite object becomes unreachable, its exclusively owned parts become unreachable too and are collected. Aggregated parts stay alive while other references exist.
Q14. Why use composition for code reuse?
You reuse another class's behaviour by delegating to it, exposing only the methods you choose and keeping the freedom to change the implementation.
Q15. Is dependency injection an example of aggregation?
Typically yes. Injected dependencies are created and managed by the container and shared, while the class only holds references to them.
Q16. What is delegation?
Forwarding a method call to a contained object, for example a Stack implementing push by calling list.add. It is how composition reuses behaviour.
Q17. Should aggregated collections be exposed directly?
No. Provide methods such as add and remove, and return unmodifiable views or copies, to keep the whole in control.
Q18. Can composition be implemented with inner classes?
Yes. Private nested classes or records are a natural way to model parts that only the whole should create.
Q19. What is the "favour composition over inheritance" principle?
A design guideline from the Gang of Four book: build classes by combining objects rather than extending classes, to reduce coupling and increase flexibility.
Q20. How do JPA relationships map to these concepts?
Associations like @ManyToMany often represent aggregation, while @OneToMany(cascade = ALL, orphanRemoval = true) models composition, where children are removed with their parent.