Aggregation vs Composition
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 48 of 87.
Both aggregation and composition are forms of "has-a" relationships, but they differ in one crucial aspect: ownership and lifecycle dependency.
In composition, the contained object cannot exist independently of the container. When the container is destroyed, so are its parts. Think of a House and its Room objects—rooms don't exist without the house:
class House {
private Room[] rooms;
public House(int numRooms) {
rooms = new Room[numRooms];
for (int i = 0; i < numRooms; i++) {
rooms[i] = new Room(); // House creates and owns rooms
}
}
}In aggregation, the contained object can exist independently. The container uses the object but doesn't control its lifecycle. Consider a Team and its Player objects—players exist even without a team:
class Team {
private List<Player> players;
public Team() {
players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // Team uses existing players
}
}The key distinction: in composition, the container creates its parts internally. In aggregation, objects are passed in from outside. When a Team is deleted, the Player objects still exist. When a House is deleted, its Room objects are gone too.
Challenge
EasyLet's build a university course system that demonstrates both aggregation and composition. You'll see how a Course owns its Lecture objects (composition), while it only references Professor objects that exist independently (aggregation).
You'll organize your code across four files:
Professor.java: Create a class representing a professor who can exist independently of any course. A Professor has two private fields:name(String) anddepartment(String). Include a constructor to initialize both fields and getter methods for each. OverridetoString()to return:Prof. [name] ([department])Lecture.java: Create a class representing a lecture that only makes sense within a course. A Lecture has two private fields:topic(String) anddurationMinutes(int). Include a constructor and getters. OverridetoString()to return:Lecture: [topic] ([durationMinutes] min)Course.java: This is where you'll demonstrate both relationships! A Course has three private fields:title(String),professor(Professor - aggregation), andlectures(an array of Lecture objects - composition).The constructor takes the course title, a Professor object (passed in from outside - aggregation), and the number of lectures. Inside the constructor, create the Lecture array and populate it with new Lecture objects. For each lecture at index
i, create it with topic"Topic " + (i + 1)and duration45minutes. This internal creation demonstrates composition.Add a
getInfo()method that returns a multi-line String:Course: [title] Instructor: [professor.toString()] Lectures: [number of lectures]Also add a
listLectures()method that returns a String with each lecture's toString() on its own line.Main.java: Bring everything together! You'll receive four inputs: professor name (String), professor department (String), course title (String), and number of lectures (int).First, create a Professor with the given name and department—this professor exists independently. Then create a Course, passing in the title, the professor (aggregation), and the lecture count (the course will create its own lectures internally - composition).
Print the result of
getInfo(), then print an empty line, then print the result oflistLectures().
You will receive four inputs in order: professor name, department, course title, and number of lectures.
Notice the key difference: the Professor is created outside and passed into the Course (aggregation—the professor could teach other courses or exist without this one). The Lectures are created inside the Course constructor (composition—they belong exclusively to this course and wouldn't exist without it).
Cheat sheet
Both aggregation and composition are "has-a" relationships that differ in ownership and lifecycle dependency.
Composition: The contained object cannot exist independently of the container. When the container is destroyed, its parts are destroyed too. The container creates its parts internally.
class House {
private Room[] rooms;
public House(int numRooms) {
rooms = new Room[numRooms];
for (int i = 0; i < numRooms; i++) {
rooms[i] = new Room(); // House creates and owns rooms
}
}
}Aggregation: The contained object can exist independently. The container uses the object but doesn't control its lifecycle. Objects are passed in from outside.
class Team {
private List<Player> players;
public Team() {
players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // Team uses existing players
}
}Key distinction: When a container is deleted, aggregated objects still exist, but composed objects are destroyed.
Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read inputs
String professorName = scanner.nextLine();
String department = scanner.nextLine();
String courseTitle = scanner.nextLine();
int numberOfLectures = scanner.nextInt();
// TODO: Create a Professor object (exists independently - aggregation)
// TODO: Create a Course object, passing the professor (aggregation)
// The course will create its own lectures internally (composition)
// TODO: Print getInfo() result
// TODO: Print an empty line
// TODO: Print listLectures() result
}
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System