Inheritance is a feature of object-oriented programming that allows you to define a new class based on an existing class, enabling code reuse and promoting a hierarchical relationship among classes.
The class that extends another class is called Child class or Sub class and the class being extended is call Parent class or Super class.

When a class extends another class, it gets access to all the properties and methods of the parent class, provided they do not have private access.

In java, inheritance is considered as an IS-A relationship, since child object is of same type as its parent.

Inheritance Syntax

Inheritance in java is achieved using extends keyword.
A class can become a child class of another class by writing extends followed by the parent class name as shown below

class Child extends Parent {

}

Remember that the parent class must be visible to the child class, meaning that it should not be private Also, if the parent class has default(package level) access and the child class should be in the same package.

When a class inherits another class, its object can access all its methods and variables using dot operator, similar to how it accesses its own properties.

Calling Parent class method

To call a method of parent class or access its properties from child class, super keyword is used.
Simply write super followed by dot and the name of method or property inside child class.

Calling Parent class constructor

Though a parent class constructor is implicitly called from child class constructor.
But, you can also call it explicitly using super followed by parenthesis and appropriate arguments.
Note that super() MUST be the first line in child class constructor.

Inheritance in Java Example

Below is an example of inheritance in java, where a parent class MobilePhone is extended by SmartPhone

// Parent class
class MobilePhone {
  private String brand;
  private String model;
  private String screenSize;

  // Constructor
  public MobilePhone(String brand, String model, String size) {
    this.brand = brand;
    this.model = model;
    this.screenSize = size;
  }

  // Method to get mobile phone details
  public void getDetails() {
    System.out.println("Brand: " + brand);
    System.out.println("Model: " + model);
    System.out.println("Screen Size: " + screenSize);
  }
}

// Child class inheriting from MobilePhone
class Smartphone extends MobilePhone {
  private String operatingSystem;

  // Constructor
  public Smartphone(String brand, String model, String size, String os) {
    // Call parent class constructor using super keyword
    super(brand, model, size);
    this.operatingSystem = os;
  }

  // Method to get smartphone details
  public void getSmartphoneDetails() {
    // Call parent class method using super keyword
    super.getDetails();
    System.out.println("Operating System: " + operatingSystem);
  }
}

public class Main {
  public static void main(String[] args) {
    // Create an instance of Smartphone class
    Smartphone myPhone = new Smartphone("Samsung", 
                                            "Galaxy S21", 
                                            "6.2 inches", 
                                            "Android");
    // Call child class method
    myPhone.getSmartphoneDetails();
  }
}

Below is the output

Brand: Samsung
Model: Galaxy 21
Screen Size: 6.2 inches
Operating System: Android

  • In this example, MobilePhone is the parent class with fields brand, model, and screenSize, and a method getDetails() to print the mobile phone details.
  • Smartphone is the child class that inherits from MobilePhone and adds its own field operatingSystem.
  • The constructor of Smartphone class initializes the operatingSystem field and calls the constructor of the parent class (MobilePhone) using the super keyword.
  • The getSmartphoneDetails() method in the Smartphone class calls the getDetails() method from the parent class using the super keyword and then prints the operatingSystem field specific to the Smartphone class.
  • In the main method, we create an instance of the Smartphone class and call its method, which in turn calls parent class method using super keyword.

Benefits of Inheritance in Java

Following are the benefits of inheritance in java:

1. Code Reusability

Child classes share methods and fields of their parent class.
This means that the same code is reusable across multiple places.

2. Ease of Maintenance

Since code is shared, a change performed in super class is reflected for all child classes and it does not needs to be done for each child individually, making maintenance easier.

3. Abstraction Support

Inheritance supports the concept of abstraction, where common characteristics and behaviors are abstracted into a superclass, while specific details are implemented in subclasses.
This allows for a higher level of abstraction and encapsulation, leading to cleaner and more maintainable code.

4. Polymorphism

Inheritance enables polymorphic behavior, where objects of different subclasses can be assigned to a super class reference.
This allows for more flexible and extensible code, as new subclasses can be added without modifying existing code that uses the superclass interface(reference).

Method Overriding in Child Classes

A child class gets access to parent class methods implicitly. But, there are situations when child class needs its own specific implementation.

For example,

Consider a parent class Account with a method withdraw() that deducts a specified amount from the account balance.
In the parent class, the withdraw() method may have a default implementation that performs the deduction based on certain rules, such as checking for available balance and deducting the amount accordingly.

Now, let’s say there are different types of accounts, such as SavingsAccount and CheckingAccount, which are subclasses of Account.
Each type of account may have its own rules and restrictions for withdrawals.
For example, a SavingsAccount may have a limit on the number of withdrawals allowed per month, while a CheckingAccount may not have such restrictions.

In such scenarios, child classes can implement a method of parent class in their own specific way, which is also called Method Overriding in java.

So, the child classes (SavingsAccount and CheckingAccount) would need to override the withdraw() method to implement their specific withdrawal rules.
The SavingsAccount class may override the withdraw() method to check if the withdrawal exceeds the monthly limit, while the CheckingAccount class may simply deduct the amount without any additional checks.

Types of Inheritance in Java

In Java, there are different types of inheritance that can be implemented, each serving a specific purpose.
It is crucial to understand these variations to effectively leverage the power of inheritance in object-oriented programming.
Let’s explore into the various types of inheritance in Java:

1. Single Inheritance

In single inheritance, a class inherits from only one superclass. This means that a subclass can have only one direct parent class. Example,

public class Parent {
    // Parent class code here
}

public class Child extends Parent {
    // Child class code here
}

By utilizing single inheritance, classes can achieve a clear and structured hierarchy, enhancing code readability and maintainability.

2. Multilevel Inheritance

For multilevel inheritance, a subclass is derived from another subclass, creating a hierarchical structure.
That is, a child class has a parent, which is the child of another parent and so on. Example,

public class Grandparent {
    // Grandparent class code here
}

public class Parent extends Grandparent {
    // Parent class code here
}

public class Child extends Parent {
    // Child class code here
}

This type of inheritance allows for the extension of classes through multiple levels, enabling greater flexibility in code design and implementation.


To achieve multilevel inheritance in Java, classes are structured in a cascading manner, with each subsequent subclass inheriting properties and behaviors from its immediate parent class.
This cascading effect allows for the creation of complex class hierarchies, enhancing code reusability and modularity.

3. Hierarchial Inheritance

Hierarchial inheritance is when two or more classes extend the same class.
Simplest real life example is real brothers and sisters. They have same father or parent class.

Example,

class Television {
  void display(){
  }
}

class Led extends Television {
  void display() {

  }
}

class Plasma extends Television {
  void display() {

  }
}

4. Multiple Inheritance

Multiple inheritance is when a class extends more than one class or has more than one parents.
This type of inheritance is not supported in java using classes and we will understand the reason in coming sections.

5. Hybrid Inheritance

Hybrid inheritance is a combination of multiple types of inheritance within a single class hierarchy.
It typically involves the use of both single inheritance (where a class inherits from only one superclass) and multiple inheritance (where a class inherits from more than one superclass) in the same hierarchy.

In a hybrid inheritance scenario, classes can inherit properties and behaviors from multiple super classes, leading to complex class relationships.
This can introduce challenges such as ambiguity in method resolution and the diamond problem (where the same method is inherited from multiple super classes).

Why Multiple Inheritance is not supported

Multiple inheritance is not supported in Java primarily to avoid the complexity and ambiguity that can arise from it.
There are several reasons why Java does not allow multiple inheritance:

1. Diamond Problem

If a class inherits from two or more classes that have a common superclass. This can result in ambiguity when resolving method calls or accessing shared members, as the compiler may not know which superclass implementation to use.
This is called Diamond Problem.

2. Complexity

Multiple inheritance introduces additional complexity to the language and runtime environment, as it requires more sophisticated mechanisms for method resolution, memory layout, and object initialization.

3. Namespace Pollution

Multiple inheritance can lead to namespace pollution, where subclasses inherit conflicting or redundant members from multiple super classes.
This can make the codebase harder to understand and maintain, as it may introduce unnecessary complexity and dependencies.

Multiple Inheritance Using Interface

Multiple Inheritance is when a class extends more than one classes. This is NOT allowed in java using classes.
But, you can achieve multiple inheritance using interfaces. That is, a class is allowed to implement more than one interfaces.
This way it can implement methods of two different interfaces.
A class can implement more than one interfaces separated by a comma.
Example of multiple inheritance in java using interfaces is given below

interface A {
  void methodA();
}

interface B {
  void methodB();
}

public class Multiple implements A, B {
  void methodA() {
    System.out.println("Interface A");
  }

  void methodB() {
    System.out.println("Interface B");
  }
}

Remember that if the interfaces implemented by a class have a default method with same name, then it will be a compiler error.

Duplicate default methods named go() with parameters are inherited from types B and A

where go() is a default method defined in both interfaces.

Inheritance vs Composition

Composition is a design principle in which a class contains one or more instances of other classes (objects) as member variables.
Rather than inheriting behavior, a class delegates responsibilities to its component objects. Example,

public interface Engine {
    void start();
}

public class Vehicle {
    private Engine engine;
    
    public void startEngine() {
        engine.start();
    }
}

In this example, Vehicle class is contains reference to an Engine object, which is responsible for implementation of start() method.

Below are some important differences between Inheritance and Composition in java

1. Relationship

Inheritance establishes an “is-a” relationship between classes, while composition establishes a “has-a” relationship.

2. Flexibility

Composition is more flexible than inheritance because it allows classes to change behavior dynamically by swapping out components.
Inheritance, on the other hand, creates a tight coupling between subclasses and super classes, making it less flexible.

3. Code Reuse

Inheritance promotes code reuse by inheriting properties and behaviors from a superclass.
Composition promotes code reuse by reusing components in multiple classes.

4. Complexity

Inheritance can lead to deep class hierarchies, making the codebase complex and harder to maintain.
Composition, when used appropriately, can simplify the codebase by breaking it down into smaller, more manageable components.

5. Overriding vs Delegation

Inheritance allows subclasses to override superclass methods to customize behavior.
Composition delegates responsibilities to component objects, which can be swapped out or modified independently.

Conclusion

In conclusion, inheritance in Java is a powerful mechanism that allows for code reuse, flexibility, and abstraction.
From single to hierarchical and interface-based inheritance, Java provides various ways to structure and organize code effectively.
While multiple inheritance is not supported due to complexity and ambiguity concerns, interfaces offer a versatile alternative for achieving similar functionality.
By understanding and leveraging inheritance effectively, Java developers can create more modular, maintainable, and extensible software solutions.