← Back to Course Hub
Chapter 4

Inheritance

class Child extends Parent { ... }

What is Inheritance?

Inheritance is an OOP mechanism that derives a new class from an existing one, promoting code reuse and establishing hierarchical relationships.

Learning Objectives
  • Create and interact with objects that inherit from other objects
  • Create subclasses using the extends keyword
  • Define reusable classes based on inheritance hierarchies
  • Use the protected modifier for controlled access
  • Understand constructors in inheritance chains
  • Override methods in subclasses
Key Concept: Java supports single inheritance only — a class can extend only one other class (unlike C++ which supports multiple inheritance).

Explore the Topics

🔗
Inheritance Basics
The "is-a" relationship and the extends keyword
📈
Access Rules
Visibility table, protected modifier, and interactive examples
🔧
Constructors
How parent constructors are called in subclasses
super Keyword
Referring to parent class members and constructors
🔄
Overriding vs Overloading
When a subclass redefines a parent method
Student hierarchy — a classic inheritance example
Tutorial Tip: Inheritance Checklist

Before creating an inheritance hierarchy, verify these points:

☑ IS-A test passes: "Child IS-A Parent" makes semantic sense ☑ Common behavior exists that belongs in the parent ☑ Subclass adds or overrides behavior (not just data) ☑ No more than 3 levels deep (avoid over-inheritance) ☑ Consider: would Composition (HAS-A) work better? Common mistakes: ✗ Car extends Engine → Car HAS-A Engine (use Composition) ✗ Stack extends ArrayList → exposes unwanted methods ✓ GraduateStudent extends Student → proper IS-A
🔗

Inheritance Basics

Inheritance allows defining a class in terms of a previously defined class using the extends keyword.

The Problem: Code Duplication
1
The Problem
2
Identify Duplicates
3
The Solution

Without inheritance, related classes must duplicate shared fields and methods:

Employee.java
Javapublic class Employee { public String name = ""; public double salary; public Date birthDate; public String getDetails() {...} }
Manager.java (duplicated!)
Javapublic class Manager extends Employee { public String name = ""; // duplicated public double salary; // duplicated public Date birthDate; // duplicated public String department; // new field public String getDetails() {...}}
Interactive: "Is-A" Relationship

Inheritance is appropriate when an "is a" relationship exists between two classes. Drag each subclass to its correct superclass:

Manager
Taxi
UndergraduateStudent
GraduateStudent
Circle
is-a Employee
is-a Car
is-a Student
is-a Student
is-a Shape
Try It Yourself: Create GraduateStudent extends Student

Create a GraduateStudent class that extends Student and adds a researchTopic field.

public class GraduateStudent extends Student { private String researchTopic; public GraduateStudent(String name, double gpa, String topic) { super(name, gpa); this.researchTopic = topic; } @Override public String toString() { return super.toString() + " - Research: " + researchTopic; } }

Notice: super(name, gpa) must be the first line. The @Override annotation ensures toString() properly overrides the parent.

📈

Access Rules

Complete reference for Java access modifiers, visibility spectrum, and interactive examples.

Modifier Same Class Same Package Subclass Different Package Scope / Rule
public Unrestricted access from anywhere
protected Accessible to the class, its subclasses, and classes in the same package
default Restricted to within the same package only
private Restricted to within the defining class only
Visibility Spectrum

Java provides four levels of access control, from most restrictive to most accessible:

private
default
protected
public

Visibility increases →

Interactive: Click to Test Access

Click on each member to see if it's accessible from the selected context:

Javapublic class C1 { public int x; // click to check protected int y; // click to check int z; // click to check private int u; // click to check }
Visibility Example — Packages p1 and p2
package p1;
public class C1 {
  public int x;
  protected int y;
  int z;
  private int u;
 
  protected void m() { }
}
public class C2 {
  C1 o = new C1();
  o.x; // ✓ can access
  o.y; // ✓ can access
  o.z; // ✓ can access
  o.u; // ✗ cannot access
  o.m(); // ✓ can invoke
}
public class C3
  extends C1 {
  x; // ✓ can access
  y; // ✓ can access
  z; // ✓ can access
  u; // ✗ cannot access
  m(); // ✓ can invoke
}
package p2;
public class C4
  extends C1 {
  x; // ✓ can access
  y; // ✓ can access
  z; // ✗ cannot access
  u; // ✗ cannot access
  m(); // ✓ can invoke
}
public class C5 {
  C1 o = new C1();
  o.x; // ✓ can access
  o.y; // ✗ cannot access
  o.z; // ✗ cannot access
  o.u; // ✗ cannot access
  o.m(); // ✗ cannot invoke
}
Rule: A subclass cannot weaken the accessibility of a method defined in the superclass. If a method is public in the superclass, it must remain public in the subclass. However, you can increase visibility (e.g., protectedpublic).
From a Client (Outside) Class

Only public members are visible from an unrelated class. Both protected and private are hidden.

A Client class can only access public members of both Super and Sub objects.
From a Sub Class Method

Everything is visible except the private members of its superclass.

A subclass can access public and protected members inherited from the parent, plus its own members.
Try It Yourself: Predict which members are accessible

Given class Vehicle { public String make; protected int year; private String vin; } and class Truck extends Vehicle in a different package, which can Truck access?

🔧

Constructors in Inheritance

Constructors are not inherited. The parent constructor is always called before the child constructor body executes.

Key Rules
  • Constructors of a superclass are NOT inherited by subclasses
  • If the subclass constructor does not explicitly call super(), Java implicitly calls the no-arg constructor of the parent
  • If the parent class has no no-arg constructor, the subclass will not compile
  • The parent constructor call must be the first line of the subclass constructor
Implicit Call — Works Fine
Javapublic class Employee { String name; public Employee() { name = "unallocated"; } public Employee(String n) { name = n; } } public class Manager extends Employee { String department; public Manager(String s, String d) { // Implicit: super() calls Employee() // name is set to "unallocated" department = d; } }
Compile Error — No No-Arg Constructor
Javapublic class Employee { String name; public Employee(String n) { name = n; } // No no-arg constructor! } public class Manager extends Employee { String department; public Manager(String s, String d) { // Implicit super() tries to call Employee() // COMPILE ERROR! No matching constructor department = d; } }
Fix: Either add a no-arg constructor to Employee, or use super(s) to explicitly call the existing Employee(String) constructor.
Interactive: Constructor Chain Tracer
1
main()
2
Faculty()
3
Employee()
4
Emp(String)
5
Person()
6
Print (1)
7
Print (2)
8
Print (3,4)

Step through the constructor chain when new Faculty() is called:

Java Code
Javaclass TestFaculty { public static void main(String[] args) { new Faculty(); }} class Person { public Person() { System.out.println("(1) Person's no-arg constructor"); }}class Employee extends Person { public Employee() { this("(2) Employee's overloaded constructor"); System.out.println("(3) Employee's no-arg constructor"); } public Employee(String s) { System.out.println(s); }}public class Faculty extends Employee { public Faculty() { System.out.println("(4) Faculty's no-arg constructor"); }}
Execution
main()
Call new Faculty() — JVM enters Faculty's no-arg constructor.
Console Output
$ java Faculty
Try It Yourself: Fix this broken constructor chain

This code has a compile error. Can you spot and fix it?

public class Animal { public Animal(String name) { System.out.println("Animal: " + name); } } public class Dog extends Animal { public Dog() { // ERROR! System.out.println("Dog created"); } }

Problem: Dog() implicitly calls super(), but Animal has no no-arg constructor!

Fix: Change to public Dog(String name) { super(name); ... }

The super Keyword

A reference variable used to refer to the immediate parent class object.

Three Usages of super
1
super.variable
Access parent class instance variable
2
super.method()
Invoke parent class method
3
super(args)
Invoke parent class constructor
Explicit Constructor Call with super
Javapublic class Employee { private String name; public Employee() { name = "unallocated"; } public Employee(String n) { name = n; } } public class Manager extends Employee { String department; public Manager(String s, String d) { super(s); // Calls Employee(String n) department = d; // name is set properly via parent constructor } }
Important: super() must be the first statement in the subclass constructor. You cannot place other code before it.
Accessing Protected Parent Fields

When the parent field is protected, the subclass can directly access it without super:

Javapublic class Employee { protected String name; public Employee() { name = "unallocated"; } public Employee(String n) { name = n; } } public class Manager extends Employee { String department; public Manager(String s, String d) { // implicit super() sets name = "unallocated" name = s; // direct access to protected field department = d; } }
Find the Error

What is wrong with this code?

Javapublic class Apple extends Fruit { } class Fruit { public Fruit(String name) { System.out.println("Fruit's constructor is invoked"); } }
Try It Yourself: Use super.toString() and extend it

Given a Person class with toString() returning "Person: Alice", write Employee's toString() that appends company info:

@Override public String toString() { return super.toString() + " at " + company; } // Output: "Person: Alice at TechCorp"

super.toString() calls the parent's version, and you extend it with additional info. This is the most common override pattern!

🔄

Overriding vs. Overloading

Two different concepts that are often confused by students.

Overriding
  • Same method name
  • Same parameter types
  • Same return type
  • Occurs in parent-child relationship
  • Replaces the parent's implementation
Overrideclass B { public void p(double i) { System.out.println(i * 2); } } class A extends B { public void p(double i) { System.out.println(i); } }

a.p(10)10.0
a.p(10.0)10.0

Overloading
  • Same method name
  • Different parameter types
  • Return type may differ
  • Can be in same class or parent-child
  • Adds a new version of the method
Overloadclass B { public void p(double i) { System.out.println(i * 2); } } class A extends B { public void p(int i) { System.out.println(i); } }

a.p(10)10 (int version)
a.p(10.0)20.0 (parent's double version)

Key Difference: Overriding replaces the parent's method (same signature). Overloading creates a new method with different parameters. In overriding, p(double) in both classes — in overloading, p(double) vs p(int).
Interactive: Override or Overload?

For each pair, decide whether the subclass method overrides or overloads the parent method:

Knowledge Check

Test your understanding of Inheritance in Java. Click an answer to check it.

YOUR SCORE
0 / 10