Inheritance — extends, super, Overriding, Constructor Chaining
2361 words
12 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Inheritance — extends, super, Overriding, Constructor Chaining ## 🎯 Learning Objectives By the end of this topic, you will be able to: - Create class hierarchies using `extends` - Use `super` to access parent constructors and methods - Override methods correctly with `@Override` - Understand constructor chaining...

Inheritance — extends, super, Overriding, Constructor Chaining
🎯 Learning Objectives
By the end of this topic, you will be able to:
- Create class hierarchies using
extends - Use
superto access parent constructors and methods - Override methods correctly with
@Override - Understand constructor chaining and initialization order
- Use
finalto prevent inheritance and overriding - Distinguish inheritance from composition
📋 Prerequisites
- Classes & Objects (week02/05-classes-objects.md): Class structure
- OOP Concepts (week01/05-oop-concepts.md): "Is-a" relationship
1. Intuition: What Problem Does Inheritance Solve?
1.1 The Problem
Imagine modeling animals in a zoo. Without inheritance:
javapublic class Dog { String name; int age; void eat() { /* ... */ } void sleep() { /* ... */ } void bark() { System.out.println("Woof!"); } } public class Cat { String name; int age; // DUPLICATE! void eat() { /* ... */ } // DUPLICATE! void sleep() { /* ... */ } // DUPLICATE! void meow() { System.out.println("Meow!"); } }
Everything is duplicated. Inheritance lets you share common code through a hierarchy:
javapublic class Animal { String name; int age; void eat() { /* ... */ } void sleep() { /* ... */ } } public class Dog extends Animal { void bark() { System.out.println("Woof!"); } } public class Cat extends Animal { void meow() { System.out.println("Meow!"); } }
1.2 Mental Model: Family Tree
javaAnimal (base class) / \ Dog Cat (derived classes) / \ Beagle Poodle (further derived)
Each child inherits everything from ancestors and can add or modify behavior. A Beagle IS-A Dog, which IS-A Animal.
2. The extends Keyword
2.1 Basic Syntax
javapublic class Parent { // fields, methods } public class Child extends Parent { // inherits Parent's public/protected members // can add new members // can override inherited methods }
2.2 What Gets Inherited?
| Member | Subclass Access |
|---|---|
public | Inherited and accessible |
protected | Inherited and accessible |
package-private (default) | Inherited only if subclass is in same package |
private | NOT inherited (exists in object but not accessible) |
static | Inherited (shared, can be hidden) |
| Constructors | NOT inherited (must be called via super) |
2.3 Single Inheritance
Java supports single inheritance for classes — a class can extend only ONE parent class:
javapublic class A extends B { } // OK public class C extends B, D { } // Compile error! No multiple inheritance
Multiple inheritance is achieved through interfaces (covered separately).
3. The super Keyword
3.1 Calling Parent Constructor
The first statement of any constructor must be a call to a parent constructor:
javapublic class Vehicle { private String brand; public Vehicle(String brand) { this.brand = brand; } } public class Car extends Vehicle { private int doors; public Car(String brand, int doors) { super(brand); // Must be first statement this.doors = doors; } }
If you don't write
super(), Java inserts an implicit super() (no-arg):javapublic class Parent { public Parent() { System.out.println("Parent created"); } } public class Child extends Parent { public Child() { // Implicit: super(); inserted by compiler System.out.println("Child created"); } } // new Child() prints: // "Parent created" // "Child created"
Error: If parent has NO no-arg constructor, you MUST explicitly call
super(args).3.2 Calling Parent Method
javapublic class Animal { public void eat() { System.out.println("Animal is eating"); } } public class Dog extends Animal { @Override public void eat() { super.eat(); // Call parent's version System.out.println("Dog is eating dog food"); } }
4. Method Overriding
4.1 Rules for Overriding
javapublic class Parent { public void display() { System.out.println("Parent"); } protected void show() { System.out.println("Parent show"); } public final void cannotOverride() { } } public class Child extends Parent { @Override public void display() { System.out.println("Child"); } // OK @Override protected void show() { System.out.println("Child show"); } // OK // @Override // public void cannotOverride() { } // Compile error! Final method }
Override rules:
- Same method signature (name + parameter types)
- Return type must be same or covariant (subtype)
- Access level must be same or wider (protected → public OK, public → protected not OK)
- Can't override
final,static, orprivatemethods
4.2 @Override Annotation
Always use
@Override — it causes a compile error if you mis-spell the method name or get the signature wrong, saving you from runtime bugs.javapublic class Parent { public void doSomething(int x) { } } public class Child extends Parent { @Override public void doSomething(int x) { } // OK — actually overrides // @Override // public void doSomething(double x) { } // Overloading, not overriding! }
4.3 Covariant Return Types
javapublic class Parent { public Parent getInstance() { return new Parent(); } } public class Child extends Parent { @Override public Child getInstance() { return new Child(); } // OK: Child is subtype of Parent }
4.4 Access Level Rules
(Diagram)
5. Constructor Chaining — Detailed Trace
javaclass Grandparent { Grandparent() { System.out.println("1: Grandparent"); } } class Parent extends Grandparent { Parent() { System.out.println("2: Parent"); } } class Child extends Parent { Child() { System.out.println("3: Child"); } } public class Test { public static void main(String[] args) { Child c = new Child(); } } // Output: // 1: Grandparent // 2: Parent // 3: Child
Chain of calls:
new Child()callsChild()Child()implicitly callssuper()→Parent()Parent()implicitly callssuper()→Grandparent()Grandparent()executes body (prints "1: Grandparent")- Returns to
Parent(), executes body (prints "2: Parent") - Returns to
Child(), executes body (prints "3: Child") This is the bottom-up then top-down execution: constructors chain up, then execute body top-down.
6. The final Keyword
6.1 Final Class (Cannot Be Extended)
javapublic final class String { } // You cannot extends String public final class Math { } // Cannot be extended
6.2 Final Method (Cannot Be Overridden)
javapublic class Parent { public final void securityCheck() { // This implementation must never change } }
6.3 Final Variable (Constant)
javapublic final int MAX_SIZE = 100; // Cannot be reassigned
7. Inheritance vs Composition
Both model "is-a" (inheritance) and "has-a" (composition) relationships:
java// Inheritance: Car IS-A Vehicle public class Car extends Vehicle { } // Composition: Car HAS-A Engine public class Car { private Engine engine; // Composition }
Prefer composition over inheritance when:
- The relationship is "has-a", not "is-a"
- You want to reuse behavior, not type identity
- The base class is not designed for extension
java// Instead of: class Stack extends ArrayList (BAD!) // Use composition: public class Stack<E> { private ArrayList<E> list = new ArrayList<>(); public void push(E item) { list.add(item); } public E pop() { return list.remove(list.size() - 1); } }
8. Java vs Python: Inheritance
| Feature | Java | Python |
|---|---|---|
| Syntax | class Child extends Parent | class Child(Parent): |
| Multiple inheritance | Classes: No. Interfaces: Yes | Yes (with MRO) |
super() | super(args) (call parent constructor) | super().__init__(args) |
@Override | Explicit annotation recommended | Not needed (duck typing) |
final class | Cannot be extended | No equivalent (convention only) |
final method | Cannot be overridden | No equivalent |
| Access control | Modifiers control inheritance | All methods are virtual |
| Abstract enforcement | Compile-time | Runtime |
9. Common Pitfalls
Pitfall 1: Overriding Instead of Overloading
javaclass Parent { void show(int x) { } } class Child extends Parent { void show(double x) { } // Overloading, not overriding! }
Why: Different parameter type. The child has BOTH methods. When called with an int, the parent's version runs. Fix: Use
@Override to catch signature mismatches.Pitfall 2: Calling Overridable Method from Constructor
javaclass Parent { Parent() { init(); } void init() { } } class Child extends Parent { String name = "Child"; @Override void init() { System.out.println(name); } } // new Child() prints "null", not "Child"!
Why: When parent constructor runs, child's
name hasn't been initialized yet. Fix: Never call overridable methods from constructors. Make such methods private or final.Pitfall 3: Forgetting super() When Parent Has No No-Arg Constructor
javaclass Parent { Parent(int x) { } } class Child extends Parent { Child() { } // Error: implicit super() doesn't exist! }
Why: Parent only has a parameterized constructor. Java can't insert
super(). Fix: Child() { super(0); }Pitfall 4: Downcasting Without instanceof Check
javaAnimal a = new Dog(); Cat c = (Cat) a; // ClassCastException at runtime
Why:
a is a Dog, not a Cat. The cast is invalid. Fix: if (a instanceof Cat) { Cat c = (Cat) a; }Pitfall 5: Using Inheritance for Code Reuse Only
javaclass Dog extends ArrayList<String> { } // BAD! Dog IS-NOT-A list
Why: Inheritance should model "is-a", not just code reuse. If Dog just needs a collection, use composition. Fix:
class Dog { private List<String> tricks; }10. Practice Questions
Q1: What is the output?javaclass Parent { Parent() { System.out.print("A "); } } class Child extends Parent { Child() { System.out.print("B "); } } class GrandChild extends Child { GrandChild() { System.out.print("C "); } } public class Test { public static void main(String[] args) { new GrandChild(); } }Answer:A B CConstructor chaining: GrandChild calls Child (via super), Child calls Parent (via super). Parent executes ("A"), returns to Child ("B"), returns to GrandChild ("C"). Q2: Does this code compile? Explain.javaclass Parent { private void secret() { } } class Child extends Parent { private void secret() { } }Answer: Yes, it compiles.secret()in Parent is private, so Child doesn't inherit it. Child'ssecret()is a completely new method, not an override. There's no@Overrideannotation, so no conflict. Q3: What is wrong with this code?javaclass Parent { Parent(int x) { } } class Child extends Parent { int y; Child(int x, int y) { this.y = y; super(x); // super() must be FIRST statement! } }Answer:super(x)must be the first statement in the constructor, butthis.y = ycomes before it. Fix: movesuper(x)to the first line. Q4: What is the output?javaclass A { void show() { System.out.println("A"); } } class B extends A { void show() { System.out.println("B"); } } class C extends B { void show() { System.out.println("C"); } } public class Test { public static void main(String[] args) { A obj = new C(); obj.show(); } }Answer:CDynamic dispatch: Reference is A, but actual object is C. JVM calls C'sshow()at runtime. Q5: Can you override a static method? Explain.Answer: No. Static methods are hidden, not overridden. The method called depends on the reference type at compile-time:javaclass Parent { static void greet() { System.out.println("Parent"); } } class Child extends Parent { static void greet() { System.out.println("Child"); } } Parent p = new Child(); p.greet(); // Prints "Parent" (compile-time binding, not dynamic dispatch)Q6: What is the difference between super and this?Answer:
this: Reference to the current object. Used to access current class members, pass current object, or call another constructor in same class (this(...)).super: Reference to the parent class. Used to access parent members hidden by overridden methods, or call parent constructor (super(...)).- Both must be the first statement if used as constructor calls. Q7: What is a covariant return type?
Answer: An overriding method can return a subtype of the original method's return type:javaclass Parent { Number getValue() { return 0; } } class Child extends Parent { @Override Integer getValue() { return 42; } // Integer IS-A Number }This is covariant return — the return type can "vary together" (co-vary) with the subclass. Q8: Why does Java not support multiple inheritance of classes?Answer: Java avoids multiple class inheritance to prevent the diamond problem:javaclass A { void foo() { } } class B extends A { void foo() { } } class C extends A { void foo() { } } class D extends B, C { } // Which foo() does D inherit?Java solves this by allowing multiple interfaces (which have no state and default methods resolve conflicts explicitly). Q9: What does thefinalkeyword do when applied to a class?Answer:final classprevents the class from being subclassed (extended). Common examples:String,Integer,Math,System. This is done for:
- Security: prevent malicious subclassing
- Immutability: prevents mutable subclasses
- Optimization: compiler can inline methods more aggressively Q10: When should you prefer composition over inheritance?
Answer: Prefer composition when:
- The relationship is "has-a" not "is-a" (e.g., Car has-a Engine)
- You only need code reuse, not polymorphic behavior
- The base class is fragile (changes break subclasses)
- You need multiple "parents" (composition allows multiple objects)
Effective Java (Item 18) recommends: "Favor composition over inheritance" because inheritance breaks encapsulation when the base class changes.
📐 Key Concepts
| Concept | Syntax | Purpose |
|---|---|---|
| Extends | class B extends A | Declare inheritance |
| Super constructor | super(args) | Call parent constructor |
| Super method | super.method() | Call overridden parent method |
| Override | @Override | Replace parent method implementation |
| Final class | final class A | Prevent subclassing |
| Final method | final void m() | Prevent overriding |
| Downcasting | (Child) parentRef | Cast to subtype (risky) |
| Upcasting | Implicit | Assign child to parent ref (safe) |
🔗 Cross-References
- Next: Polymorphism
- Related: Abstract Classes & Interfaces
- Python Comparison: BSCS1002 — Inheritance in Python Join Discord Previous2.3 Classes & ObjectsNext3.2 Polymorphism