Historical Context & Motivation
Imagine you are building a video game with dozens of character types — warriors, mages, archers, and healers. Each character has a name, health points, and a method to take damage. Without some way to share that common code, you would copy and paste the same fields and methods into every single class. That is tedious, error-prone, and a nightmare to maintain. Inheritance was invented to solve exactly this problem: it lets one class automatically receive the fields and methods of another, so you only write the shared code once.
The idea of inheritance did not appear overnight. It grew out of decades of research into how programmers can organize and reuse code more effectively. The timeline below highlights the key milestones that led to Java's inheritance model and the super keyword.
The central question inheritance answers is: How can we write shared behavior once and let many classes reuse and customize it? Java's answer involves the extends keyword to establish a parent-child relationship and the super keyword to reach back into the parent class when needed.
Core Principles & Definitions
Before diving into code, let's nail down the key vocabulary. Understanding these terms clearly will make everything else in the lesson click.
Superclass (Parent Class)
class Dog extends Animal, the superclass is Animal.Subclass (Child Class)
Dog is the subclass.extends Keyword
super Keyword
super() to call a superclass constructor and super.methodName() to call a superclass method from the subclass.Method Overriding
super to call back to the original steps whenever you want the classic flavor.One important rule to remember: the super() call inside a constructor must be the very first statement. If you don't write it explicitly, Java inserts super() (the no-argument version) for you behind the scenes. This guarantees that the parent is always initialized before the child adds anything new.
Visual Explanation — The Inheritance Hierarchy
The diagram below illustrates a simple class hierarchy. An Animal superclass holds shared fields and methods. Two subclasses, Dog and Cat, extend it, inheriting everything and adding their own specialized behavior. Arrows point from child to parent to show the "extends" relationship.
Dog and Cat inherit name, age, and the speak() method from Animal. Each subclass calls super(name, age) in its constructor and overrides speak() with its own version.Notice that the subclasses do not redeclare name or age. Those fields are inherited automatically. The constructor in each subclass uses super(name, age) to pass the values up to Animal's constructor, which handles initializing them. This keeps the code DRY (Don't Repeat Yourself) — a core principle of good software design.
How super Works Under the Hood
Two Uses of super
The super keyword has exactly two uses in Java. First, super() calls a superclass constructor. You place it as the first line of a subclass constructor and pass the arguments the parent constructor expects. Second, super.methodName() calls a superclass method. This is useful when you override a method but still want to reuse the parent's version as part of your new implementation.
Constructor Chaining
When you create a new Dog object, Java does not just run the Dog constructor in isolation. Instead, it follows a chain: the Dog constructor calls super(), which runs the Animal constructor first. The Animal constructor itself implicitly calls super() on Object (Java's built-in root class). This is called constructor chaining, and it ensures that every level of the hierarchy is properly initialized from top to bottom.
super() calls going up the chain. The green arrows show each constructor finishing and returning control down to the subclass. The superclass is always initialized before the subclass.Calling super.method()
Sometimes when you override a method, you don't want to replace the parent's behavior entirely — you want to add to it. For example, suppose Animal.speak() returns "I am an animal". In Dog, you could write:
@Override
public String speak() {
return super.speak() + " and I bark!";
}Here, super.speak() calls the Animal version of the method, and the subclass adds its own piece. The result would be "I am an animal and I bark!". Without super, calling speak() inside Dog would recursively call the Dog version — which is not what you want.
Rules, Patterns, and Common Mistakes
Now that you understand the mechanics, let's catalog the specific rules Java enforces and the common mistakes beginners make. The table below is a handy reference you can come back to while coding.
| Rule | What It Means | What Happens If You Break It |
|---|---|---|
super() must be line 1 | In a subclass constructor, the call to super() must appear before any other statement. | Compiler error: "call to super must be first statement in constructor." |
| Arguments must match | The arguments in super(...) must match one of the superclass's constructor signatures. | Compiler error: "no suitable constructor found." |
Implicit super() | If you omit super(), Java auto-inserts the no-argument version. | If the superclass has no no-arg constructor, you get a compiler error. |
Can't use super in static context | super refers to an instance, so it cannot appear in a static method. | Compiler error: "non-static variable super cannot be referenced from a static context." |
| Single inheritance only | A Java class can extend only one superclass (no multiple inheritance of classes). | Compiler error. Use interfaces if you need multiple "types." |
super(args), Java tries to call super() automatically — and fails because no such constructor exists. Always either provide a no-arg constructor in the superclass or explicitly call super(args) in every subclass constructor.Worked Example — Building an Animal Hierarchy
Let's walk through a complete example step by step. We will create an Animal superclass and a Dog subclass, then trace what happens when we create a Dog object.
Animal class. It has two private fields (name and age), a constructor that initializes them, and a speak() method.public class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String speak() {
return name + " makes a sound.";
}
public String getName() { return name; }
public int getAge() { return age; }
}Dog using extends Animal. It adds a breed field and overrides speak(). Notice that the constructor calls super(name, age) as its very first line.public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // calls Animal's constructor
this.breed = breed;
}
@Override
public String speak() {
return getName() + " barks! Woof!";
}
public String getBreed() { return breed; }
}main method, we instantiate a Dog.Dog myDog = new Dog("Rex", 3, "Labrador");new Dog("Rex", 3, "Labrador") runs, Java enters the Dog constructor and immediately encounters super("Rex", 3). This triggers the Animal constructor, which sets name = "Rex" and age = 3. Control returns to the Dog constructor, which then sets breed = "Labrador".myDog object. Because Dog overrides speak(), the overridden version runs.System.out.println(myDog.speak()); // Rex barks! Woof!
System.out.println(myDog.getName()); // Rex (inherited)
System.out.println(myDog.getAge()); // 3 (inherited)
System.out.println(myDog.getBreed()); // Labrador (Dog-specific)Inheritance vs. Other Approaches
Inheritance is powerful, but it is not the only way to share code between classes. Understanding when to use inheritance versus other techniques is an important skill. The table below compares inheritance with two common alternatives.
| Approach | How It Works | Best Used When |
|---|---|---|
| Inheritance (extends) | Subclass automatically receives all non-private members of the superclass. Represents an "is-a" relationship. | The subclass truly is a specialized version of the superclass (e.g., Dog is-a Animal). |
| Composition (has-a) | A class stores a reference to another class as a field and delegates work to it. | The relationship is "has-a" (e.g., a Car has-an Engine). More flexible than inheritance. |
| Interfaces (implements) | A class promises to provide certain methods. Multiple interfaces can be implemented. | You need a common contract without shared implementation, or you need multiple types. |
Connection to Advanced OOP Concepts
Inheritance with super is foundational, but it opens the door to more powerful concepts in Java. As you grow as a programmer, you will encounter ideas that build directly on what you've learned here.
| What You Know Now | What Comes Next |
|---|---|
| Extending a concrete class | Abstract classes — a superclass that cannot be instantiated and may contain abstract methods that subclasses must implement. |
| Overriding a single method | Polymorphism — using a superclass reference to call overridden methods, letting the JVM pick the correct version at runtime. |
| Single inheritance with extends | Interfaces — a class can implement multiple interfaces, gaining a form of multiple inheritance of type (not implementation). |
| Using super to call parent methods | The protected access modifier — grants subclasses direct access to fields/methods that outsiders cannot see, offering a middle ground between public and private. |
Mastering extends and super now gives you a strong foundation. When you encounter abstract classes, polymorphism, and interfaces later, they will feel like natural extensions of what you already know — pun intended.
Practice Problems
super() call must be the first statement in a subclass constructor. What could go wrong if Java allowed other statements to come first?Circle that extends Shape and adds a radius field. Use super to call the parent constructor.
public class Shape {
private String color;
public Shape(String color) {
this.color = color;
}
public String getColor() { return color; }
}public class Vehicle {
private int speed;
public Vehicle(int speed) {
this.speed = speed;
}
}
public class Truck extends Vehicle {
private int payload;
public Truck(int speed, int payload) {
this.payload = payload;
super(speed);
}
}Person superclass with name and age fields, and a Student subclass that adds gpa. Override a toString() method so that Student.toString() uses super.toString() and appends the GPA. Write the complete code for both classes.A has a method greet() that returns "Hello". Class B extends A and overrides greet() to return "Hi". Class C extends B and overrides greet() to return super.greet() + " there". What does new C().greet() return? Could class C directly access A's version of greet() using super.super.greet()? Explain why or why not.Lesson Summary
Inheritance lets a subclass automatically receive the fields and methods of a superclass by using the extends keyword. This supports the is-a relationship — a Dog is-an Animal, a Student is-a Person. The shared code lives in the superclass, and each subclass adds its own specialized fields and methods, keeping your codebase clean and maintainable.
The super keyword is your bridge back to the parent class. Use super() in constructors (always as the first statement) to initialize the inherited fields, and use super.methodName() in overridden methods when you want to build on the parent's behavior rather than replace it entirely. Remember: Java enforces single inheritance for classes, and the constructor chain always runs from the topmost superclass down to the most specific subclass.