Inheritance vs Composition in Java

Inheritance 

Introduction :

Inheritance is a fundamental concept in Java and other object-oriented programming languages. It allows a class to inherit the properties and behaviors of another class, thereby promoting code reuse and creating a hierarchical relationship between classes. In Java, inheritance is achieved using the extends keyword. The class that is being inherited from is called the superclass or base class, and the class inheriting from it is called the subclass or derived class.

Inheritance basic syntax:

class Superclass {
    // Fields, methods, and nested classes
}

class Subclass extends Superclass {
    // Additional fields, methods, and nested classes,
    // along with inherited members
}
Inheritance example:
// Superclass
class Animal {
    String species;
    int age;

    void makeSound() {
        System.out.println("Animal makes a sound.");
    }
}

// Subclass inheriting from Animal
class Dog extends Animal {
    String breed;

    void bark() {
        System.out.println("Woof! Woof!");
    }
}
There are four types of inheritance in java . The types are given below:
1)Single Inheritance 
2)Multiple Inheritance
3)Hierarchical Inheritance
4)Multilevel Inheritance

Single Inheritance : Java allows a class to extend only one superclass. This ensures a simple and linear class hierarchy.
Single Inheritance Example:

// Superclass
class Vehicle {
    String brand;
    String model;

    Vehicle(String brand, String model) {
        this.brand = brand;
        this.model = model;
    }

    void displayInfo() {
        System.out.println("Brand: " + brand);
        System.out.println("Model: " + model);
    }
}

// Subclass inheriting from Vehicle
class Car extends Vehicle {
    int numberOfDoors;

    Car(String brand, String model, int numberOfDoors) {
        super(brand, model);
        this.numberOfDoors = numberOfDoors;
    }

    void displayInfo() {
        super.displayInfo();
        System.out.println("Number of doors: " + numberOfDoors);
    }
}

// Subclass inheriting from Car
class ElectricCar extends Car {
    int batteryCapacity;

    ElectricCar(String brand, String model, int numberOfDoors, int batteryCapacity) {
        super(brand, model, numberOfDoors);
        this.batteryCapacity = batteryCapacity;
    }

    void displayInfo() {
        super.displayInfo();
        System.out.println("Battery Capacity: " + batteryCapacity + " kWh");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle("Generic Brand", "Generic Model");
        vehicle.displayInfo();

        System.out.println("---------------------------");

        Car car = new Car("Toyota", "Corolla", 4);
        car.displayInfo();

        System.out.println("---------------------------");

        ElectricCar electricCar = new ElectricCar("Tesla", "Model S", 4, 75);
        electricCar.displayInfo();
    }
}
Multiple Inheritance:While Java doesn't support multiple inheritance through classes, it allows a class to implement multiple interfaces. Interfaces provide a way to achieve multiple inheritance by defining abstract methods that must be implemented by the implementing class.

Multiple Inheritance Example:
interface Swimmer {
    void swim();
}

interface Flyer {
    void fly();
}

class Bird implements Swimmer, Flyer {
    // Implementation of swim() and fly() methods
}
Hierarchical Inheritance: Hierarchical inheritance in Java refers to a situation where a single base class (superclass) serves as the parent for multiple derived classes (subclasses). Each of these subclasses inherits the attributes and behaviors of the common superclass, forming a hierarchical relationship.

Hierarchical Inheritance example:
class Animal {
    // Fields and methods
}

class Cat extends Animal {
    // Additional fields and methods specific to Cat
}

class Dog extends Animal {
    // Additional fields and methods specific to Dog
}
Multilevel Inheritance : Multilevel inheritance in Java creates a sequence of inheritance, where a derived class (subclass) inherits from another derived class, and this process can continue. As a result, a hierarchical structure is formed, where each subclass inherits properties and behaviors not only from its immediate superclass but also from its ancestors in the chain of inheritance.

Multilevel Inheritance Example:

class Animal {
    // Fields and methods
}

class Mammal extends Animal {
    // Additional fields and methods specific to Mammal
}

class Dog extends Mammal {
    // Additional fields and methods specific to Dog
}
Benefits of inheritance

Code Reuse: Inheritance allows sharing common code among classes, reducing duplication.

Polymorphism: Objects of different subclasses can be treated as objects of their common superclass, enhancing flexibility.

Method Overriding: Subclasses can provide specialized implementations of inherited methods.

Modularity: Organizes classes into hierarchies for a more structured design.

Extensibility: Easily extend existing classes to add new functionalities.

Abstraction: Abstract classes and interfaces promote high-level design without implementation details.

Limitations of Inheritance

Tight coupling: Subclasses become tightly coupled to their superclass, making it challenging to change the superclass without affecting the subclasses.

Composition

Introduction:
Composition is a design principle in Java and other object-oriented programming languages that promotes building complex objects by combining simpler objects rather than inheriting from a base class. In composition, a class contains one or more objects of other classes, and the relationship between the classes is typically represented through instance variables. This approach enables greater flexibility in object composition, making it easier to create modular and maintainable code.

Composition basic syntax:
class Component {
    // Fields and methods of the component class
}

class Composite {
    private Component component;

    Composite(Component component) {
        this.component = component;
    }

    // Methods and behaviors of the composite class, working with the 'component' object
}
There are mainly two types of Composition in java:
1)Aggregation
2) Strong Composition

Aggregation : Aggregation is a type of composition in which the component class is regarded as a part of the container class but retains its independence. In simpler terms, the component class exists on its own and is not tightly bound to the lifecycle of the container class. The relationship between the container and component classes is described as a "has-a" association, where the container class contains one or more instances of the component class.

Aggregation Composition Example:
class Engine {
    // Engine class code
}

class Car {
    private Engine engine;

    Car(Engine engine) {
        this.engine = engine;
    }

    // Car class code using the 'engine' object
}
Strong Composition: Strong Composition is a more strict form of aggregation. In Strong Composition, the component class is considered an integral part of the container class, and its existence is closely tied to the container class. If the container class is destroyed, the component class is also destroyed. Composition is represented by a "whole-part" relationship, where the container class cannot exist without the component class.

Strong Composition Example:

class Address {
    // Address class code
}

class Person {
    private Address address;

    Person(Address address) {
        this.address = address;
    }

    // Person class code using the 'address' object
}
Benefits of Composition 

Flexibility: Allows for easily changing behavior by modifying composed objects.

Encapsulation: Each class maintains its own behavior, reducing dependencies.

Code Reuse: Reusable components can be assembled in different classes.

Modularity: Promotes a more modular and loosely coupled design.

Multiple Interfaces: A class can implement multiple interfaces through composition.

Clear Ownership: Components have a clear ownership, simplifying lifecycle management.

Limitations of Composition:

Code overhead: Composition may lead to more classes and delegation between them, increasing code complexity.

Java Inheritance vs Composition

Java Inheritance:

Establishes an "is-a" relationship between classes for code reuse.

Single inheritance allows extending only one superclass.

Promotes method overriding for specialized implementations in subclasses.

Java Composition:

Creates a "has-a" relationship for flexible and modular designs.

Supports multiple interfaces and better encapsulation.

Encourages code reuse through reusable components.

Next Post Previous Post