Inheritance in Java: Learn extends, super, and Overriding with Runnable Examples

Follow one runnable Vehicle and ElectricCar program to see inherited methods, constructor order, super calls, runtime dispatch, common errors, and practice tasks.

KnowledgeGate Team

Exam prep & CS education

Updated 31 Oct 20266 min read
Inheritance in Java: Learn extends, super, and Overriding with Runnable Examples

Inheritance is often reduced to the extends keyword, but the real challenge is predicting which state is available, which constructor runs, and which method body executes. In the Vehicle and ElectricCar program, one object carries superclass and subclass state while an overridden method is selected at runtime.

What Inheritance Means in Java

A superclass represents a general idea, while a subclass represents a specialised version. ElectricCar is a Vehicle passes the useful "is-a" test, so inheritance fits. ElectricCar has a Battery is a "has-a" relationship, which normally calls for composition instead.

The basic class declaration is:

java
class ElectricCar extends Vehicle { }

Oracle's inheritance rules say that a class has one direct superclass, every class except Object ultimately descends from Object, and a subclass can reuse accessible fields and methods while adding or overriding behaviour. The language-independent model of objects, encapsulation, inheritance, and polymorphism is explained in OOP for CS teaching exams: classes, inheritance and polymorphism explained. The Vehicle and ElectricCar trace applies those ideas to Java-specific access, constructor, and dispatch rules.

Build the First Runnable Superclass and Subclass

Save this exact program as Main.java, then compile and run it.

java
class Vehicle {
    private final String model;
    private int speedKmph;

    Vehicle(String model, int speedKmph) {
        this.model = model;
        this.speedKmph = speedKmph;
    }

    public void accelerate(int increase) {
        speedKmph += increase;
    }

    public String status() {
        return model + " at " + speedKmph + " km/h";
    }
}

class ElectricCar extends Vehicle {
    private int batteryPercent;

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

    public void useBattery(int points) {
        batteryPercent -= points;
    }

    @Override
    public String status() {
        return super.status() + ", battery " + batteryPercent + "%";
    }
}

public class Main {
    public static void main(String[] args) {
        ElectricCar car = new ElectricCar("Nexon EV", 40, 82);
        car.accelerate(15);
        car.useBattery(7);

        Vehicle ref = car;
        System.out.println(ref.status());
    }
}

Trace the numbers before looking at the output. speedKmph begins at 40; accelerate(15) makes it 40 + 15 = 55. batteryPercent begins at 82; useBattery(7) makes it 82 - 7 = 75. Therefore the exact output is:

Code
Nexon EV at 55 km/h, battery 75%

If you need a sequenced path through programming fundamentals, use the Coding & DSA category after you finish tracing this program.

Java inheritance chain from ElectricCar to Vehicle to Object, beside an ElectricCar object whose inherited speed moves from 40 to 55 and battery from 82 to 75, with a Vehicle reference pointing to it.

What Is Inherited, and What super Does

car.accelerate(15) works because the public method is inherited. The representation stays controlled by Vehicle: ElectricCar cannot directly read its private speedKmph field. Following Oracle's access summary, remember this beginner-level map:

  • public members are accessible wherever the class is visible.

  • protected members are available to subclasses, subject to Java's package rules.

  • Package-private members are accessible to a subclass only when it is in the same package.

  • private members are not inherited as subclass members and cannot be accessed directly there.

The Packages and Access Modifiers in Java: Visibility Rules with Runnable Examples tutorial works through the full four-context matrix and the cross-package protected receiver rule. For this inheritance trace, the narrower question is which Vehicle members ElectricCar can reuse or access.

Constructors are not inherited. For new ElectricCar("Nexon EV", 40, 82), the subclass constructor first calls super(model, speedKmph). The Vehicle part stores "Nexon EV" and 40, then the ElectricCar part stores 82.

If the explicit super(...) call were omitted, the compiler would try super(). That would fail because this Vehicle has no accessible no-argument constructor. In this program, super(...) selects the superclass constructor, while super.status() deliberately runs the superclass version of an overridden method.

The Constructors in Java: Types, Chaining and Runnable Examples tutorial develops default, overloaded, this(), and parent-constructor chains. Here, super(...) initializes the Vehicle state that the overridden status() method later reads.

Overriding and Runtime Method Selection

@Override asks the compiler to confirm that ElectricCar.status() matches an inherited instance method. Overriding keeps the same method signature and selects the implementation at runtime. Overloading uses a different parameter list and is resolved at compile time.

Now trace Vehicle ref = car. The reference type is Vehicle, but the actual object is ElectricCar. Calling ref.status() therefore runs ElectricCar.status(). That method calls Vehicle.status() through super, gets Nexon EV at 55 km/h, then appends the battery state 75%.

Runtime dispatch applies to overridden instance methods. Fields and static methods are hidden, not dynamically overridden, so do not use the same prediction rule for them.

Six-step execution trace of the Main program, from constructing the Nexon EV ElectricCar through accelerate and useBattery to ref.status() printing Nexon EV at 55 km/h, battery 75%.

Types of Inheritance Java Supports

Java class hierarchies can take three common shapes:

  • Single: ElectricCar extends Vehicle.

  • Multilevel: SportsEV extends ElectricCar, which already extends Vehicle.

  • Hierarchical: ElectricCar and DieselCar both extend Vehicle.

Each class still has one direct superclass. This declaration is invalid and causes a compile-time error:

java
class AmphibiousCar extends Car, Boat { }

The important qualification is that a class can implement multiple interfaces:

java
class FleetEV extends ElectricCar implements Chargeable, Trackable { }

This is multiple inheritance of type. It does not create two copies of superclass state or inherit constructors from two classes.

Common Inheritance Errors and Their Fixes

Constructor failure

If Vehicle provides only Vehicle(String, int), then class ElectricCar extends Vehicle { ElectricCar() {} } fails because its implicit super() cannot resolve. Call an available constructor explicitly, such as super("Nexon EV", 40).

Access and override failures

Writing speedKmph += 15 inside ElectricCar fails because the field is private. Reuse accelerate(15) or provide a deliberate accessor. A misspelled public String stats() is a new method, not an override. Adding @Override makes the compiler expose that mistake.

Unsafe downcast

This code compiles but throws ClassCastException at runtime:

java
Vehicle plain = new Vehicle("Bus", 30);
ElectricCar ev = (ElectricCar) plain;

Guard a cast with plain instanceof ElectricCar. If a design needs repeated downcasts, reconsider whether the abstraction is doing useful work.

How Exams and Interviews Test Inheritance

Typical tasks ask you to predict output, separate compile-time and runtime errors, trace constructor calls, distinguish overriding from overloading or hiding, and judge whether a cast is safe. Oracle's official Java inheritance tutorial documents these stable fundamentals. Oracle labels that tutorial as JDK 8-era material, so use it for inheritance rules, not current-release claims.

Test the rules with these exercises:

  1. Change accelerate(15) to accelerate(25). Speed becomes 40 + 25 = 65, while battery remains 82 - 7 = 75. Answer: Nexon EV at 65 km/h, battery 75%.

  2. Replace Vehicle ref = car with Object ref = car. ref.status() does not compile because Object does not declare status(), even though the actual object is an ElectricCar.

  3. Evaluate new Vehicle("Bus", 30) instanceof ElectricCar. The answer is false because that object is a Vehicle, not an ElectricCar.

For a design exercise, create DeliveryEV extends ElectricCar with loadKg = 120, construct it as new DeliveryEV("E-Transit", 35, 76), then call accelerate(10) and useBattery(8). The values become 35 + 10 = 45 and 76 - 8 = 68. Override status() using super.status() so the result is exactly E-Transit at 45 km/h, battery 68%, load 120 kg.

Short Version and the Next Step

  • extends creates the class relationship.

  • Accessible members are inherited.

  • Constructors run in a chain but are not inherited.

  • super reaches superclass construction or behaviour.

  • Overridden instance methods dispatch by the actual object type.

Continue with Java Programming for a structured language sequence. Use Data Structures and Algorithms Using Java after classes, inheritance, and collections feel comfortable and you are ready to apply them to data structures and placement problems.

Now rerun Main, complete the three prediction exercises, and implement DeliveryEV without looking back at the answer string.