Skip to content
Java inheritance 7 min read

Inheritance

Inheritance lets one class acquire the fields and methods of another, so you can build on existing code instead of rewriting it from scratch. It is one of the four pillars of object-oriented programming and the feature that makes deep, expressive class hierarchies possible in Java.

What Is Inheritance?

When class B inherits from class A, B automatically gets every non-private field and method defined in A. You describe this relationship with the extends keyword.

  • A is called the superclass (also: parent class, base class).
  • B is called the subclass (also: child class, derived class).

The relationship is often described as IS-A: a Dog IS-A Animal, a SavingsAccount IS-A BankAccount.

// Superclass
class Animal {
    String name;

    void eat() {
        System.out.println(name + " is eating.");
    }
}

// Subclass — inherits eat() from Animal
class Dog extends Animal {

    void bark() {
        System.out.println(name + " says: Woof!");
    }
}

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

Output:

Rex is eating.
Rex says: Woof!

Note: Java supports single inheritance for classes — a class can extend exactly one superclass. Multiple inheritance of classes is not allowed (it causes the “Diamond Problem”). You can, however, implement multiple interfaces.

The extends Keyword

extends is the only keyword you need to establish inheritance in Java:

class Subclass extends Superclass { }

If you don’t write extends, your class implicitly extends java.lang.Object — the root of every Java class hierarchy. See the Object Class page for what that gives you for free (toString(), equals(), hashCode(), and more).

What Gets Inherited?

MemberInherited?
public fields & methodsYes
protected fields & methodsYes
Package-private (default) membersYes, if same package
private fields & methodsNo
ConstructorsNo — but callable via super()
static membersInherited (hidden, not overridden)

Tip: Even though private members are not directly accessible in the subclass, they still exist inside the inherited object. The subclass can reach them indirectly through public/protected getter and setter methods.

Calling the Superclass — super

The super keyword gives you explicit access to the parent class from within the subclass.

Accessing a superclass method

class Vehicle {
    void describe() {
        System.out.println("I am a vehicle.");
    }
}

class Car extends Vehicle {
    @Override
    void describe() {
        super.describe();                    // calls Vehicle.describe()
        System.out.println("I am a Car.");
    }
}

Output:

I am a vehicle.
I am a Car.

Calling a superclass constructor

class Person {
    String name;

    Person(String name) {
        this.name = name;
    }
}

class Employee extends Person {
    int id;

    Employee(String name, int id) {
        super(name);   // must be the first statement
        this.id = id;
    }

    void display() {
        System.out.println("ID: " + id + ", Name: " + name);
    }
}

public class Main {
    public static void main(String[] args) {
        Employee e = new Employee("Alice", 101);
        e.display();
    }
}

Output:

ID: 101, Name: Alice

Warning: If a superclass defines a constructor with parameters and no no-arg constructor, you must call super(...) explicitly as the first line of every subclass constructor, or the code won’t compile.

Method Overriding

A subclass can provide its own implementation of an inherited method — this is called method overriding and is the foundation of runtime polymorphism.

class Shape {
    double area() {
        return 0;
    }
}

class Circle extends Shape {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * radius * radius;
    }
}

public class Main {
    public static void main(String[] args) {
        Shape s = new Circle(5);  // polymorphic reference
        System.out.printf("Area: %.2f%n", s.area());
    }
}

Output:

Area: 78.54

The @Override annotation is optional but strongly recommended — it makes your intent explicit and lets the compiler catch typos in method signatures.

Multilevel Inheritance

Java allows a chain of inheritance: A → B → C. Each subclass inherits from its immediate parent, which itself may have inherited from its own parent.

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

class Mammal extends Animal {
    void feedMilk() { System.out.println("Feeding milk..."); }
}

class Cat extends Mammal {
    void meow() { System.out.println("Meow!"); }
}

public class Main {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.breathe();    // from Animal
        c.feedMilk();   // from Mammal
        c.meow();       // from Cat
    }
}

Output:

Breathing...
Feeding milk...
Meow!

There is no practical depth limit, but very deep hierarchies are hard to read and maintain. Favour shallow hierarchies combined with interfaces when possible.

The final Keyword and Inheritance

You can restrict inheritance in two ways using the final keyword:

  • final class — the class cannot be extended at all (e.g., String is final).
  • final method — the method cannot be overridden in any subclass.
final class Utility {
    static int square(int n) { return n * n; }
}

// Compilation error — cannot extend a final class
// class MyUtil extends Utility { }

Under the Hood

Object layout and vtable dispatch

When the JVM loads a class, it builds a vtable (virtual method table) — an array of method pointers for every overridable method the class exposes. Each subclass gets its own vtable that copies the parent’s entries and replaces entries for overridden methods.

When you call a virtual method through a reference (e.g., shape.area()), the JVM uses the actual runtime type of the object to look up the correct vtable entry. This is called dynamic dispatch and is what makes polymorphism work. See vtable & Dynamic Dispatch for the full picture.

Memory layout

A subclass object contains the fields of every class in its hierarchy, laid out contiguously on the heap. The JVM prepends an object header (mark word + class pointer, typically 16 bytes) before the field data. Because of this, even an empty subclass is slightly larger than its superclass — the extra space comes from the header, not new fields.

Bytecode: invokespecial vs invokevirtual

The Java compiler generates different bytecode instructions depending on how a method is called:

Call typeBytecode instruction
super.method()invokespecial (resolved at compile time)
Normal virtual callinvokevirtual (resolved at runtime)
Static methodinvokestatic
Interface methodinvokeinterface

invokespecial is used for superclass calls and constructors because the target is known statically — there is no need for vtable lookup. invokevirtual performs the runtime vtable dispatch described above.

The JIT compiler further optimises hot call sites with inline caching and, when the type is monomorphic (only one concrete class seen at that call site), can devirtualise the call entirely — turning the dispatch into a direct call with zero overhead. Read more in JIT Compilation & Bytecode.

Inheritance vs Composition

A common question is: should I extend this class, or hold a reference to it?

Inheritance (IS-A)Composition (HAS-A)
RelationshipSubtype of parentContains an instance
CouplingTight — breaks if superclass changesLoose — easy to swap
FlexibilityFixed at compile timeCan swap at runtime
Best forTrue IS-A relationshipsEverything else

Composition (HAS-A) is covered in depth on the Aggregation page. The classic advice is “favour composition over inheritance” — reach for extends when you genuinely have a subtype relationship, not just because you want to reuse a few methods.

In This Section

  • Types of Inheritance — a guided tour of single, multilevel, hierarchical, and hybrid inheritance with diagrams and code examples for each.
  • Aggregation (HAS-A) — when one object owns or uses another; the composition alternative to inheritance.
  • Polymorphism — inheritance is the mechanism that makes polymorphism possible; see how it all fits together.
  • Method Overriding — the full rules for correctly overriding a superclass method, including covariant return types and checked exceptions.
  • super Keyword — all the ways super lets you reach back to the parent class from a subclass.
  • Abstract Class — how to define a partially-implemented superclass that forces subclasses to fill in the blanks.
  • Interface — achieve multiple-inheritance-style flexibility without the diamond problem.
  • final Keyword — lock down classes and methods to prevent unwanted extension or overriding.
Last updated June 13, 2026
Was this helpful?