A family recipe card#
Picture your grandmother’s chili recipe on an index card. You like it, but you make it with turkey and add corn. You do not rewrite the whole card. You clip a note to it that says “same as Grandma’s, except: turkey instead of beef, and add corn at the end”.
That note is a subclass. Grandma’s card is the superclass. Inheritance just means a new class starts with everything an existing class has, and then adds or changes a few things. You write only the differences.
Your course, your textbook and your exam use three different pairs of names for the same two roles. They mean exactly the same thing:
| The class you start from | The class that starts from it |
|---|---|
| base class | derived class |
| parent class | child class |
| superclass | subclass |
The test for whether inheritance fits is one sentence: a subclass object is a superclass object. A dog is a pet. A savings account is a bank account. If the sentence sounds silly (“an engine is a car”), inheritance is the wrong tool. The polymorphism guide comes back to this test.
extends: what the child gets for free#
The keyword is extends. Write it after the class name, followed by the parent:
class Pet {
private String name;
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Dog extends Pet {
public Dog(String name) {
super(name);
}
public String fetch() {
return getName() + " brings the ball back";
}
}
public class Extends {
public static void main(String[] args) {
Dog rex = new Dog("Rex");
System.out.println(rex.getName());
System.out.println(rex.fetch());
}
}
Rex
Rex brings the ball back
Dog never wrote getName, yet rex.getName() works. The child received the parent’s public methods. It also added one of its own, fetch. The parent did not get fetch: inheritance only flows downwards, like the recipe note that Grandma’s card knows nothing about.
To keep each listing short, the classes in this guide share one file, and only the class with main is public. In your own projects, give each public class its own .java file, named after the class.
A Java class can extend only one parent. class Dog extends Pet, Animal does not compile. (Interfaces, two guides on, are how Java gets around this.)
Private fields stay private, even from children#
A subclass object does contain the parent’s private fields, but the subclass’s own code is not allowed to touch them by name. private means “only code inside this one class”, and a child is a different class. This is why the Java rulebook, and many exam questions, say that private members are not inherited: the data is there, but the child has no access to it.
class Pet {
private String name;
public Pet(String name) {
this.name = name;
}
}
class Dog extends Pet {
public Dog(String name) {
super(name);
}
public String tag() {
return "Tag: " + name;
}
}
public class PrivateErr {
public static void main(String[] args) {
System.out.println(new Dog("Rex").tag());
}
}
PrivateErr.java:15: error: name has private access in Pet
return "Tag: " + name;
^
1 error
The fix is to go through the parent’s public methods, here getName(). If you want children (and only children) to reach a member directly, mark it protected. Most courses still prefer private fields with getters, because it keeps the parent in control of its own data.
| Modifier | Who can use it by name | UML symbol |
|---|---|---|
private | only the class itself | - |
protected | the class, its subclasses, and classes in the same package | # |
public | everyone | + |
Constructors and super(...)#
Constructors are never inherited. A Dog needs its own constructor. Its first job is to let the parent set up the parent’s part, by calling super(...) with the parent’s arguments. That call must be the first line of the child’s constructor. (Java 25 relaxed this a little, allowing simple checks before the call, but the first-line rule is what your textbook, your IDE on older versions, and your exam expect.)
If you leave the call out, Java quietly writes super(); for you, with no arguments. That works only when the parent has a constructor that takes no arguments. When it does not, you get this:
class Pet {
private String name;
public Pet(String name) {
this.name = name;
}
}
class Dog extends Pet {
public Dog(String name) {
System.out.println("Making a dog");
}
}
public class NoSuper {
public static void main(String[] args) {
new Dog("Rex");
}
}
NoSuper.java:10: error: constructor Pet in class Pet cannot be applied to given types;
public Dog(String name) {
^
required: String
found: no arguments
reason: actual and formal argument lists differ in length
1 error
Read the error as “you tried to build a Pet with nothing, but a Pet needs a String”. The fix is the explicit call: super(name);.
Because the parent is always set up first, constructors run from the top of the family down. Watch the order:
class Animal {
public Animal() {
System.out.println("1. Animal part built");
}
}
class Dog extends Animal {
public Dog() {
super();
System.out.println("2. Dog part built");
}
}
class Puppy extends Dog {
public Puppy() {
System.out.println("3. Puppy part built");
}
}
public class Chain {
public static void main(String[] args) {
new Puppy();
}
}
1. Animal part built
2. Dog part built
3. Puppy part built
Building one Puppy ran three constructors, oldest ancestor first. A useful way to remember it: you cannot add a basement after the house is built. The parent part is the foundation, so it is poured first.
Overriding: replacing a parent method#
Overriding means the child writes its own version of a method the parent already has, with the same name and the same parameter list. When that method is called on a child object, the child’s version runs. This is the “turkey instead of beef” line on the recipe note.
class Pet {
public String speak() {
return "...";
}
}
class Cat extends Pet {
@Override
public String speak() {
return "Meow";
}
}
class Parrot extends Pet {
@Override
public String speak() {
return "Hello!";
}
}
public class Overriding {
public static void main(String[] args) {
System.out.println(new Pet().speak());
System.out.println(new Cat().speak());
System.out.println(new Parrot().speak());
}
}
...
Meow
Hello!
The cat and the parrot replaced speak. The generic pet still uses the parent’s version. Two rules come with overriding: the return type must match (or be a subclass of it), and the child cannot make the method more private. A public method stays public.
Put @Override on the line above every method you mean to override. It is an annotation, a note to the compiler, and it asks the compiler to check that a matching parent method really exists. Without it, a typo silently creates a brand-new method instead:
class Pet {
public String speak() {
return "...";
}
}
class Cat extends Pet {
@Override
public String speek() {
return "Meow";
}
}
public class Typo {
public static void main(String[] args) {
System.out.println(new Cat().speak());
}
}
Typo.java:8: error: method does not override or implement a method from a supertype
@Override
^
1 error
That error is a gift. Without @Override, speek would compile, the cat would still say the generic line, and you would be hunting for the bug at run time.
Overriding versus overloading#
The two words differ by three letters and examiners love to swap them. The difference is the parameter list.
| Overriding | Overloading | |
|---|---|---|
| Name | same | same |
| Parameter list | same | different (number, types or order) |
| Where | in a subclass, replacing the parent’s version | usually in the same class (a subclass can add one too) |
| Who picks the version | the object, while the program runs | the compiler, from the argument types |
class Animal {
public String move() {
return "moves";
}
}
class Bird extends Animal {
@Override
public String move() {
return "flies";
}
public String move(int metres) {
return "flies " + metres + " m";
}
}
public class Both {
public static void main(String[] args) {
Bird b = new Bird();
System.out.println(new Animal().move());
System.out.println(b.move());
System.out.println(b.move(40));
}
}
moves
flies
flies 40 m
Bird has three move methods. move() with no arguments replaces the parent’s, which is overriding. move(int) has a different parameter list, which is overloading: it sits beside the others rather than replacing anything. The memory line: override is a re-ride of the same route; overload loads a different set of parameters.
Calling the parent’s version with super.#
Sometimes you want to add to the parent’s behaviour rather than throw it away. Inside an overriding method, super.methodName() runs the parent’s version. The word super here means “my parent’s part of me”.
class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public String describe() {
return owner + ": $" + balance;
}
}
class Savings extends Account {
private double rate;
public Savings(String owner, double balance, double rate) {
super(owner, balance);
this.rate = rate;
}
@Override
public String describe() {
return super.describe() + " at " + rate + "%";
}
}
public class SuperDot {
public static void main(String[] args) {
System.out.println(new Account("Ana", 120.0).describe());
System.out.println(new Savings("Ben", 500.0, 2.5).describe());
}
}
Ana: $120.0
Ben: $500.0 at 2.5%
Savings reused the parent’s description and tacked the rate on the end. Without the super. prefix, describe() would call itself, then call itself again, until the call stack ran out of room and Java stopped with a StackOverflowError. That is a classic exam trap.
So super has two jobs, and it is worth keeping them apart:
| Written as | Where | Does |
|---|---|---|
super(...) | first line of a constructor | runs the parent’s constructor |
super.method() | any instance method | runs the parent’s version of that method |
Drawing inheritance in UML#
UML, the Unified Modeling Language, is a standard way to sketch classes as boxes. Each box has three parts stacked top to bottom: the class name, the fields, then the methods. A minus sign means private and a plus sign means public. Inheritance is drawn as a solid line with a hollow triangle arrowhead pointing at the parent.
+-----------------------+
| Account |
+-----------------------+
| - owner : String |
| - balance : double |
+-----------------------+
| + deposit(amt:double) |
| + describe() : String |
+-----------------------+
^ hollow triangle points at the parent
|
+-----------------------+
| Savings |
+-----------------------+
| - rate : double |
+-----------------------+
| + describe() : String |
+-----------------------+
The child box lists only what is new or overridden. Savings shows describe() again because it overrides it; it does not repeat deposit, which it simply inherits. If you remember one thing: the arrow points from child to parent, because the child knows who its parent is, and the parent does not know its children.
One more fact for later: a class with no extends still has a parent. Java gives it Object, the class at the top of every family tree. The next guide is about what you inherit from it.
A subclass is the recipe note, not a new card: it calls super(...) first, inherits everything public, and overrides a method only when the name and the parameter list match. Same parameters is overriding; different parameters is overloading.
Where these go wrong#
- Reaching for a parent’s
privatefield by name. It is there, but locked. Use the parent’s getter. - Putting
super(...)anywhere but the first line. Before Java 25 it must come first, or the constructor does not compile; write it first and you are safe on every version. - Forgetting
super(...)when the parent has no empty constructor. Java insertssuper()for you, and it fails. - Calling an overloaded method an override. A different parameter list is a new method beside the old one, not a replacement.
- Leaving off
@Override. A misspelled name then compiles as a new method and the parent’s version keeps running. - Writing
describe()instead ofsuper.describe()inside an override. The method calls itself until the program crashes with aStackOverflowError. - Drawing the UML arrow at the child. The hollow triangle points at the parent.
- Trying to extend two classes. Java allows one parent class.
Practice#
Answer each one on paper before you look at the solutions. Every answer that involves running code was checked by compiling and running it.
- In
class Truck extends Vehicle, name the superclass and the subclass, and give the other two names for each. - What does this program print?
class A { public A() { System.out.println("A"); } public void show() { System.out.println("A.show"); } } class B extends A { public B() { System.out.println("B"); } @Override public void show() { super.show(); System.out.println("B.show"); } } // in main: B b = new B(); b.show(); - A class
Pethas only the constructorPet(String name). Its subclass haspublic Dog() { }. Why does this not compile, and what is the smallest fix? Shapehasdouble area().Circle extends Shapedeclaresdouble area()and alsodouble area(int decimals). Which one overrides and which one overloads?- Write a class
Squarethat extends aRectangle(double width, double height)class. ASquareis built from one side length and overridesdescribe()to say “Square” instead of “Rectangle”. - What does
@Overridedo, and what happens if you leave it off a correctly spelled override?
Solutions#
Vehicleis the superclass, also called the base class or parent class.Truckis the subclass, also called the derived class or child class. The test sentence holds: a truck is a vehicle.- The parent constructor runs first (Java inserted
super()at the top ofB()), thenshowruns the parent’s version before adding its own line:class A { public A() { System.out.println("A"); } public void show() { System.out.println("A.show"); } } class B extends A { public B() { System.out.println("B"); } @Override public void show() { super.show(); System.out.println("B.show"); } } public class Q2 { public static void main(String[] args) { B b = new B(); b.show(); } }A B A.show B.show - Because Java inserts
super();as the first line ofDog(), andPethas no constructor that takes no arguments. The compiler reportsconstructor Pet in class Pet cannot be applied to given types. Fix: make the first line pass a name up, for examplesuper("unnamed");, or giveDogaString nameparameter and callsuper(name);. area()inCirclehas the same name and the same (empty) parameter list as the parent’s, so it overrides.area(int decimals)has a different parameter list, so it overloads: it adds a new method and replaces nothing.- The constructor passes the side up twice, and
describeis overridden with the same signature:class Rectangle { private double width, height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double area() { return width * height; } public String describe() { return "Rectangle with area " + area(); } } class Square extends Rectangle { public Square(double side) { super(side, side); } @Override public String describe() { return "Square with area " + area(); } } public class Q5 { public static void main(String[] args) { System.out.println(new Rectangle(2, 5).describe()); System.out.println(new Square(3).describe()); } }Rectangle with area 10.0 Square with area 9.0Squarenever wrotearea(); it inherited it. - It asks the compiler to confirm that the method really overrides a parent method, and to stop with
method does not override or implement a method from a supertypeif it does not. Leaving it off a correctly spelled override changes nothing at run time; the method still overrides. You lose only the safety check against typos.
Test-readiness checklist#
These are the items from the course’s Exam 2 topic list that this guide covers. Tick each one only when you can do it without looking.
- ☐ I can explain inheritance and give the three pairs of names: base/derived, parent/child, super/sub class.
- ☐ I can write a subclass with
extendsand a constructor that callssuper(...)first. - ☐ I can override a method, and I can say how overriding differs from overloading.
- ☐ I can call the base class’s version of a method with
super.method(). - ☐ I can draw the UML for a parent and child class, arrow pointing the right way.
Test yourself in the free Kestrel Exams app
40 practice questions on extends, super, constructor chains and overriding, with every code answer checked by compiling and running it. Free, offline, no account.
Frequently asked questions#
What is the difference between a superclass and a subclass in Java?
The superclass is the existing class; the subclass is the new class that extends it with the extends keyword. The subclass inherits the superclass's public and protected members, and adds or overrides only what is different. Superclass, base class and parent class all mean the same thing, as do subclass, derived class and child class.
Does a subclass inherit private fields?
A subclass object contains the parent's private fields, but the subclass's own code cannot use them by name. Code in the subclass gets "has private access" from the compiler. It must go through the parent's public methods such as getters, or the field must be made protected.
Why must super() be the first line of a constructor?
Because the parent part of the object has to be set up before the child part can rely on it. Java 25 relaxed the rule slightly to allow simple statements that do not use the object before the call, but on earlier versions, and in most courses, super(...) must come first. If you do not write a super call, Java inserts super() with no arguments, which fails to compile when the parent has no constructor that takes no arguments.
What is the difference between overriding and overloading?
Overriding is a subclass method with the same name and the same parameter list as a parent method; it replaces the parent version for objects of the subclass, and the version is chosen while the program runs. Overloading is a method with the same name but a different parameter list; it adds a new method, and the compiler chooses which one from the argument types.
What does super.method() do?
Inside a subclass, super.method() runs the parent's version of a method, usually from inside an override that wants to add to the parent's behaviour rather than replace it. Without the super. prefix, the override would call itself.
Can a Java class extend more than one class?
No. A Java class has exactly one direct superclass. If no extends clause is written, the superclass is Object. A class can implement many interfaces, which is how Java lets one class take on several roles.
Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.