Topic 5.1
Inheritance with extends
In one line
class Dog extends Animal makes Dog a kind of Animal: it gets Animal's fields and methods for free and can add its own. A class can extend only one class, and every class ultimately extends java.lang.Object.
Think of it like this
A family recipe book. Grandma's book has recipes for rice, dal and roti. When your mother starts her own book, she doesn't copy every page by hand. She starts with grandma's book and adds her own recipes at the end. Anyone who opens your mother's book can still cook grandma's dal. That is inheritance: the new book gets everything the old one had, plus its additions.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Inheritance
- A way for one class to start with everything another class has, then add or change things. You write it with the keyword
extends. - Superclass
- The class being extended, also called the parent or base class. In
Dog extends Animal,Animalis the superclass. - Subclass
- The class that extends another, also called the child or derived class. In
Dog extends Animal,Dogis the subclass. - is-a relationship
- The test for inheritance: if 'every Dog is an Animal' is true,
Dog extends Animalmakes sense. - Class hierarchy
- The family tree of classes formed by
extends.Objectis at the top, and each class has exactly one parent. - java.lang.Object
- The root class of Java. Every class extends it, directly or through its parents, so every object has its methods.
- protected
- An access level: visible in the same package and in subclasses, even subclasses in other packages.
- Single inheritance
- The Java rule that a class may extend only one class.
Step by step
01The problem: copy-pasted code
Imagine a zoo app with Dog and Bird classes. Both need a name, a number of legs, an eat() method and a sleep() method. Written separately, the same fields and methods appear twice. Fix a bug in eat() and you must remember to fix it in both places. With ten animal classes, you will forget one.
Inheritance solves this by putting the shared parts in one place, a class called Animal, and letting Dog and Bird start from it.
class Animal {
String name;
int legs = 4;
void eat() { System.out.println(name + " is eating"); }
void sleep() { System.out.println(name + " is sleeping"); }
}
class Dog extends Animal { // Dog gets name, legs, eat(), sleep()
void bark() { System.out.println(name + " says Woof"); }
}
class Bird extends Animal {
Bird() { legs = 2; } // change an inherited field
void fly() { System.out.println(name + " is flying"); }
}02Draw the family tree
A class diagram shows the hierarchy. The arrow points from the child to the parent and reads 'extends'. Object sits at the very top even though we never wrote it.
A Dog object can do everything in its own box and everything in every box above it. A plain Animal object can't bark(): inheritance flows down the tree, never up.
03What gets inherited, and what doesn't
Inherited: public, protected, and package-private fields and methods (package-private only when the subclass is in the same package). Static methods and fields are also reachable through the subclass name.
Not inherited: constructors. Dog does not get a Dog(String name) constructor just because Animal has Animal(String name). It must declare its own and pass the value up with super(name) (Topic 5.2).
Present but not visible: private fields. If Animal has private String name, every Dog object still contains a name slot, but code inside Dog that writes name gets a compile error. The field belongs to Animal's code, and Dog must go through Animal's methods, such as a getName() getter. This is encapsulation (Topic 4.5) protecting the parent from its children.
04Constructors run from the top down
When you write new Dog(), Java must build the whole object: Object's part, then Animal's part, then Dog's part. The compiler makes sure of this by putting a call to the parent constructor at the start of every constructor. If you don't write one, it inserts super(); (a call to the parent's no-argument constructor).
Inside each constructor the order is fixed: (1) call the parent constructor, (2) run this class's field initializers and instance initializer blocks in the order they appear, (3) run the rest of the constructor body.
This is why the parent's fields are always ready when the child's constructor body runs: the parent finished first.
05One object, not a chain of objects
A common misunderstanding: 'new Dog() creates an Animal object and a Dog object linked together.' It doesn't. It creates one object on the heap. That single block of memory has a header (which records that its class is Dog), then slots for the fields declared in Animal, then slots for the fields declared in Dog.
The variable on the stack holds one reference to that one block. Calling d.eat() runs Animal's code on that same object; calling d.bark() runs Dog's code on the same object.
06Only one parent class
Java forbids class C extends A, B. If A and B both had a field called id or a method start(), which one would C get? C++ allows this and has extra rules to resolve it. Java's designers chose simplicity: one parent class only.
You can still build deep trees (Object → Animal → Mammal → Dog), and a class can implement any number of interfaces (Topic 5.7). Deep trees are usually a warning sign, though; Topic 5.12 explains why.
07Every class extends Object
Write class Animal { } and the compiler treats it as class Animal extends Object { }. You can see this at run time with getClass().getSuperclass(), which walks up the tree one step at a time until it reaches Object, whose superclass is null.
This is why System.out.println(anyObject) always works: println calls toString(), and every object has one, inherited from Object if nobody overrode it.
Try it yourself
- 1
Add a third animal
In the first example, add
class Fish extends Animalwithlegs = 0in its constructor and aswim()method. Create one inmain, calleat()andswim().Before running, predict the exact lines it prints. Then run and compare.
- 2
Predict the constructor order
In the construction-order example, add a field
String colour = log("4b. Dog second field");*below* the Dog constructor. Predict where its line appears. (Answer: right after line 4, before line 5. Field initializers run in source order, all before the constructor body, no matter where they sit in the file.) - 3
Hide a field behind private
Make
nameprivate inAnimaland compile. Read the error, then addString getName() { return name; }to Animal and change Dog'sbark()to usegetName().
Code & diagrams
Dog never declares name, legs or eat(), yet it uses all three.
Expected output
Rex is eating
Rex says Woof
Rex legs: 4
Tweety is sleeping
Tweety is flying
Tweety legs: 2Field initializers run after the parent constructor finishes, but before the rest of this class's constructor body.
Expected output
1. LivingThing constructor body
2. Animal field initializer
3. Animal constructor body
4. Dog field initializer
5. Dog constructor bodyObject's toString() prints the class name, '@', and a hex hash code, so we only check the prefix to keep the output stable.
Expected output
Dog
Animal
java.lang.Object
d instanceof Animal: true
d instanceof Object: true
toString from Object: trueBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Read a private parent field
Declare private String name = "Rex"; in Animal and use name directly in a Dog method.
class Animal { private String name = "Rex"; }
class Dog extends Animal { String hello() { return "Hi " + name; } }Break #2
Parent has no no-argument constructor
Give Animal only Animal(String name) and write a Dog constructor that does not call super(...).
class Animal { Animal(String name) { } }
class Dog extends Animal { Dog() { System.out.println("dog"); } }Myth vs fact
Myth
Private fields are not inherited, so a Dog object doesn't contain Animal's private fields.
Fact
The fields are there in memory and are used by Animal's methods. They're just not *accessible by name* from Dog's code. The JLS says private members are not 'inherited' in the sense of being members of the subclass, which is about naming, not storage.
Myth
new Dog() creates two objects: an Animal and a Dog.
Fact
It creates exactly one object whose class is Dog. The constructors of every ancestor run on that one object to initialise their own fields.
Myth
Inheritance is mainly for reusing code.
Fact
Reuse is a side effect. The real meaning is substitutability: a Dog can be used anywhere an Animal is expected (Topic 5.4). If you only want reuse, composition (Topic 5.12) is usually safer.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Bytecode: the compiler-inserted
super()is aninvokespecial Animal."<init>":()Vat the start ofDog.<init>. The JVM verifier rejects any constructor that usesthis(except to assign its own fields) before that call completes, which is why the object is never seen half-built from the parent's side. - ▸
HotSpot lays out an object as a header (mark word plus a compressed class pointer, usually 12 bytes on 64-bit with compressed class pointers) followed by fields. Superclass fields come before subclass fields, so a superclass method can find
nameat the same offset in every subclass object. That fixed offset is what makes inherited field access a single load instruction. - ▸
Fields are never overridden. If
Dogdeclares its ownString name, the Dog object has twonameslots, and which one you read depends on the compile-time type of the reference (field hiding, shown in Topic 5.2 and 5.4). Avoid declaring a field with the same name as a parent's field. - ▸
Deep hierarchies hurt. Each level couples the child to the parent's implementation details (the 'fragile base class' problem). Most well-designed Java code keeps class hierarchies two or three levels deep and uses interfaces plus composition for the rest. See the System Design course's SOLID topic (
/topic/phase-1/solid) for the Liskov Substitution rule that inheritance must obey.
Remember this
- 1
Inheritance lets one class reuse another class's code. You write
class Dog extends Animal.Animalis the superclass (also called parent or base class) andDogis the subclass (child or derived class). EveryDogobject has all of Animal's fields and can call all of Animal's non-private methods, as if they were written insideDog. - 2
Inheritance models an is-a relationship. A dog *is an* animal, so
Dog extends Animalreads correctly. A car is *not an* engine, soCar extends Engineis wrong even though a car uses an engine (that is a *has-a* relationship, and Topic 5.12 shows the right tool for it). If the sentence 'every X is a Y' sounds false, don't useextends. - 3
What is inherited: all fields and methods that are
public,protected, or package-private (no modifier, when both classes are in the same package). What is not inherited: constructors (each class writes its own) and access toprivatemembers. A private field still exists inside the subclass object and takes up memory. The subclass just can't name it directly; it must use the parent's public or protected methods. - 4
Java allows single inheritance of classes: a class can
extendexactly one class.class C extends A, Bdoes not compile. This avoids the 'diamond problem', where two parents give conflicting versions of the same field or method. (A class can implement many *interfaces*, which you'll meet in Topic 5.7.) - 5
If you don't write
extends, the compiler addsextends Objectfor you. So every class is part of one big tree withjava.lang.Objectat the root, and every object you ever create hastoString(),equals(),hashCode()andgetClass()(Topic 4.8). - 6
When you create a subclass object, the parent part is built first. Every constructor begins by calling a parent constructor, either one you write with
super(...)or an invisiblesuper()the compiler inserts. Sonew Dog()runsObject's constructor, thenAnimal's, thenDog's: from the top of the tree down.
Explain it without notes
What does extends give a subclass, and what does it not give?
Why does Java allow only one superclass?
In what order do constructors and field initializers run for new C() where C extends B extends A?
A Dog object can't name Animal's private name field. Does the Dog object still contain that field? Explain.
Practice
Create Vehicle with fields brand and wheels and a method describe() that prints them. Create Car (4 wheels) and Bike (2 wheels) that extend it, each setting wheels in its constructor and adding one method of its own. Print a description of each.
Write a three-level hierarchy Person → Employee → Manager where each constructor prints its name, and show the order they print in.
Print the full superclass chain of java.util.ArrayList using getSuperclass() in a loop.
Trade-offs
- ↔
Inheritance removes duplication instantly, but it couples the child to the parent's internals: a change in the parent can silently change every child. Use it for true is-a relationships with a stable parent.
- ↔
Protected fields are convenient for subclasses but widen the parent's public surface: any subclass anywhere can now depend on them. Private fields plus protected or public methods keep the parent free to change.
- ↔
Deep hierarchies (four or more levels) make it hard to find where behaviour comes from. Flat hierarchies plus interfaces are easier to read and test.
Done when you can
Done when you can write a subclass with
extendsand use inherited fields and methods.Done when you can list what is and isn't inherited, including constructors and private fields.
Done when you can predict the order of constructors and field initializers in a three-level hierarchy.
Done when you can explain why Java has single class inheritance and that every class extends
Object.Done when you can apply the is-a test to reject a bad
extends.