Association is a mechanism to define a relationship between classes of objects. Two classes are said to be associated with each other if they are related to each other in some way.
Types of Association
- Is-A
- Has-A
- Aggregation
- Composition
Important definitions for association
Subclass/child class/ derived class
A class which is derived from another class.
Super class/ parent class/ Base class
A class from which subclass is derived.
Example:
Let us take the example of the Developer and JavaDeveloper. The JavaDeveloper class is derived from the Developer class and can inherit the properties from the Developer class. Here, JavaDeveloper is a subclass and Student is a superclass.
Note: Every class in Java except the object class has a superclass (object class is a superclass of all classes).
Aggregation in Java
Aggregation is a type of HAS-A relationship. Aggregation refers to a type of relationship between two objects in which one contains the other’s reference. Two objects can exist independently. If one is deleted other can still exist. It is mainly used for code re-usability.
Aggregation in the real world:
Consider an example: A room has a chair. The Room object contains the chair object. Both room and chair exist independently.
Aggregation Example
package com.w3schools; class Chair{ public void display(){ System.out.println("Display chair details."); } } public class RoomTest { public static void main(String args[]){ //Chair class object in RoomTest class Chair obj = new Chair(); obj.display(); } }
Output
Display chair details.
Composition in Java
Like Association, Composition also represents a Has-A relationship. Composition is a design principle in object-oriented programming that allows objects of one class to be composed of objects from another class. It enables the creation of complex objects by combining simpler ones.
// Outer class class Car { private String make; private String model; // Inner Engine class class Engine { private String type; public Engine(String type) { this.type = type; } public void start() { System.out.println("Engine started."); } } // Inner Wheel class class Wheel { private int size; public Wheel(int size) { this.size = size; } public void rotate() { System.out.println("Wheel rotating."); } } // Constructor for Car class public Car(String make, String model) { this.make = make; this.model = model; } public void drive() { System.out.println("Car is moving."); } // Access Engine and Wheel from within Car public void displayCarDetails() { System.out.println("Car Details:"); System.out.println("Make: " + make); System.out.println("Model: " + model); Engine engine = new Engine("V8"); Wheel wheel = new Wheel(18); engine.start(); wheel.rotate(); } } public class Main { public static void main(String[] args) { // Create a Car object Car myCar = new Car("Toyota", "Camry"); // Access Car's inner classes and methods myCar.displayCarDetails(); // Access Car's own method myCar.drive(); } }
In this example, we have an outer class, which contains two inner classes, Engine and Wheel. The Engine class represents the car’s engine, and the Wheel class represents the car’s wheels. Each inner class has its own attributes and methods.
In the displayCarDetails method of the Car class, we create instances of the Engine and Wheel classes and demonstrate how composition works. The Car class itself has a drive method, which is an example of its own behavior.
When you run the Main class, you will see that we create a Car object and access its inner classes as well as its own methods.