Skip to content
Inheritance and super
step 1/7

Reading — step 1 of 7

Learn

~3 min readInheritance and Interfaces

Inheritance is one of OOP's core mechanisms. A subclass inherits fields and methods from a parent class, then adds or overrides what's different. The Oracle Java Tutorials make this chapter 5; we treat it as a Java fundamental for the same reason.

The basic shape

public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public String describe() {
        return name + " is an animal";
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);    // calls Animal's constructor
    }
    
    public String bark() {
        return name + " says woof";
    }
}

extends declares the subclass relationship. Dog automatically has name and describe() from Animal plus bark() it adds.

super — calling the parent

public class Cat extends Animal {
    public Cat(String name) {
        super(name);    // REQUIRED if parent has a parameterized constructor
    }
    
    @Override
    public String describe() {
        return super.describe() + " (specifically a cat)";
    }
}
  • super(args) in a constructor — calls the parent's constructor. Must be the first statement.
  • super.method() in any method — calls the parent's version (useful when overriding).

@Override — annotated overrides

@Override
public String describe() {
    return name + " is a special kind of animal";
}

The @Override annotation tells the compiler "I intend to override an inherited method." If the signature doesn't actually match a parent method (typo, wrong parameters), the compiler errors. Always annotate overrides — catches subtle bugs.

Polymorphism — same call, different method

Animal[] zoo = { new Dog("Rex"), new Cat("Whiskers") };
for (Animal a : zoo) {
    System.out.println(a.describe());   // calls the actual subclass version
}

Even though the array's static type is Animal[], the runtime calls each instance's actual type's describe(). This is dynamic dispatch — the engine of polymorphism.

Access modifiers and inheritance

  • public — accessible everywhere
  • protected — accessible in this class, subclasses, and same-package classes
  • private — only this class. Subclasses CANNOT access private members of their parent.
  • package-private (no modifier) — same package only

Use protected for fields/methods that subclasses need to access; private for true encapsulation.

final — preventing inheritance/override

public final class Constants { ... }      // can't be subclassed

public class Foo {
    public final int compute() { ... }    // can't be overridden
}

final says "no further customization here." Effective Java (Item 19) goes further: prohibit inheritance unless the class is explicitly designed and documented for it.

Single inheritance only

Java classes can extend exactly ONE parent. Multiple inheritance is the territory of interfaces (next lesson).

Common mistakes

  • Forgetting super(...) in a subclass constructor when the parent has no no-arg constructor — compile error.
  • Calling this() and super() together — only one allowed, and only as the first statement.
  • Not using @Override — typos in method signatures silently create new methods instead of overriding. Always annotate.
  • Deep hierarchies — Animal → Mammal → Dog → Labrador → ShowDog. Hard to maintain. Prefer composition or interfaces.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…