Java Inheritance

Java inheritance lets one class reuse fields and methods from another class. It helps you model an is-a relationship, such as a Dog is an Animal.

The class being inherited from is often called the parent class or superclass. The class that inherits from it is called the child class or subclass.

Using extends

Use the extends keyword to create a subclass. The subclass gets access to inherited fields and methods that are not private.

class Animal {
    String name;

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

class Dog extends Animal {
    void bark() {
        System.out.println(name + " says woof.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "Buddy";

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

Output:

Buddy is eating.
Buddy says woof.

The Dog class does not define name or eat(), but it can use them because it extends Animal. The bark() method belongs only to Dog.

Parent And Child Classes

Inheritance is useful when several classes share common behavior. Put the shared fields and methods in the parent class, then put the more specific behavior in each child class.

  • A parent class can hold common data, such as name or speed.
  • A child class can add its own fields and methods.
  • A child class can also replace inherited behavior by overriding a method.

Java classes can extend only one class directly. This keeps class relationships clear and avoids conflicts from multiple parent classes.

Calling A Parent Constructor With super

When a subclass object is created, the parent part of the object must be created first. If the parent class has a constructor that needs arguments, the child constructor can call it with super(...).

class Vehicle {
    private String model;

    Vehicle(String model) {
        this.model = model;
    }

    String getModel() {
        return model;
    }

    void start() {
        System.out.println(model + " is starting.");
    }
}

class ElectricCar extends Vehicle {
    private int batteryPercent;

    ElectricCar(String model, int batteryPercent) {
        super(model);
        this.batteryPercent = batteryPercent;
    }

    @Override
    void start() {
        System.out.println(getModel() + " starts silently.");
    }

    void printBattery() {
        System.out.println("Battery: " + batteryPercent + "%");
    }
}

public class Main {
    public static void main(String[] args) {
        ElectricCar car = new ElectricCar("Leaf", 82);

        car.start();
        car.printBattery();
    }
}

Output:

Leaf starts silently.
Battery: 82%

The ElectricCar constructor calls super(model) to run the Vehicle constructor. This lets the parent class initialize its private model field.

Overriding Methods

A subclass can provide its own version of an inherited method. This is called method overriding. In the example, ElectricCar overrides start() because an electric car starts differently from a general vehicle.

The @Override annotation is optional, but it is helpful. It tells the compiler that you intend to override a method from the parent class. If the method name or parameter list is wrong, the compiler can catch the mistake.

Inheritance And private Members

A subclass does not directly access private fields from its parent class. The model field in Vehicle is private, so ElectricCar uses getModel() instead.

This works well with encapsulation: the parent class can protect its data, while the child class can still use public or package-access methods to work with that data.

Common Mistakes

  • Using inheritance for a class that is not really an is-a version of the parent class.
  • Trying to access a parent’s private fields directly from a subclass.
  • Forgetting that super(...) must be the first statement in a constructor when it is used.
  • Changing a method’s parameters by accident and creating an overload instead of an override.

Takeaway: inheritance lets a subclass reuse and specialize a parent class, while super and overriding help connect shared setup with child-specific behavior.