UML Relationships in Java
Conceptual overview (UML basics)
Association -> Aggregation -> Composition
Wikipedia : Sometimes aggregation is referred to as composition when the
distinction between ordinary composition and aggregation is unimportant.
Association: “can-call” - connection between classes, like a friendship.
Aggregation: “has-a” relationship, where one class has (but doesn’t own) instances of another class.
Composition: “composed of” relationship (Whole-Part), where one class is composed of (and owns) instances of another class.
Association (concept)
https://www.uml-diagrams.org/association.html?context=class-diagrams
- General relationship
- No specific ownership or lifecycle dependency
- One-to-one, one-to-many, or many-to-many
- Represented by a simple line connecting classes
For example, a Department class may be associated with an Employee class to represent that employees belong to different departments.
Association (one-way) + multiplicity
public class Department {
private List<Employee> employees;
public Department(List<Employee> employees) {
this.employees = employees;
}
}
@Data
public class Employee {
private String name;
private int id;
}
Association (two-way)
Code snippet (bidirectional link)
public class User {
private Email email;
public User(Email email) {
this.email = email;
}
}
public class Email {
private User recipient;
public Email(User recipient) {
this.recipient = recipient;
}
}
N-ary association
Code snippet (three participants)
public class Meeting {
private final Person host;
private final Room room;
private final CalendarDay day;
public Meeting(Person host, Room room, CalendarDay day) {
this.host = host;
this.room = room;
this.day = day;
}
}
Has-A relationship: composition vs. aggregation (concept)
Composition and Aggregation both represent a “has-a” relationship between classes, but they differ in ownership and dependency.
Aggregation (empty diamond)
- Special form of association
- “Whole-part” relationship
- Weaker ownership: The part class is less tightly bound to the whole class.
- Dependency: Parts can exist independently and be shared among multiple containing classes.
-
Example:
- A University “has-a” Department. Departments may continue to exist independently even if the University closes.
- A Car class may have wheels, where wheels are parts of the car but can exist independently.
// Contained class
public class Wheel {
// Attributes and methods of the wheel
}
// Containing class
public class Car {
private final List<Wheel> wheels; // Aggregation relationship
public Car(List<Wheel> wheels) {
this.wheels = wheels; // Assigning wheels passed as parameter
}
}
Composition (filled diamond)
- Also known as whole-part Has-a relationship
- Strong ownership: The part class is tightly bound to the whole class.
- Part class’s lifecycle is controlled by the whole class
- Indicated by a filled diamond (◆)
A Car class may have an Engine, where the Engine is a part of the Car and cannot exist independently. If the Car is destroyed, the Engine ceases to exist.
// Contained class
public class Engine {
// Attributes and methods of the engine
}
// Containing class
public class Car {
private final Engine engine; // Composition relationship
public Car() {
this.engine = new Engine(); // Creating engine instance within Car
}
}
A House class may have rooms, where rooms are parts of the house and cannot exist without the house. If the House is destroyed, Rooms cease to exist.
public class House {
private List<Room> rooms;
public House() {
this.rooms = new ArrayList<>();
}
}
Multiplicity
- Denotes the number of instances of one class related to the number of instances of another class.
- Represented with a number at one end of the line and a “*” (asterisk) at the other end.
// Example of multiplicity in a relationship
public class Department {
private final List<Employee> employees; // One-to-many relationship
public Department(List<Employee> employees) {
this.employees = employees;
}
}
Generalization - IS-A (empty arrowhead)
Generalization/Inheritance represents an “is-a” relationship, where the subclass inherits attributes and behaviors from the superclass.
- Denoted by an empty arrowhead pointing from the subclass to the superclass.
- Indicates an “is-a” relationship.
- IS-A: The property of an object being an instance of a data type.
- Subclass inherits attributes and behaviors from the superclass.
Generalization/Inheritance (implements)
- The Is-A relationship test is also known as INHERITANCE test.
- This holds true for a child that is a subclass of any parent, be it a direct subclass or a distant child.
// Parent class
public class Vehicle {
// Attributes and methods common to all vehicles
public Vehicle(String manufacturer, int year) { }
}
// Child class inheriting from Vehicle
public class Car extends Vehicle {
// Additional attributes and methods specific to cars
public Car(String manufacturer, int year, String model, int mileage) {
super(manufacturer, year);
}
}
public class Boat extends Vehicle {
public Boat(String manufacturer, int year, String type, int length) {
super(manufacturer, year);
}
Generalization/realization (extends)
- We use the multi-inheritance property of interfaces to preserve the IS-A relationship.
- For example, a Cat is an Animal, and a Cat is also a Pet.
Code snippet (interface realization)
public interface Animal {
void eat();
void sleep();
}
public interface Pet {
void play();
void cuddle();
}
public class Cat implements Animal, Pet {
public void eat() { }
public void sleep() { }
public void play() { }
public void cuddle() { }
}
Dependency (dashed line with arrow)
- Denoted by a dashed line with an arrow pointing from the dependent class to the independent class.
- Represents a using or “uses-a” relationship, where one class depends on another class for its implementation.
-
Dependencies are typically indicated by method parameters, local variables, or return types.
// Dependent class public class Car { public void drive(Engine engine) { // Dependency on Engine class // Implementation of drive method using Engine } }
Code snippet (constructor injection + usage)
private final Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void drive() {
engine.start();
}
Using « » for Annotations:
- Used to indicate properties or qualifiers of a relationship or dependency.
- Often used with dependencies to specify the nature of the relationship, such as «interface», «implementation», «association», etc.
For example, if class A implements interface B, you would write “«implements»” near the dashed line between class A and interface B.
// Dependent class implementing an interface
public class Car implements Drivable { // <<implements>> annotation
// Implementation of methods from Drivable interface
}
Elaborate end-to-end model
public class Car extends Vehicle implements Drivable {
private List<Wheel> wheels;
private Engine engine;
public Car(String manufacturer, String model, List<Wheel> wheels, Engine engine) {
super(manufacturer, model);
this.wheels = wheels;
this.engine = engine;
}
}
public class Boat extends Vehicle implements Drivable {
private Engine engine;
private Rudder rudder;
public Boat(String manufacturer, String model, int length, String type, Engine engine, Rudder rudder) {
super(manufacturer, model);
this.engine = engine;
this.rudder = rudder;
}
}
References
https://www.visual-paradigm.com/guide/uml-unified-modeling-language/uml-aggregation-vs-composition/


