Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Java

Inheritance

What does a class inherit through extends?

Inheritance is syntax in which you write extends and another class after the class name, as in class Dog extends Animal. The Animal after extends is the superclass, Dog is the subclass, and Dog inherits the methods and fields written in Animal. So you can call eat(), which is not written in Dog, on a Dog object. If you write an inherited method again in Dog with the same name and the same parameters, the one in Dog runs on a Dog object, and this is overriding. And because you used extends, you can put a Dog object in a variable of type Animal. In this lab you remove extends, write eat() again, and change the type of the variable, and the same code is compiled and run each time. You see what the compiler reports and which eat runs.

Checked against real execution · Eight combinations were compiled with javax.tools and run on JDK 21, and the results were checked against the model

Concepts in this lab

Inheritance
This means defining a new class (the subclass) that receives the fields and methods of an existing class (the superclass). It reuses common code, and the subclass adds or overrides only the parts it needs. A Java class supports single inheritance only, and a change to the superclass affects every subclass, so it is best used only when there is a clear "is-a" relationship.
extends
extends is the keyword in a class declaration that says which class the class inherits from. You write it after the class name, as in class Dog extends Animal. The class written after it (Animal) is the superclass, and the class being declared (Dog) is the subclass. A class can write only one class after extends. A class marked final cannot be inherited from with extends. When you use extends, the superclass becomes a supertype of the subclass, so you can put an object of the subclass in a variable of the superclass type. A class that does not use extends has Object as its superclass.
Superclass and subclass
A superclass is a class that other classes inherit from with extends, and a subclass is a class that names its superclass with extends. In class Dog extends Animal, Animal is the superclass of Dog. A subclass inherits those methods of its superclass that it can access, so you can call them on an object of the subclass even if the subclass does not write them. If the subclass writes a method again with the same name and the same parameters, it uses that one instead of inheriting, and this is overriding. Every class further up the chain, such as the superclass of a superclass, is also called a superclass of the subclass.
Overriding
This means that a subclass redefines a method of its superclass (or of an interface) with the same signature. At run time, the method that matches the type of the actual object is called, and this is how polymorphism is implemented. The access level cannot be made narrower, and static, private, and final methods cannot be overridden.

Try these

Running with the default settings

  1. The compiler reads the source from the top. First it reads class Animal and learns that Animal has an eat method. Next it reads the line class Dog extends Animal and remembers that Dog is a subclass of Animal and inherits what is written in Animal. The Animal written after extends is the superclass. Inside Dog, the bark method was written directly.
  2. The compiler checks the line Dog d = new Dog();. It puts a Dog object in a variable of type Dog, so there is no problem. The type of the variable d is Dog, so a method called through d is looked up in the Dog type.
  3. The compiler checks the line d.eat();. The type of d is Dog, so it looks for the eat method in Dog, and there is no eat in Dog. Dog inherits from Animal, so it keeps looking in Animal, finds the eat written in Animal, and passes. This is why you can call, on a Dog object, an eat that is not written in Dog.
  4. Compilation succeeds and the Main class file that will run is created. So far the compiler has only checked, line by line, whether things can be used, and eat has not run even once.
  5. You run it with java Main. main starts, and new Dog() creates a Dog object and puts it in the variable d.
  6. The line d.eat(); runs. The object d refers to is a Dog object, so the eat to run is looked up first in the class of that object, Dog. Dog has no eat, so it looks in Animal, and the eat written in Animal runs and prints "eats".
  7. The line d.bark(); runs. The bark of a Dog object is a method written directly in Dog, so it runs as it is and prints "woof".

Result of this run

Code

class Animal {
    void eat() {
        System.out.println("eats");
    }
}

// Inheritance: Dog inherits what is written in Animal
class Dog extends Animal {
    void bark() {
        System.out.println("woof");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat();
        d.bark();
    }
}

Assumptions of this model

The compiler and runtime are JDK 21.0.12.1 (javac 21). For all eight combinations, the same source as the code on the screen (identical line by line) was compiled with javax.tools. The ones that compiled had their class files loaded by a new class loader and Main.main was run, and the results were checked against the standard output that was captured. What was checked is whether compilation succeeded, the diagnostic code of the first error (compiler.err.cant.resolve.location.args and compiler.err.prob.found.req, shown on the screen as the two error descriptions), the number of errors and the lines where they occurred, whether the Main class file was created, and the output when run. The "eat that ran" was decided not by guessing but by the output. The eat of Animal was written to print "eats" and the eat of Dog to print "the dog eats", and the actual output was read to see which one it was. The facts that the step sentences rely on were also checked by separate runs. Calling bark(), which is written only in Dog, through an Animal-type variable is a compile-time error (so the code for the Animal variable has no d.bark() line). Even if eat is written again in Dog, the eat called on an Animal object still prints "eats". Even without extends, the bark written directly in Dog can be used without a problem. The documentation checked was the Java Language Specification (Java SE 21), opened directly. The rule that the extends clause names the direct superclass and that the class is called a subclass follows section 8.1.4. The rule that a class inherits the accessible methods of its superclass that it does not write again with the same signature follows section 8.4.8. The rule that a subclass writing a method of its superclass again with the same signature is overriding follows section 8.4.8.1. The rule that a superclass is a supertype of its subclass (so a subclass object can be put in a superclass-type variable) follows section 4.10.2. The rule that at run time the overriding method is looked up by starting from the actual class of the target object and going upward, not from the type of the variable, follows section 15.12.4.4. Sections 5.1.5 and 5.2 of the specification (the conversion that puts a value of a subclass type in a superclass-type variable in an assignment context) were not opened and checked in this lab. The kind of error, the number of errors, and the line where each occurs are not set by the specification. They were observed with this javac. When a Dog was put in an Animal variable without extends, the same one error occurred on the same line whether or not eat was written again in Dog. The code on the screen has the classes together in one file and shortens the access modifiers, and it does not use @Override. Every class inherits from Object even if it does not use extends, but this lab did not cover that, and the statement that without extends Dog has only what it writes itself is about what is written in Animal. The rule that a class also inherits the accessible fields of its superclass was checked in section 8.3, but this lab showed only methods by running them. Writing a field of the superclass, constructors, the super keyword, the fact that private members are not inherited, and the order in which a subclass calls a superclass constructor were also not covered in this lab. The order in which superclass constructors run and super are covered in "In-depth lab: Inheritance and overriding".

Previous lab: static · Next lab: Interfaces

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these