Dataslope logoDataslope

Inheritance

The "is-a" relationship — extending classes, calling `super`, and the trade-offs of building tall class trees

Inheritance is the relationship that says one class is a kind of another. A Dog is a Mammal. A SavingsAccount is a BankAccount. A Square is a Rectangle — well, maybe — we'll come back to that.

Inheritance is the most famous OOP feature and also the most overused. This page will teach you how it works in Java and when it is the right tool — not just how to type extends.

A first family

The hollow arrow <|-- in UML means inheritanceDog is-an Animal. In Java, the keyword is extends.

Code Block
Java 8 (Update 492)

Three new pieces of Java vocabulary appear:

WordWhat it does
extendsDeclares "this class inherits from..."
super(...)Inside a subclass constructor: calls the parent constructor
@OverrideAnnotation that says "I'm replacing an inherited method" (the compiler checks this)

A subclass automatically inherits all public and protected members from its parent. It can add new fields and methods, and it can override inherited methods to change their behavior.

What super actually does

When you build a Dog, you build an Animal first, then add the Dog-specific bits on top. In memory, every Dog instance includes the state of an Animal.

super(name) in the Dog constructor is what runs the Animal constructor on the Dog-being-built to set up name. It must be the first statement in the subclass constructor.

If you omit super(...), Java silently inserts super() — a call to the parent's no-arg constructor. If the parent doesn't have a no-arg constructor, that silent insertion fails and you must call the right one explicitly.

Overriding: replacing inherited behavior

When a subclass declares a method with the same signature as one inherited from the parent, the subclass version replaces the parent's version for instances of the subclass.

The @Override annotation isn't strictly required, but it's free help: if you misspell the method name or get the parameter types wrong, the compiler refuses to compile. Always write it.

Calling the parent's version from the override

Sometimes the subclass wants to add to the parent's behavior rather than completely replace it. You can call the parent's version explicitly with super.methodName(...).

Code Block
Java 8 (Update 492)

Manager.monthlyPay() reuses everything Employee knows about pay and adds a bonus on top. If the salary formula in Employee changes (say, to add overtime), Manager automatically benefits.

final classes and methods: closing the door

You can opt out of being extended:

  • final class Foo { ... } — no class may extends Foo.
  • final on a method — subclasses may not override it.

final is a useful design tool. Java's String is final — for good reason; if anyone could subclass String and break its rules, the entire JVM's security model would collapse.

The trap: inheritance is strong coupling

The reason the GoF say "favor composition over inheritance" is not that inheritance is bad. It's that inheritance is very strong. A subclass depends on its parent's internal design. If the parent changes how it stores its data or which methods it calls internally, subclasses can break in surprising ways. This is sometimes called the fragile base class problem.

Use inheritance when you genuinely have an is-a relationship and the parent class was designed for extension. For everything else, reach for composition first.

A famous cautionary example: a Square is a Rectangle mathematically, but if you make Square extends Rectangle, you quickly discover that setting a square's width to a value different from its height violates the square's invariant. The "is-a" relationship in mathematics does not always translate cleanly into behavioral substitutability in software.

Practice

Challenge
Java 8 (Update 492)
Shape hierarchy with a subclass override

Build a small Shape hierarchy:

  • Shape has a method area() that returns 0.0 and a method describe() that returns "Shape with area " + area().
  • Circle extends Shape with a private final double radius and overrides area() to return Math.PI * radius * radius.
  • Square extends Shape with a private final double side and overrides area() to return side * side.

The provided Main builds a small list of shapes and prints each one. Expected output (the radius-1 area uses Java's Math.PI):

Shape with area 0.0
Shape with area 3.141592653589793
Shape with area 16.0

Test your understanding

QuestionSelect one

What does super(name) do inside a subclass constructor?

Calls a static method on the parent class

Invokes the parent class's constructor with the given arguments to initialize the parent part of the new object

Creates an entirely separate parent object

Marks the constructor as overriding

QuestionSelect one

Why is the @Override annotation a good habit?

It is required for the override to take effect at runtime

It tells the JVM to skip the parent method entirely

It asks the compiler to verify that you really are overriding an inherited method, catching typos and signature mismatches at compile time

It improves runtime performance of the method

QuestionSelect one

Which is the best reason to choose inheritance over composition?

You want to reuse code from another class

The other class has many methods

The new class is genuinely a kind of the other class, and the parent was designed for extension

You want to avoid creating new files

On this page