Inheritance Java Program: Complete Guide with Examples (2026)

Published: 2021-11-23
13 min read
Share:

Inheritance is one of the four fundamental Object-Oriented Programming (OOP) principles in Java. It allows a class to acquire the fields and methods of another class, promoting code reuse, maintainability, and extensibility.

In this guide, you'll learn:

  • What inheritance is and why it matters
  • The different types of inheritance in Java
  • Single inheritance with a complete Java program
  • Multilevel inheritance with a working example
  • How the extends keyword works
  • Best practices for writing maintainable inheritance hierarchies

All examples are compatible with modern Java versions, including Java 17 and Java 21 LTS, and follow practices that remain relevant in 2026.


Executive Overview

Inheritance represents an "is-a" relationship between classes. Instead of writing duplicate code across multiple classes, developers define common functionality in a parent class and allow child classes to inherit and extend that functionality.

For example:

  • A Dog is an Animal.
  • A Car is a Vehicle.
  • A SavingsAccount is a BankAccount.

Each child class automatically gains access to accessible members of its parent class while adding its own specialized behavior.

Inheritance offers several advantages:

  • Reduces duplicate code
  • Improves maintainability
  • Encourages code reuse
  • Supports runtime polymorphism
  • Makes applications easier to extend

However, inheritance should be used only when a genuine "is-a" relationship exists. Modern Java development encourages developers to prefer composition when inheritance becomes deep or tightly coupled.

Java supports inheritance through the extends keyword for classes and implements for interfaces. Unlike some programming languages, Java intentionally does not allow multiple inheritance of classes to avoid ambiguity, though a class can implement multiple interfaces.

Understanding inheritance is essential because it appears frequently in Java interviews, enterprise applications, frameworks like Spring, Android development, and backend systems.


Prerequisites

Before working through these programs, you should be comfortable with:

  • Basic Java syntax
  • Classes and objects
  • Methods
  • Constructors
  • Access modifiers (public, protected, private)
  • Compiling and running Java programs
  • Java Development Kit (JDK 17 or newer)

A basic understanding of Object-Oriented Programming concepts such as encapsulation and polymorphism will also be helpful.


What Is Inheritance in Java?

Inheritance is the mechanism by which one class acquires the properties and behavior of another class.

The existing class is called the:

  • Parent class
  • Superclass
  • Base class

The new class is called the:

  • Child class
  • Subclass
  • Derived class

The child class inherits accessible methods and fields from the parent class and can also define additional members of its own.

General syntax:

class Parent {
    // fields and methods
}

class Child extends Parent {
    // additional fields and methods
}

The extends keyword establishes the inheritance relationship.

For example:

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

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

Here:

  • Dog inherits the eat() method.
  • Dog adds its own bark() method.
  • A Dog object can call both methods without duplicating code.

This reuse of behavior is the primary purpose of inheritance.


Types of Inheritance in Java

Java supports several inheritance models.

Single Inheritance

A child class inherits from exactly one parent class.

Animal
   │
   ▼
 Dog

This is the simplest and most commonly used inheritance model.


Multilevel Inheritance

A class inherits from another child class, forming a chain.

Animal
   │
   ▼
 Dog
   │
   ▼
 Puppy

Each level inherits the behavior of every class above it.


Hierarchical Inheritance

Multiple child classes inherit from the same parent.

        Animal
       /      \
     Dog      Cat

This is commonly used when several classes share common functionality.


Multiple Inheritance (via Interfaces)

Java does not support multiple inheritance of classes because it can lead to ambiguity, commonly known as the Diamond Problem.

Instead, Java allows a class to implement multiple interfaces safely.

This topic is covered later in this guide.


Single Inheritance

Single inheritance allows one child class to inherit the methods and fields of one parent class.

This is the foundation of inheritance in Java and is widely used across enterprise applications.

Example Program

class Animal {

    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Barking...");
    }
}

public class SingleInheritance {

    public static void main(String[] args) {

        Dog dog = new Dog();

        dog.bark();
        dog.eat();
    }
}

Output

Barking...
Eating...

Explanation

The program contains two classes.

The Animal class provides the common behavior:

void eat()

The Dog class extends Animal:

class Dog extends Animal

Since Dog inherits from Animal, every Dog object automatically has access to the eat() method.

When the program executes:

Dog dog = new Dog();

the object can call:

dog.bark();

because it belongs to Dog.

It can also call:

dog.eat();

because the method is inherited from Animal.

No duplicate implementation of eat() is required inside the Dog class.

This demonstrates one of the biggest advantages of inheritance—code reuse.

Instead of rewriting shared functionality in every class, common behavior is centralized in the parent class.


When to Use Single Inheritance

Single inheritance is ideal when:

  • Multiple objects share common behavior.
  • The child naturally extends the parent.
  • Code duplication needs to be minimized.
  • The hierarchy is simple and easy to maintain.

Examples include:

  • Employee → Manager
  • Vehicle → Car
  • Account → SavingsAccount
  • Shape → Circle

Multilevel Inheritance

Multilevel inheritance occurs when a child class itself becomes the parent of another class.

Each level inherits the accessible members of every class above it.

This creates a chain of inheritance.

Example Program

class Animal {

    void eat() {
        System.out.println("Eating...");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Barking...");
    }
}

class Puppy extends Dog {

    void weep() {
        System.out.println("Weeping...");
    }
}

public class MultilevelInheritance {

    public static void main(String[] args) {

        Puppy puppy = new Puppy();

        puppy.weep();
        puppy.bark();
        puppy.eat();
    }
}

Output

Weeping...
Barking...
Eating...

Explanation

The inheritance chain is:

Animal
   │
   ▼
 Dog
   │
   ▼
Puppy

The Animal class defines:

eat()

The Dog class inherits eat() and introduces:

bark()

Finally, the Puppy class inherits both methods and defines:

weep()

As a result, the Puppy object can invoke all three methods:

  • weep() from Puppy
  • bark() from Dog
  • eat() from Animal

This illustrates how inheritance accumulates functionality through each level of the hierarchy.


Advantages of Multilevel Inheritance

Multilevel inheritance is useful when functionality becomes progressively more specialized.

Its benefits include:

  • Better organization of related classes
  • Reduced code duplication
  • Easier maintenance
  • Incremental extension of functionality
  • Improved readability for well-designed hierarchies

However, avoid creating excessively deep inheritance chains. Modern Java design generally recommends keeping hierarchies shallow because deep inheritance can make applications more difficult to understand, debug, and modify. When classes become too tightly coupled, composition is often a better design choice.

Multiple Inheritance Using Interfaces

Unlike C++, Java does not allow a class to inherit from multiple classes. However, Java does allow a class to implement multiple interfaces, enabling a form of multiple inheritance without the ambiguity associated with multiple parent classes.

Interfaces define contracts that implementing classes must fulfill. Since Java 8, interfaces can also include default and static methods, making them even more powerful while preserving backward compatibility.

Example Program

interface Vehicle {

    void vehicleType();
}

interface Color {

    void colorType();
}

class Car implements Vehicle, Color {

    @Override
    public void vehicleType() {
        System.out.println("Four-wheeler");
    }

    @Override
    public void colorType() {
        System.out.println("Red");
    }
}

public class MultipleInheritance {

    public static void main(String[] args) {

        Car car = new Car();

        car.vehicleType();
        car.colorType();
    }
}

Output

Four-wheeler
Red

Explanation

In this example:

  • Vehicle defines the vehicleType() contract.
  • Color defines the colorType() contract.
  • Car implements both interfaces.

The class therefore gains two independent capabilities without inheriting implementation from multiple parent classes.

This approach is flexible because multiple interfaces can be combined as application requirements evolve.


Why Java Doesn't Support Multiple Class Inheritance

A common interview question is:

Why can't one Java class extend multiple classes?

The answer lies in avoiding ambiguity.

Consider the following hypothetical example:

class A {

    void display() {
        System.out.println("A");
    }
}

class B {

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

// Not allowed in Java
class C extends A, B {
}

If C called:

display();

Which implementation should execute?

  • A.display()
  • B.display()

This ambiguity is known as the Diamond Problem.

Rather than introducing complex conflict-resolution rules, Java avoids the problem entirely by allowing a class to extend only one superclass.

Interfaces solve this safely because they primarily define behavior contracts rather than shared implementation. If two interfaces contain identical default methods, Java requires the implementing class to explicitly override the conflicting method.

This design keeps inheritance predictable, readable, and easier to maintain.


extends vs implements

Both keywords establish relationships between types, but they serve different purposes.

Use extends when:

  • Creating a child class from a parent class
  • Reusing implementation
  • Modeling an "is-a" relationship
  • Inheriting fields and methods

Example:

class Animal {
}

class Dog extends Animal {
}

Use implements when:

  • Implementing one or more interfaces
  • Defining capabilities or contracts
  • Allowing different classes to share behavior without sharing implementation

Example:

interface Printable {

    void print();
}

class Report implements Printable {

    @Override
    public void print() {
        System.out.println("Printing report");
    }
}

As a design guideline:

  • Use inheritance for closely related classes.
  • Use interfaces for shared capabilities across unrelated classes.

Modern Java frameworks rely heavily on interfaces because they encourage loose coupling and easier testing.


Method Overriding and Runtime Polymorphism

Inheritance becomes significantly more useful when combined with method overriding.

A child class can provide its own implementation of an inherited method.

Example:

class Animal {

    void sound() {
        System.out.println("Some sound");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Bark");
    }
}

Now consider:

Animal animal = new Dog();

animal.sound();

Output:

Bark

Although the reference type is Animal, Java executes the overridden method from Dog.

This behavior is called runtime polymorphism or dynamic method dispatch.

It allows applications to become more flexible because the same interface or parent type can represent many concrete implementations.

Many enterprise Java frameworks, including Spring, Jakarta EE, and numerous ORM libraries, rely heavily on runtime polymorphism.


The super Keyword

The super keyword refers to the immediate parent class.

It is commonly used for:

  • Calling superclass constructors
  • Accessing overridden methods
  • Accessing hidden parent fields

Calling a Parent Constructor

class Animal {

    Animal() {
        System.out.println("Animal created");
    }
}

class Dog extends Animal {

    Dog() {
        super();
        System.out.println("Dog created");
    }
}

Output:

Animal created
Dog created

If omitted, Java automatically inserts super() when possible.

Calling an Overridden Method

class Animal {

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

class Dog extends Animal {

    @Override
    void sound() {

        super.sound();

        System.out.println("Dog bark");
    }
}

Output:

Animal sound
Dog bark

Using super makes it possible to extend existing behavior rather than completely replacing it.


Real-World Use Cases

Inheritance is widely used across Java applications when there is a clear hierarchical relationship.

Examples include:

Banking Systems

Account
    ├── SavingsAccount
    ├── CurrentAccount
    └── FixedDepositAccount

Each account type inherits common banking operations while implementing specialized functionality.


E-Commerce Applications

Product
    ├── Book
    ├── Laptop
    └── MobilePhone

Shared attributes such as price and product ID are defined once in the parent class.


Human Resource Systems

Employee
    ├── Manager
    ├── Developer
    └── Tester

All employees share common information while maintaining role-specific behavior.


GUI Frameworks

Desktop UI toolkits often define base components such as:

Component
    ├── Button
    ├── Label
    └── TextField

Each component inherits rendering and event-handling functionality.


Game Development

Character
    ├── Warrior
    ├── Mage
    └── Archer

Movement, health, and inventory logic can reside in the base class while subclasses define unique abilities.


Common Pitfalls & Edge Cases

Although inheritance is powerful, it can be misused.

Using Inheritance Instead of Composition

Not every relationship is an "is-a" relationship.

For example, a Car has an Engine; it is not an engine.

Favor composition when objects collaborate rather than specialize.


Deep Inheritance Chains

Hierarchies with many levels become difficult to understand and maintain.

For example:

A
└── B
    └── C
        └── D
            └── E

Shallow hierarchies are generally easier to work with.


Forgetting @Override

Always annotate overridden methods.

The compiler can detect signature mismatches before runtime.

@Override
public void display() {
}

Access Modifier Confusion

Private members are not inherited directly.

Only accessible members (public, protected, and package-private within the same package) can be used by subclasses.


Incorrect Constructor Assumptions

Superclass constructors execute before subclass constructors.

Understanding constructor chaining helps avoid initialization bugs.


Confusing Overloading and Overriding

These concepts are frequently mixed up.

  • Overloading: Same method name, different parameters.
  • Overriding: Same method signature in a subclass.

They solve different design problems.


Best Practices (2026)

Modern Java development favors simplicity and maintainability over deep inheritance hierarchies.

Follow these recommendations:

  • Prefer inheritance only for genuine "is-a" relationships.
  • Keep inheritance trees shallow.
  • Favor composition when classes collaborate.
  • Use interfaces to define capabilities.
  • Always use the @Override annotation.
  • Avoid exposing unnecessary parent implementation details.
  • Design parent classes to be stable and reusable.
  • Use meaningful class names that reflect the domain model.
  • Document inheritance hierarchies in larger projects.
  • Follow the Liskov Substitution Principle so subclasses can safely replace their parent types.

When designing enterprise applications, prioritize readability and maintainability over clever inheritance structures.


Conclusion

Inheritance remains one of Java's most important object-oriented programming features because it enables code reuse, extensibility, and cleaner software design. By placing common behavior in a parent class and extending it through specialized subclasses, developers can build applications that are easier to maintain and evolve.

Java supports single, multilevel, and hierarchical inheritance through classes while intentionally preventing multiple class inheritance to eliminate ambiguity. Instead, multiple interfaces provide a flexible and safe mechanism for combining behaviors.

As you build larger Java applications, remember that inheritance is just one design tool. Use it thoughtfully, keep class hierarchies simple, and combine it with interfaces, composition, and polymorphism to create maintainable, scalable software.


Key Takeaways

  • Inheritance models an "is-a" relationship between classes.
  • The extends keyword enables class inheritance.
  • Java supports single, multilevel, and hierarchical inheritance.
  • Multiple inheritance of classes is not supported, but multiple interfaces are.
  • Method overriding enables runtime polymorphism.
  • The super keyword provides access to parent constructors and methods.
  • Use inheritance to promote code reuse, but avoid unnecessarily deep hierarchies.
  • Prefer composition when inheritance does not accurately represent the domain model.
  • Modern Java applications often combine inheritance with interfaces to achieve flexibility and maintainability.
Free Engineering ToolsNEW

8 free, 100% client-side tools for developers — no signup, no data uploads.

Explore all tools