Java Inheritance – Harnessing Code Reuse And Hierarchy

Imagine you have a family tree. At the top, you have your grandparents, who have certain traits and characteristics. They pass down these traits to their children, who, in turn, pass them down to their own children. This process of passing down traits and characteristics from generation to generation is similar to inheritance in Java.

Inheritance in family

Let’s understand some terminologies before diving into Inheritance in Java.

Terms Used In Inheritance

  1. Class: A class is a blueprint or template in Java that describes the characteristics (data) and behaviors (methods) that instances of that class will have. It provides a framework for constructing object instances.
  1. Object: An object is a representation of a specific instance of a class. It contains the characteristics and behaviors specified by its class. Consider it a physical entity that can interact with other items in the program.
  1. Parent Class (Superclass): A parent class, also referred to as a superclass, is an existing class from which other classes inherit attributes and behaviors. It serves as a foundation or base for creating derived classes (child classes).
  1. Child Class (Subclass): A child class, also known as a subclass, is a new class that inherits properties and behaviors from its parent class. It can add additional attributes and behaviors specific to itself, while also utilizing those inherited from the parent class.
  1. extends Keyword: The “extends” keyword is used in Java to establish an inheritance relationship between classes. It is employed in the declaration of a child class, indicating that it extends (inherits from) a specific parent class.
  1. super Keyword: The “super” keyword refers to the parent class and is used to access or invoke overridden methods or constructors specified in the parent class from within the child class. It enables the easy integration of inherited functions.
  1. Reusability: Inheritance enables code reusability, which means you can reuse existing code from a parent class in a child class. This avoids redundant coding and promotes efficient development by leveraging the capabilities of existing classes.

By understanding these terminologies, you can leverage the power of inheritance in Java. It promotes code reuse, enhances modularity, and allows for the efficient creation of class hierarchies to represent real-world scenarios.

Now we are well aware of the basic terminologies we needed to understand Inheritance, let’s see what Inheritance is.

What Is Inheritance?

Inheritance is one of the 4 pillars of object-oriented programming (OOP) that allows Java classes to inherit properties from other classes. It allows you to create a class hierarchy in which a child class can inherit characteristics and methods from its parent class. This method encourages code reuse, improves class organization, and increases modularity.

To understand inheritance, you can think of it as a parent-child relationship. Similar to how children inherit certain traits from their parents, a child class inherits the properties and behaviors of its parent class. In Java, this relationship is established using the “extends” keyword. By extending a parent class, the child class gains access to its attributes and methods.

In Java, inheritance is represented by the “IS-A” relationship. In this case, we might state that a child class “IS-A” type of its parent class. It denotes a hierarchical connection in which a child class inherits the parent class’s properties and behaviors. Simply put, consider a class hierarchy with a broad class at the top, such as “Animal,” and more specialized classes below it, such as “Dog”, and  “Cat”. In this scenario, a “Dog” IS-A type of “Animal,” a “Cat” IS-A type of “Animal,” and so on.

More such examples are:

  • “Car” IS-A type of “Vehicle”.
  • “Circle” IS-A type of “Shape”.
  • “Manager” IS-A type of “Employee”.
Inheritance

In each of these examples, the child class inherits the characteristics of its parent class, establishing an IS-A relationship. This allows us to model real-world relationships and leverage code reuse, promoting a more efficient and organized development process.

Need For Inheritance In Java

  1. Reusing Code: Inheritance allows us to reuse existing code, saving time and effort.
  2. Organizing Classes: Inheritance helps organize related classes, making code easier to understand and maintain.
  3. Adding Functionality: Inheritance enables us to extend the functionality of existing classes easily.
  4. Flexible Behavior: Inheritance enables flexible behavior through polymorphism.
  5. Real-World Representation: Inheritance helps model real-world relationships and hierarchies in code.

Inheritance simplifies code reuse, improves code organization, adds functionality easily, enables flexible behavior, and helps in modeling real-world relationships.

We saw what is Inheritance and its importance and need, now let’s jump to its syntax that how to declare and achieve Inheritance in our Java code.

Syntax Of Inheritance

class ChildClass extends ParentClass {
    // Child class members and methods
}

In this syntax, the ChildClass is the class that inherits from the ParentClass. The keyword extends is used to establish the inheritance relationship between the two classes. The ChildClass can access and inherit the properties and methods defined in the ParentClass.

By extending the parent class, the child class inherits all the accessible non-private members (fields and methods) of the parent class. It can also override the inherited methods to provide its own implementation or add new methods and fields specific to the child class.

Example:

// Parent class
class Animal {
    void eat() {
        System.out.println("The animal is eating.");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("The dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat();  // Inherited from the Animal class
        myDog.bark(); // Specific to the Dog class
    }
}

Output:

The animal is eating.
The dog is barking.

The code demonstrates inheritance in Java with an example of an “Animal” class and a “Dog” class. The “Dog” class extends the “Animal” class, inheriting its behavior. The “Animal” class has an “eat” method representing generic eating behavior. The “Dog” class adds a “bark” method, which is specific to dogs.

In the code, we create a “Dog” object and call the “eat” method, inherited from the “Animal” class, to indicate that the animal is eating. We also call the “bark” method, specific to the “Dog” class, to show the dog’s barking behavior. The output will display messages indicating the animal is eating and the dog is barking.

Types Of Inheritance In Java

In Java, there are several types of inheritance that allow classes to inherit properties and behaviors from other classes. These are:

  1. Single Inheritance:

Single inheritance is the simplest form of inheritance where a class can inherit properties and behaviors from only one parent class. It’s like a child inheriting traits from a single parent. For example, a “Car” class can inherit from a “Vehicle” class to acquire common vehicle attributes.

For example,

class Vehicle {
    String type;
    int speed;

    void accelerate() {
        // Implementation to increase the speed of the vehicle
    }

    void stop() {
        // Implementation to stop the vehicle
    }
}

class Car extends Vehicle {
    String brand;
    int numberOfSeats;

    void startEngine() {
        // Implementation to start the car's engine
    }

    void honk() {
        // Implementation to make the car honk
    }
}

In the given example, 

  • we have a “Vehicle” class representing a general vehicle with data members “type” and “speed” and methods to accelerate and stop. 
  • The “Car” class inherits from “Vehicle” and adds data members “brand” and “numberOfSeats” along with methods to start the engine and honk. 
  • This allows a car object to inherit the basic properties of a vehicle (accelerate, speed, stop) and also have its own specific attributes and behaviors.
  1. Multi-level Inheritance:

A multilevel inheritance is a chain in which a class is derived from another derived class. It’s similar to having a relationship with a grandparent, a parent, and a child. For example, a “SportsCar” class, can derive from the “Car” class, which in turn derives from the “Vehicle” class. As a result, the “SportsCar” class can inherit properties from both its parent and grandparent.

For example, 

class Vehicle {
    String manufacturer;
    String color;

    void startEngine() {
        System.out.println("Engine started");
    }

    void stopEngine() {
        System.out.println("Engine stopped");
    }
}

class Car extends Vehicle {
    int numDoors;

    void accelerate() {
        System.out.println("Car is accelerating");
    }

    void brake() {
        System.out.println("Car is braking");
    }
}

class SportsCar extends Car {
    int topSpeed;

    void launchControl() {
        System.out.println("Sports car launched with control");
    }
}

public class Main {
    public static void main(String[] args) {
        SportsCar sportsCar = new SportsCar();
        sportsCar.manufacturer = "Ferrari";
        sportsCar.color = "Red";
        sportsCar.numDoors = 2;
        sportsCar.topSpeed = 300;

        sportsCar.startEngine();
        sportsCar.accelerate();
        sportsCar.launchControl();
        sportsCar.stopEngine();
    }
}

In the code, we have three classes: “Vehicle”, “Car”, and “SportsCar”. Each class inherits from the class above it, forming a multilevel inheritance hierarchy.

  • The “Vehicle” class represents a basic vehicle and has properties like “manufacturer” and “color”, as well as methods for starting and stopping the engine.
  • The “Car” class extends the “Vehicle” class and adds an additional property, “numDoors”, and methods for accelerating and braking.
  • The “SportsCar” class further extends the “Car” class and introduces a new property, “topSpeed”, and a method called “launchControl”.
  • In the main method, we create an object of the “SportsCar” class and set its properties. We can then call methods inherited from the “Vehicle”, “Car”, and “SportsCar” classes, such as starting the engine, accelerating, using launch control, and stopping the engine.
  1. Hierarchical Inheritance

When multiple classes inherit from a single parent class, this is referred to as hierarchical inheritance. It’s similar to siblings sharing shared characteristics acquired from their parents. A “Car” class and a “Motorcycle” class, for example, can both derive from a “Vehicle” class, which provides common vehicle attributes.

For example, 

class Vehicle {
    String manufacturer;
    String color;

    public void startEngine() {
        // Code for starting the engine
    }

    public void stopVehicle() {
        // Code for stopping the vehicle
    }
}

class Car extends Vehicle {
    int numDoors;
    String transmissionType;

    public void accelerate() {
        // Code for accelerating the car
    }

    public void brake() {
        // Code for braking the car
    }
}

class Motorcycle extends Vehicle {
    int numWheels;
    String handlebarType;

    public void balance() {
        // Code for balancing the motorcycle
    }

    public void changeGear() {
        // Code for changing gears in the motorcycle
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.manufacturer = "Toyota";
        myCar.color = "Red";
        myCar.numDoors = 4;
        myCar.transmissionType = "Automatic";

        Motorcycle myMotorcycle = new Motorcycle();
        myMotorcycle.manufacturer = "Honda";
        myMotorcycle.color = "Blue";
        myMotorcycle.numWheels = 2;
        myMotorcycle.handlebarType = "Sport";

        // Perform actions using the inherited and specific methods
        myCar.startEngine();
        myCar.accelerate();
        myMotorcycle.startEngine();
        myMotorcycle.balance();
    }
}

In this example, the “Car” and “Motorcycle” classes inherit the properties and methods of the “Vehicle” class, allowing us to reuse code and define specialized behaviors specific to each type of vehicle.

  1. Multiple inheritance:

Multiple inheritance is a concept in object-oriented programming where a class can inherit properties and behaviors from multiple parent classes. It allows a derived class to have characteristics from more than one base class.

However, Java does not support multiple inheritance directly. This means that a class in Java can only extend a single class. There are a few reasons why Java chose not to include multiple inheritance:

  • Ambiguity: Multiple inheritance can lead to ambiguity when two or more parent classes have methods or fields with the same name. It becomes difficult to determine which parent’s method or field should be used in the derived class.

For example, 

class Parent1 {
    public void display() {
        System.out.println("Parent1");
    }
}

class Parent2 {
    public void display() {
        System.out.println("Parent2");
    }
}

class Child extends Parent1, Parent2 {
    // Error: Multiple inheritance not allowed
    // ...
}

In this example, the child class Child tries to inherit from both Parent1 and Parent2, which have a method with the same name display(). This leads to ambiguity as it’s unclear which display() method should be used in the child class.

  • Diamond Problem: The diamond problem occurs when a class inherits from two classes that have a common base class. If both parent classes provide an implementation for the same method, it creates ambiguity for the derived class on which implementation to use.

For example, 

class Grandparent {
    public void display() {
        System.out.println("Grandparent");
    }
}

class Parent1 extends Grandparent {
    public void display() {
        System.out.println("Parent1");
    }
}

class Parent2 extends Grandparent {
    public void display() {
        System.out.println("Parent2");
    }
}

class Child extends Parent1, Parent2 { // Error: Multiple inheritance not allowed
    // ...
}

In this example, the child class Child tries to inherit from both Parent1 and Parent2, which themselves inherit from Grandparent. If Child tries to call the display() method, it’s unclear which implementation should be used, causing the diamond problem.

  • Code Complexity: Multiple inheritance can introduce complexity and make the code more challenging to understand and maintain. It can lead to intricate relationships between classes, making the code harder to debug and extend.
interface Interface1 {
    void method1();
}

interface Interface2 {
    void method2();
}

class MyClass implements Interface1, Interface2 {
    public void method1() {
        System.out.println("Implementation of method1");
    }
   
    public void method2() {
        System.out.println("Implementation of method2");
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.method1();
        obj.method2();
    }
}

In this example, multiple inheritance is simulated using interfaces. The class MyClass implements both Interface1 and Interface2, inheriting behavior from both interfaces. It provides its own implementation for each method defined in the interfaces. By using interfaces, the code remains simple and avoids the complexities associated with multiple inheritance.

To overcome the limitations of multiple inheritance, Java uses the concept of interfaces. Interfaces allow classes to inherit behavior from multiple interfaces, providing a form of multiple inheritance for abstract behaviors. By implementing interfaces, a class can define its own behavior while reusing and combining functionalities from different interfaces.

  1. Hybrid Inheritance:

Hybrid inheritance combines multiple types of inheritance. It can involve a combination of single, multilevel, hierarchical, and multiple inheritance. This allows for a more flexible and diverse inheritance structure to meet various programming needs.

For example,

class Vehicle {
    public void start() {
        System.out.println("Starting the vehicle.");
    }
}

class Car extends Vehicle {
    public void accelerate() {
        System.out.println("Accelerating the car.");
    }
}

class SportsCar extends Car {
    public void boost() {
        System.out.println("Boosting the sports car.");
    }
}

class Motorcycle extends Vehicle {
    public void wheelie() {
        System.out.println("Performing a wheelie with the motorcycle.");
    }
}

In this example, we have a base class called “Vehicle,” which represents a generic vehicle. The “Car” class extends the “Vehicle” class and adds specific behaviors related to cars. The “SportsCar” class further extends the “Car” class, adding additional functionalities specific to sports cars. On the other hand, the “Motorcycle” class directly extends the “Vehicle” class, providing unique behaviors related to motorcycles.

The hierarchy can be visualized as follows:

           Vehicle

             /   \

          Car    Motorcycle

           /

      SportsCar

With hybrid inheritance, we have a mix of single inheritance (Vehicle -> Car, Vehicle -> Motorcycle) and multiple levels of inheritance (Vehicle -> Car -> SportsCar).

Advantages Of Inheritance In Java

  • Code Reusability: Inheritance allows classes to inherit properties and behaviors from existing classes, promoting code reusability. Instead of writing similar code from scratch, we can extend an existing class and add/modify functionality as needed.
  • Method Overriding: Inheritance enables us to override methods from the parent class in the child class. This allows us to customize the behavior of inherited methods to suit the specific needs of the child class.
  • Polymorphism: Inheritance is closely tied to the concept of polymorphism. Polymorphism allows objects of different classes to be treated as objects of a common parent class. This flexibility allows for more dynamic and flexible code.
  • Modularity and Organization: Inheritance helps in organizing classes into a hierarchy based on their relationships. It provides a structured way of representing real-world or abstract relationships, making the code more organized and easier to manage.

Disadvantages Of Inheritance In Java

  • Tight Coupling: Inheritance can lead to tight coupling between classes, where changes in the parent class can have an impact on its derived classes. This can make the code more fragile and harder to maintain.
  • Inherited Limitations: When a class inherits from another class, it also inherits its limitations. This means that any flaws or design issues in the parent class can be carried over to the child class.
  • Complexity: Inheritance can introduce complexity, especially when dealing with multiple levels of inheritance or complex class hierarchies. Understanding the relationships and dependencies between classes can become challenging.
  • Overuse and Misuse: Inheritance should be used judiciously and only when it truly represents an “is-a” relationship. Overusing inheritance or using it inappropriately can lead to bloated and inflexible code.

Conclusion

  • Inheritance is a fundamental concept in Java that enables classes to inherit properties and behaviors from other classes.
  • It promotes code reusability by allowing classes to extend existing classes and add or modify functionality as needed.
  • There are five types of inheritance in Java: single inheritance, multilevel inheritance, hierarchical inheritance, hybrid inheritance, and multiple inheritance (achieved through interfaces).
  • Single inheritance involves a class inheriting from a single parent class, allowing it to acquire the attributes and methods of the parent class.
  • Multilevel inheritance occurs when a child class inherits from another child class, creating a chain of inheritance.
  • Hierarchical inheritance involves multiple child classes inheriting from a single parent class, forming a hierarchy of related classes.
  • Hybrid inheritance combines multiple and hierarchical inheritance, where a class inherits from multiple parent classes.
  • Multiple inheritance is achieved in Java through interfaces, allowing a class to implement multiple interfaces and inherit their abstract methods.
  • Inheritance enables method overriding, where methods from the parent class can be customized in the child class.
  • It facilitates polymorphism, allowing objects of different classes to be treated as objects of a common parent class.
  • Inheritance helps in organizing classes into a hierarchy, making the code more structured and manageable.
  • However, it can lead to tight coupling, inherited limitations, complexity, and misuse if not used carefully.
  • Understanding the advantages, disadvantages, and different types of inheritance helps in making informed decisions about its usage.

Overall, inheritance is a powerful mechanism that contributes to the flexibility, modularity, and extensibility of Java programs. It plays a crucial role in object-oriented programming and allows for the creation of complex and scalable software systems.

Leave a Reply

Your email address will not be published. Required fields are marked *