Skip to content
Java inheritance 6 min read

Types of Inheritance

Inheritance lets one class acquire the fields and methods of another, encouraging code reuse and a natural “is-a” relationship. Java supports five conceptual types of inheritance, though it enforces one important restriction: a class can extend only one class at a time. Understanding each type helps you design cleaner, more maintainable class hierarchies.

1. Single Inheritance

The simplest form — one child class extends exactly one parent class. The child inherits everything that is accessible (non-private) from the parent.

class Animal {
    void breathe() {
        System.out.println("Breathing...");
    }
}

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

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.breathe(); // inherited from Animal
        d.bark();    // Dog's own method
    }
}

Output:

Breathing...
Woof!

Single inheritance is what you’ll use 80 % of the time. It keeps the hierarchy shallow and easy to reason about.

2. Multilevel Inheritance

A chain of inheritance — class B extends A, and class C extends B. C indirectly inherits from A through B.

class Vehicle {
    void start() {
        System.out.println("Vehicle started");
    }
}

class Car extends Vehicle {
    void drive() {
        System.out.println("Car is driving");
    }
}

class ElectricCar extends Car {
    void charge() {
        System.out.println("Charging battery...");
    }
}

public class Main {
    public static void main(String[] args) {
        ElectricCar ec = new ElectricCar();
        ec.start();  // from Vehicle
        ec.drive();  // from Car
        ec.charge(); // from ElectricCar
    }
}

Output:

Vehicle started
Car is driving
Charging battery...

Tip: Keep your chains short (2–3 levels). Deep hierarchies become hard to follow and test — a smell that composition might be a better fit.

3. Hierarchical Inheritance

One parent class is extended by multiple child classes. Each child independently inherits the parent’s members.

class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    void drawCircle() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle extends Shape {
    void drawRectangle() {
        System.out.println("Drawing a rectangle");
    }
}

public class Main {
    public static void main(String[] args) {
        Circle c = new Circle();
        c.draw();       // inherited
        c.drawCircle();

        Rectangle r = new Rectangle();
        r.draw();       // same inherited method
        r.drawRectangle();
    }
}

Output:

Drawing a shape
Drawing a circle
Drawing a shape
Drawing a rectangle

This is the classic “template + specialization” pattern. Shape defines common behavior; each subclass adds its own unique drawing logic.

4. Multiple Inheritance (via Interfaces)

Multiple inheritance means a class inherits from more than one parent. Java does not allow a class to extend multiple classes directly — this avoids the infamous Diamond Problem (see below). However, a class can implement multiple interfaces, which achieves the same goal safely.

interface Flyable {
    default void fly() {
        System.out.println("Flying...");
    }
}

interface Swimmable {
    default void swim() {
        System.out.println("Swimming...");
    }
}

class Duck implements Flyable, Swimmable {
    void quack() {
        System.out.println("Quack!");
    }
}

public class Main {
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.fly();   // from Flyable
        duck.swim();  // from Swimmable
        duck.quack(); // Duck's own
    }
}

Output:

Flying...
Swimming...
Quack!

Note: default methods in interfaces were introduced in Java 8. If two interfaces provide a default method with the same signature, the implementing class must override it to resolve the ambiguity — the compiler will refuse to compile otherwise.

The Diamond Problem

If Java allowed class C extends A, B and both A and B inherited from a common ancestor X with a method greet(), C would have two copies of greet() and the JVM wouldn’t know which to call. Java sidesteps this entirely by forbidding multi-class inheritance. Interfaces with default methods face the same conflict, but the compiler forces you to resolve it explicitly.

interface A {
    default void greet() { System.out.println("Hello from A"); }
}

interface B {
    default void greet() { System.out.println("Hello from B"); }
}

// Must override greet() or the compiler reports an error
class C implements A, B {
    @Override
    public void greet() {
        A.super.greet(); // explicitly pick A's version
        System.out.println("Hello from C");
    }
}

5. Hybrid Inheritance

Hybrid inheritance is a combination of two or more types (e.g., hierarchical + multiple). Because Java forbids multiple class inheritance, hybrid inheritance involving multiple parents is achieved through interfaces.

interface Printable {
    void print();
}

interface Saveable {
    void save();
}

class Document {
    void open() {
        System.out.println("Document opened");
    }
}

// Hierarchical (Document → PDFDocument) +
// Multiple interface (Printable + Saveable)
class PDFDocument extends Document implements Printable, Saveable {
    @Override
    public void print() {
        System.out.println("Printing PDF...");
    }

    @Override
    public void save() {
        System.out.println("Saving PDF...");
    }
}

public class Main {
    public static void main(String[] args) {
        PDFDocument pdf = new PDFDocument();
        pdf.open();
        pdf.print();
        pdf.save();
    }
}

Output:

Document opened
Printing PDF...
Saving PDF...

Quick Comparison

TypeRelationshipSupported via
SingleA → Bextends
MultilevelA → B → Cextends (chain)
HierarchicalA → B, A → Cextends (multiple children)
MultipleA + B → Cimplements (interfaces only)
HybridMix of aboveextends + implements

Under the Hood

Constructor Chaining Across the Hierarchy

Whenever you instantiate a class, the JVM calls constructors from the top of the chain down. Every constructor implicitly calls super() as its first statement unless you write one yourself. For a chain Vehicle → Car → ElectricCar, creating an ElectricCar triggers three constructors in order: Vehicle(), Car(), then ElectricCar().

class Vehicle {
    Vehicle() { System.out.println("Vehicle()"); }
}
class Car extends Vehicle {
    Car() { System.out.println("Car()"); }
}
class ElectricCar extends Car {
    ElectricCar() { System.out.println("ElectricCar()"); }
}

public class Main {
    public static void main(String[] args) {
        new ElectricCar();
    }
}

Output:

Vehicle()
Car()
ElectricCar()

This guarantees that parent state is always initialized before child state.

Method Resolution & vtable

The JVM builds a virtual method table (vtable) for every class. When a subclass overrides a method, the vtable slot for that method is updated to point to the new implementation. At runtime, a virtual invokevirtual bytecode instruction looks up the correct slot for the actual object type — this is the engine behind runtime polymorphism. See vtable & Dynamic Dispatch for a deeper dive.

Memory Layout

The JVM lays out object memory with the parent’s fields first, followed by the child’s fields. This means instanceof checks and casts are fast (they just check a type pointer in the object header), regardless of how deep the hierarchy runs.

Warning: Keep class hierarchies shallow (typically no more than 3–4 levels). Deep chains increase coupling, make refactoring painful, and can confuse both humans and JIT optimizers.

Key Rules to Remember

  • A class can extend only one class (single, multilevel, hierarchical).
  • A class can implement multiple interfaces (multiple, hybrid).
  • An interface can extend multiple interfaces — interface-to-interface inheritance has no diamond restriction.
  • Constructors are not inherited, but the parent constructor is called via super().
  • Private members are not inherited — they stay encapsulated in the declaring class.
  • Use the super keyword to explicitly call a parent method or constructor.
  • Inheritance — the core concept behind all five types covered here
  • super Keyword — call parent constructors and methods across the hierarchy
  • Interface — how Java achieves multiple and hybrid inheritance safely
  • Runtime Polymorphism — how method overriding works across an inheritance chain
  • Abstract Class — a partial implementation pattern that pairs naturally with inheritance
  • Aggregation (HAS-A) — when inheritance is not the right tool and composition wins
Last updated June 13, 2026
Was this helpful?