Advanced OOP

Class Relationships

Class Relationships in Java: IS-A, HAS-A, Association, Aggregation, Composition

Classes in a program rarely work alone. Class relationships describe how one class is connected to another. They fall into one hierarchy:

In simple words:

IS-A = "is a type of". HAS-A = "holds or uses". Aggregation and Composition are stronger forms of HAS-A.

Quick Overview

TermMeaningStrength
IS-AChild is a type of parentVery strong (fixed at compile time)
AssociationTwo classes are related and can use each otherWeakest
AggregationAssociation where the part can live without the wholeMedium
CompositionAssociation where the part dies with the wholeStrongest
text
1Association < Aggregation < Composition
2 (weakest) (strongest)

1. IS-A Relationship (Inheritance)

A child class is a type of the parent class. It is achieved with extends (classes) or implements (interfaces).

text
1Animal
2 ↑
3 Dog → Dog IS-A Animal
class Animal {
void eat() {
System.out.println("Eating...");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Barking...");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // inherited
dog.bark();
}
}
// Output:
// Eating...
// Barking...

Test: Say "B is a A". If it sounds natural, use inheritance.

2. HAS-A Relationship

A class holds a reference to another class as a field. It is the parent idea behind Association, Aggregation, and Composition.

text
1Car HAS-A Engine
2Employee HAS-A Address
class Engine {
void start() {
System.out.println("Engine started");
}
}
class Car {
private Engine engine = new Engine(); // HAS-A
void drive() {
engine.start();
System.out.println("Car is moving");
}
}

HAS-A is not a keyword. It is just an object stored as a field.

3. Association

Association is the most general relationship. Two classes know about or use each other, but neither one owns the other. Both can exist independently.

text
1Student ─────── Teacher
2 (uses / knows)
class Teacher {
String name;
Teacher(String name) {
this.name = name;
}
}
class Student {
String name;
Student(String name) {
this.name = name;
}
void learnFrom(Teacher teacher) { // just uses it, no ownership
System.out.println(name + " is learning from " + teacher.name);
}
}
public class Main {
public static void main(String[] args) {
Teacher t = new Teacher("Anita");
Student s = new Student("Ravi");
s.learnFrom(t);
}
}
// Output:
// Ravi is learning from Anita

Types of Association by Multiplicity

TypeMeaningExample
One-to-OneOne object linked to onePerson ↔ Passport
One-to-ManyOne object linked to manyTeacher → Students
Many-to-OneMany objects linked to oneEmployees → Company
Many-to-ManyMany linked to manyStudents ↔ Courses

4. Aggregation (Weak HAS-A)

Aggregation is an association where one class holds another class's object, but the held object can exist independently of the class holding it. The held object is usually created outside and passed in.

Part = the object being held. Whole = the object that holds it.

text
1Department ◇────── Teacher
2(whole) (part, lives independently)
class Teacher {
String name;
Teacher(String name) {
this.name = name;
}
}
class Department {
String title;
Teacher teacher; // created outside, passed in
Department(String title, Teacher teacher) {
this.title = title;
this.teacher = teacher;
}
}
public class Main {
public static void main(String[] args) {
Teacher t = new Teacher("Anita");
Department d = new Department("Computer Science", t);
d = null; // Department is gone...
System.out.println(t.name); // ...but Teacher still exists: Anita
}
}

5. Composition (Strong HAS-A)

Composition is the strongest form of HAS-A. The whole owns the part, and the part cannot exist without the whole. The part is usually created inside the owner.

text
1House ◆────── Room
2(whole) (part, dies with the house)
class Room {
String name;
Room(String name) {
this.name = name;
}
}
class House {
private Room bedroom;
private Room kitchen;
House() {
bedroom = new Room("Bedroom"); // created and owned inside
kitchen = new Room("Kitchen");
}
void showRooms() {
System.out.println(bedroom.name + ", " + kitchen.name);
}
}
public class Main {
public static void main(String[] args) {
House house = new House();
house.showRooms();
// When the House is gone, its Rooms go with it
}
}
// Output:
// Bedroom, Kitchen

Aggregation vs Composition

FeatureAggregationComposition
OwnershipWeakStrong
LifecyclePart lives independentlyPart dies with the whole
Object createdOutside, then passed inInside the owner
UML symbolEmpty diamond ◇Filled diamond ◆
ExampleDepartment and TeacherHouse and Room

All Relationships Together: University Example

import java.util.ArrayList;
import java.util.List;
// IS-A: Teacher and Student are types of Person
class Person {
String name;
Person(String name) {
this.name = name;
}
}
class Teacher extends Person {
Teacher(String name) {
super(name);
}
}
class Student extends Person {
Student(String name) {
super(name);
}
// Association: Student uses Teacher, no ownership
void learnFrom(Teacher teacher) {
System.out.println(name + " is learning from " + teacher.name);
}
}
// Aggregation: Department holds Teachers created outside
class Department {
private String title;
private List<Teacher> teachers = new ArrayList<>();
Department(String title) {
this.title = title;
}
String getTitle() {
return title;
}
void addTeacher(Teacher teacher) {
teachers.add(teacher);
}
void show() {
System.out.println(" Department: " + title);
for (Teacher t : teachers) {
System.out.println(" Teacher: " + t.name);
}
}
}
// Composition: University creates and owns its Departments
class University {
private String name;
private List<Department> departments = new ArrayList<>();
University(String name) {
this.name = name;
departments.add(new Department("Computer Science")); // created inside
departments.add(new Department("Mathematics"));
}
Department getDepartment(String title) {
for (Department d : departments) {
if (d.getTitle().equals(title)) {
return d;
}
}
return null;
}
void showInfo() {
System.out.println("University: " + name);
for (Department d : departments) {
d.show();
}
}
}
public class Main {
public static void main(String[] args) {
Teacher anita = new Teacher("Anita"); // exists independently
Student ravi = new Student("Ravi");
University uni = new University("Global Tech");
uni.getDepartment("Computer Science").addTeacher(anita);
ravi.learnFrom(anita);
uni.showInfo();
}
}
// Output:
// Ravi is learning from Anita
// University: Global Tech
// Department: Computer Science
// Teacher: Anita
// Department: Mathematics
RelationshipWhere it appears in the example
IS-ATeacher and Student extend Person
AssociationStudent uses Teacher in learnFrom()
AggregationDepartment holds Teacher objects created outside
CompositionUniversity creates and owns its Departments

How to Decide

text
1Is B a type of A? → IS-A (Inheritance)
2Does A just use or know B? → Association
3Does A hold B, but B can exist alone? → Aggregation
4Does A own B, and B dies with A? → Composition

IS-A vs HAS-A

FeatureIS-AHAS-A
MeaningChild is a type of parentClass contains another object
Achieved withextends / implementsObject as a field
CouplingTightLoose
FlexibilityFixed at compile timeCan change at runtime
ExampleDog IS-A AnimalCar HAS-A Engine

Design Tip

"Favor composition over inheritance." Use inheritance only for a true IS-A relationship. For code reuse without IS-A, hold an object and delegate to it.

Interview Definitions

TermDefinition
IS-AA relationship where a child class is a specialized type of a parent class, achieved by inheritance.
HAS-AA relationship where a class contains a reference to another class as a field.
AssociationA general relationship in which two classes are connected and can use each other.
AggregationA weak HAS-A association where the contained object can exist independently of the container.
CompositionA strong HAS-A association where the contained object cannot exist without the container.

Remember

IS-A = Inheritance. HAS-A = Association. Aggregation = HAS-A without ownership of lifecycle. Composition = HAS-A with full ownership.

Next TopicInterface vs Abstract Class