In the classes and objects lesson you built a single class at a time. As programs grow, you'll find classes that share a lot. A savings account and a current account are both bank accounts. A car and a bicycle are both vehicles. Copying the shared fields and methods into each class would work, until you need to fix a bug in every copy.
Inheritance lets one class build on another. A subclass declared with extends automatically gets the fields and methods of its superclass, then adds its own or changes, overrides, the ones that need to behave differently. The relationship reads naturally: a SavingsAccount is a BankAccount.
In this lesson you'll create subclasses, reuse a parent's constructor with super, override methods safely with @Override, control access with protected, and see polymorphism, the ability to treat many related objects through one parent type, which is one of the most important ideas in Java.
extends
class Vehicle {
String brand;
int wheels;
void describe() {
System.out.println(brand + " with " + wheels + " wheels");
}
}
class Bicycle extends Vehicle {
boolean hasBell;
}A Bicycle object has brand, wheels and describe() from Vehicle, plus its own hasBell. Java allows a class to extend only one class directly, but chains are possible: MountainBike extends Bicycle extends Vehicle. Every class you write ultimately extends Object, which is why every object has methods such as toString() and equals().
Constructors and super
Constructors are not inherited. A subclass constructor must first call a superclass constructor with super(...), as its very first line:
class Vehicle {
protected String brand;
Vehicle(String brand) { this.brand = brand; }
}
class Car extends Vehicle {
private int doors;
Car(String brand, int doors) {
super(brand); // let Vehicle set up its part
this.doors = doors; // then set up our own part
}
}If you don't write super(...), Java inserts a call to the parent's no-argument constructor, which fails to compile if the parent doesn't have one.
Overriding with @Override
A subclass can replace an inherited method by declaring one with the same name and parameters:
class Car extends Vehicle {
@Override
void describe() {
super.describe(); // reuse the parent's version
System.out.println("It has " + doors + " doors");
}
}The @Override annotation asks the compiler to check that you really are overriding something. If you misspell the name or get the parameters wrong, you get an error instead of a silent new method. super.methodName() calls the parent's version from inside the override.
Polymorphism and access levels
A variable of a parent type can hold any subclass object:
Vehicle v = new Car("Mini", 3);
v.describe(); // runs Car's describe()Java decides at run time which version to call, based on the actual object. That lets you write one loop over a List<Vehicle> that handles cars, bikes and lorries correctly, each in its own way.
Access modifiers control what subclasses can see. private members are visible only inside their own class, protected members are also visible to subclasses (and classes in the same package), and public members are visible everywhere. Mark a class or method final to forbid extending or overriding it.
Object, final and checking types
Every class in Java extends another, even if you don't write extends: a class with no parent automatically extends java.lang.Object. That's where every object gets toString(), equals() and hashCode(), which your classes can override.
The keyword final stops inheritance where it isn't wanted:
- A
finalclass can't be extended.StringandIntegerare final, so nobody can create a subclass that changes how text or numbers behave. - A
finalmethod can't be overridden by subclasses.
Sometimes code holding a parent-type variable needs to know the actual object type. instanceof checks it, and since Java 16 it can also declare a variable of the subclass type in one step:
Vehicle v = new Car("Mini", 3);
if (v instanceof Car c) {
System.out.println(c.brand + " is a car");
}Use this sparingly. If you find yourself checking types often, an overridden method that each subclass implements in its own way is usually the cleaner design. The companion lessons on inheritance and super and polymorphism and overriding go deeper.
Java Inheritance Syntax
Inheritance syntax
class Parent {
protected Type field;
Parent(Type field) { this.field = field; }
void method() { }
}
class Child extends Parent {
Child(Type field) { super(field); }
@Override
void method() {
super.method();
}
}
Parent p = new Child(value);Java Inheritance Summary
class Child extends Parentinherits the parent's fields and methods.- A subclass constructor calls
super(...)first to build the parent part. - Override a method by redefining it; add
@Overrideso the compiler checks it. - A parent-type variable can hold a subclass object; the object's own method runs.
protectedgives subclasses access;finalprevents extending or overriding.
Java Inheritance Examples
Each example shows the code, the output it produces and what each part does.
Accounts with shared and special behaviour
class BankAccount {
protected String owner;
protected double balance;
BankAccount(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
void monthEnd() { }
@Override
public String toString() {
return String.format("%s: £%.2f", owner, balance);
}
}
class SavingsAccount extends BankAccount {
private double rate;
SavingsAccount(String owner, double balance, double rate) {
super(owner, balance);
this.rate = rate;
}
@Override
void monthEnd() {
balance += balance * rate;
}
}
public class Main {
public static void main(String[] args) {
BankAccount current = new BankAccount("Sam", 120);
BankAccount savings = new SavingsAccount("Lea", 1000, 0.01);
for (BankAccount a : new BankAccount[] {current, savings}) {
a.monthEnd();
System.out.println(a);
}
}
}Sam: £120.00
Lea: £1010.00Line-by-line explanation
- Lines 2 to 3protected fields can be used directly by subclasses.
- Lines 12 to 15Overriding toString from Object controls how the account prints.
- Line 22super(...) runs the parent constructor first.
- Lines 26 to 29Savings accounts earn interest at month end; ordinary accounts do nothing.
- Lines 37 to 40The same loop calls the right monthEnd() for each object: polymorphism.
Calling the parent's method with super
class Employee {
protected String name;
Employee(String name) { this.name = name; }
String badge() {
return "Employee: " + name;
}
}
class Manager extends Employee {
private int teamSize;
Manager(String name, int teamSize) {
super(name);
this.teamSize = teamSize;
}
@Override
String badge() {
return super.badge() + " (manages " + teamSize + ")";
}
}
public class Main {
public static void main(String[] args) {
Employee e = new Employee("Ana");
Employee m = new Manager("Ben", 4);
System.out.println(e.badge());
System.out.println(m.badge());
System.out.println(m instanceof Employee);
}
}Employee: Ana
Employee: Ben (manages 4)
trueLine-by-line explanation
- Line 19super.badge() reuses the parent's text and adds to it.
- Line 26The variable's type is Employee, but the object is a Manager.
- Line 28Java calls Manager's badge() because of the actual object.
- Line 29instanceof confirms a Manager is an Employee.
Shapes and polymorphism
class Shape {
double area() { return 0; }
String name() { return getClass().getSimpleName(); }
}
class Circle extends Shape {
private double r;
Circle(double r) { this.r = r; }
@Override double area() { return Math.PI * r * r; }
}
class Rectangle extends Shape {
private double w, h;
Rectangle(double w, double h) { this.w = w; this.h = h; }
@Override double area() { return w * h; }
}
public class Main {
public static void main(String[] args) {
Shape[] shapes = { new Circle(1), new Rectangle(3, 4), new Circle(2) };
double total = 0;
for (Shape s : shapes) {
System.out.printf("%-9s %6.2f%n", s.name(), s.area());
total += s.area();
}
System.out.printf("Total %6.2f%n", total);
}
}Circle 3.14
Rectangle 12.00
Circle 12.57
Total 27.71Line-by-line explanation
- Line 3getClass().getSimpleName() returns the real class name of each object.
- Line 9Circle overrides area() with its own formula.
- Line 15Rectangle does the same with width times height.
- Lines 20 to 25The loop only knows about Shape, yet every area is calculated correctly.
Common Java Inheritance Mistakes
Forgetting to call super with arguments
class Car extends Vehicle {
Car(String brand) {
this.brand = brand; // error: Vehicle has no no-argument constructor
}
}class Car extends Vehicle {
Car(String brand) {
super(brand);
}
}Overloading instead of overriding
class Circle extends Shape {
double area(double scale) { ... } // a new method, not an override
}class Circle extends Shape {
@Override
double area() { ... }
}With @Override on the wrong version, the compiler would have caught the mismatch.
Using private when subclasses need access
class Vehicle { private String brand; }
class Car extends Vehicle {
String label() { return brand; } // brand has private access
}class Vehicle { protected String brand; }Java Inheritance in Real Projects
Inheritance in Java libraries
Every Java exception extends Exception or RuntimeException, which is why one catch can handle a whole family of errors. Android screens extend Activity, JavaFX windows extend Application, and all classes inherit toString(), equals() and hashCode() from Object, which you override so your objects print and compare sensibly.
Java Inheritance FAQ
Does Java support multiple inheritance?
Not for classes: a class can extend only one other class, which avoids the ambiguity of inheriting two different versions of the same method. A class can implement any number of interfaces, which gives most of the benefits of multiple inheritance.
What is the difference between overloading and overriding?
Overloading means several methods in the same class share a name but have different parameter lists; Java picks one at compile time from the arguments. Overriding means a subclass replaces an inherited method with the same name and parameters; Java picks the version at run time from the actual object.
Can a subclass override a private or static method?
No. Private methods aren't visible to subclasses, so a method with the same name in the subclass is a separate method. A static method with the same signature in a subclass hides the parent's version instead of overriding it, and the version called depends on the variable's declared type, not the object.
What is the difference between super and this?
this refers to the current object and its own members, and this(...) calls another constructor of the same class. super refers to the parent class's part of the object: super.method() calls the parent's version of a method, and super(...) calls a parent constructor.
When should I use composition instead of inheritance?
Use composition, a field holding another object, when the relationship is "has a" rather than "is a", or when you only want to reuse some behaviour. Composition keeps classes loosely connected, so changes to one class are less likely to break another. Many designers prefer composition by default and use inheritance for true "is a" relationships.
Java Inheritance Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the class so Dog inherits from Animal.
class Dog Animal {
}
Complete the constructor so the parent sets the name.
Dog(String name) {
(name);
}
What does this print?
class A { String hi() { return "A"; } }
class B extends A { @Override String hi() { return "B"; } }
// in main:
A obj = new B();
System.out.println(obj.hi());
Which access modifier lets subclasses use a field while hiding it from unrelated classes in other packages?
What does @Override do?
Java Inheritance Quiz
5 questions to check what you learned.
How many classes can a Java class extend directly?
- One
- Two
- As many as you like
- None
Where must
super(...)appear in a constructor?- Anywhere
- As the first statement
- As the last statement
- Outside the constructor
Which class does every Java class ultimately extend?
- Object
- Main
- Class
- Base
What is polymorphism?
- Having many constructors
- Copying a class
- Calling the same method on different subclass objects and getting each one's own behaviour
- Hiding fields
What does
finalon a method mean?- It can't be called
- Subclasses can't override it
- It runs last
- It returns a constant