Overview: How Classes Relate
In OOP, classes don't exist in isolation. They form relationships that model real-world connections between entities. This chapter covers Association and its special cases (Aggregation, Composition), Dependency, and previews Generalization (next chapter).
💡 Memory Trick: The Big Picture
Ask yourself two questions about any two classes A and B:
② Does A have or use a B? → Association / Aggregation / Composition / Dependency
Association is the parent category — Aggregation and Composition are special cases showing different lifecycle strengths.
Then ask: who controls the lifecycle of B? That narrows it down to Aggregation vs Composition.
Use this decision tree when designing your classes:
Java Copy Constructor | Constructor Overloading
Creating duplicate objects with the same characteristics
A copy constructor is a special constructor used to create a new object as a copy of an existing object. It takes an object of the same class as a parameter and creates a duplicate.
To create cloned objects that have the same characteristics (field values) as the original object but exist at different memory locations, allowing independent manipulation.
The Department class demonstrates a basic copy constructor:
Notice the critical line in the copy constructor:
This creates a shallow copy:
Problem: Changes to the cloned employee's department will affect the original employee's department!
Solution: Let's make a small change in the copy constructor of the Employee class to use deep cloning instead.
💡 Shallow vs Deep Cloning Memory Trick
Given this shallow copy constructor:
Change the last line to create a deep clone. What should it be?
Now each Employee has its own independent Department. Changing one doesn't affect the other!
Generalization
The IS-A relationship. A subclass inherits fields and methods from its superclass using the extends keyword.
super()) or methods (super.eat()).Dog reference can be stored in an Animal variable: Animal a = new Dog(...);String is a famous example of a final class in Java.Association
The USES-A or HAS-A relationship where two classes know about each other and interact, but each has its own independent lifecycle.
| Type | Description |
|---|---|
| Unidirectional | A knows about B, but B doesn't know about A |
| Bidirectional | Both classes hold a reference to each other |
| Self-Association | A class references itself (e.g., linked list Node → Node) |
| Multiplicity | 1-to-1, 1-to-many, many-to-many (shown with UML multiplicity) |
The Teacher class has addStudent(). Can you write a removeStudent(Student s) method that removes a student from the list and also sets the student's teacher to null?
Think about it: What should happen to the bidirectional reference when a student is removed? Both sides need updating!
Aggregation
Weak HAS-A relationship. The container holds references to parts, but the parts can exist independently. The part's lifecycle is NOT controlled by the whole.
The Department-Professor example uses Aggregation (professors passed in from outside). How would you change it to Composition?
Key change: Instead of accepting professors as a parameter, create them inside the Department constructor:
Now Department owns its professors. If Department is deleted, the professors go with it.
Composition
Strong HAS-A relationship. The whole owns its parts completely. Parts are created by the whole and die with it — they cannot exist independently.
🔑 Aggregation vs Composition — The Lifecycle Test
Ask: "If I delete the container, do the parts die?"
No → Aggregation ◇
Another way: Was the part created inside the constructor? If yes — Composition. If it was passed in from outside — Aggregation.
The House has a LivingRoom and a Bedroom. Add a Kitchen with area 15 m² inside the constructor.
Think about GC: If the House is set to null, all three Room objects (Living, Bedroom, Kitchen) become eligible for garbage collection — because no external references exist.
Dependency
The weakest relationship. Class A uses Class B temporarily — through a method parameter, local variable, or return type — without holding a persistent reference.
void printOut(Printer p) — the most common formFormatter f = new Formatter(); — created and discarded locallyPrinter getPrinter() — returns an object of another classComparison Table
A side-by-side reference of all Java OOP relationships.
| Relationship | Type | Keyword | Lifecycle | UML | Strength | Real Example |
|---|---|---|---|---|---|---|
| Association | HAS-A / USES-A | Reference field | Independent | Solid line → | Loose | Teacher ↔ Student |
| Aggregation | HAS-A (weak) | Reference field (passed in) | Part survives | Solid + open diamond ◇ | Weak | Dept ◇── Professor |
| Composition | HAS-A (strong) | Field created in constructor | Part dies with whole | Solid + filled diamond ◆ | Strong | House ◆── Room |
| Dependency | USES temporarily | Method parameter / local var | Momentary | Dashed arrow - - → | Weakest | Report uses Printer |
| Generalization | IS-A | extends |
Child outlives parent | Solid + filled arrow ▷ | Tight | Dog extends Animal |
RELATIONSHIP STRENGTH SPECTRUM
💡 Decision Flowchart
Knowledge Check
Test your understanding of OOP relationships in Java. Click an answer to check it.