5) Object-Oriented Programming (OOP) Lesson

What is Java Inheritance

23 min to complete · By Ryan Desmond

Inheritance is one of the four primary principles of object-oriented programming (OOP). Inheritance allows a class (subclass or derived class) to inherit the properties and behaviors of another class (superclass or base class). Inheritance promotes code reuse, extensibility, and the creation of a hierarchical structure among classes. The subclass can access the members (fields and methods) of the superclass and provide additional members or override the existing ones.

How Does Inheritance in Java Work?

You have already covered the first two principles of object-oriented programming: Abstraction and Encapsulation.

Now it’s time to look at the third: Inheritance. Java allows a subclass to add (extend) a superclass when declared. This means that a subclass inherits all the fields and methods from a superclass.

How to Add Inheritance to a Class

For one class to inherit from another, you need to add the extends keyword in the class definition. For example:

// Superclass
class Animal {
    void walk() {
        System.out.println("Animal is walking");
    }

    void jump() {
        System.out.println("Animal is jumping");
    }

    private void privateMethod(){
        System.out.println("Animal is sleeping");
    }
}

// Subclass inheriting from Animal
class Dog extends Animal {
    void bark() {
        System.out.println("Dog is barking");
    }
}

public class InheritanceExample {
    public static void main(String[] args) {
        // Creating an instance of the subclass
        Dog myDog = new Dog();

        // Accessing methods from the superclass (Animal)
        myDog.walk();
        // Output: Animal is walking
        myDog.jump();  
        // Output: Animal is jumping

        // Accessing the method from the subclass
        myDog.bark();   
        // Output: Dog is barking

        // trying to access private method
        // this is an error!
        myDog.privateMethod();
    }
}

What Does a Subclass Inherit?

In this example, the Dog class is a subclass of the Animal class. The Dog class inherits the walk() and jump() methods from the Animal class and adds its own method bark(). An instance of Dog can access both the methods from Animal and its own additional method.

It is important to remember that the Dog class cannot access private variables or methods in the Animal class. Private members are only accessible by other members of the same class where they are defined

It is also impossible for a class to extend more than one other class in Java. All Java classes can extend one other class - no exceptions.

What is Multiple Inheritance in Java

In Java, a subclass can inherit fields and methods from multiple superclasses away.

How Does Multilevel Inheritance Work?

There is no limit to how many levels of inheritance you can create. You can have an inheritance architecture that is five, six, ten, or more levels deep, not that you would necessarily want to.

That said, all the rules of inheritance apply to all parent classes. That is, a subclass continues to have direct access to all public and protected members of all parent classes.

Multiple Inheritance Example in Java

In the real world, there are many times when the architecture of objects can be more than a level deep. Looking at the example of vehicles, when you include the brand of the machine, it becomes quite intuitive to have three levels:

// parent class Vehicle
class Vehicle {
    int mpg;
    int fuel_capacity;
    String type;
    // ...
}
  
// child class MotorCycle
class MotorCycle extends Vehicle { 
    int cubicLiters;
    // ...
} 

// child class (of MotorCycle) Ducati
class Ducati extends MotorCycle {

    boolean dryClutch = true;

    // constructor for Ducati
    public Ducati(){
        // the following variables belong to Vehicle
        mpg = 30;
        fuel_capacity = 10;
        type = "Ducati Motorcycle";
        // cubicLiters belongs to MotorCycle
        cubicLiters = 2000;
    }
    // ...
}

Accessing Parent Members

A subclass has direct access to all public and protected instance variables and methods of the parent class as though they were their own.

This means that the definition of Ducati is setting the preexisting fields of mpg, fuel_capacity, type and cubicLiters from its parent classes and therefore doesn't need to initialize these variables before setting them.

Inheritance architecture. Vehicle super class with two subclasses, Motorcycle and Car. Motorcycle also has one subclass, Ducati

What is a Super Constructor in Java?

A super constructor is a constructor in a parent class (aka "super" class). Since both subclasses and parent classes have constructors, it is important to know how to manage them.

What Role do Constructors Play in Inheritance?

The subclass constructor is responsible for constructing the subclass, and the parent class constructor is responsible for constructing the parent class. One thing to keep in mind, the parent class must exist before the child class. So, often, the very first thing a child class constructor will do is invoke the parent constructor using the super() keyword.

To ensure you are calling the field or method of a parent, the super keyword is used. If you see super() (with the parenthesis), that means that the parent constructor is being invoked.

Constructors and Inheritance Example in Java

In the following example, you'll make use of the super keyword in a hospitality setting (We'll dig into the super keyword again in just a couple of pages).

In the Restaurant class, there are two constructors, one that takes no parameters and one that takes all three. Be sure to be comfortable with overloading constructors before moving on. As you can see, both constructors assign values to the Restaurant instance variables.

// superclass aka parent class
class Restaurant{

    private int area;
    private int capacity;
    private String style;
 
   // default constructor
    public Restaurant(){
        area = 0;
        capacity = 0;
        style = "";
    }

    // overloaded constructor
    public Restaurant(int area, int capacity, String style){
        this.area = area;
        this.capacity = capacity;
        this.style = style;
    }
}

You may have noticed another new keyword lately. The this keyword in Java references the current instance of the object, instead of referencing the superclass of the object like super does.

What's the Difference Between Super and This?

The this keyword is just like the super keyword. However, instead of referring to a variable or method in the parent class, this refers to a variable or method in the current class.

Constructor Overloading

In the Gourmet class, you can see that the constructor is overloaded. The constructors in the Gourmet class assign values to the Gourmet instance variables. By overloading the constructor, you're allowing various options for how to create an object of type Gourmet.

// subclass
class Gourmet extends Restaurant {

    private int waitTime;

    // default constructor
    public Gourmet(){
       // the line below invokes the default 
       // (empty) parent constructor
       super();
       waitTime = 0;
    }

    // overloaded constructor
    public Gourmet(int area, int capacity, String style, int wt){
        // in the line below you are invoking the 
        // parameterized parent constructor
        super(area, capacity, style);
        waitTime = wt;
    }
}

// controller
class RestaurantTester {
    public static void main(String args[]){
        // create new gourmet restaurant 
        // with specific parameters
        Gourmet fancy = new Gourmet(100, 250, "Italian", 20);
        // create new gourmet restaurant 
        // using the default constructors
        Gourmet fancyDefault = new Gourmet();
    }
}

In order to test how the constructors work, you can look at the RestaurantTester class. You have created two objects, one with parameters and one with no parameters. As you can see with the first object, values for the superclass and subclass are passed to the Gourmet constructor. The Gourmet constructor creates the Gourmet parts of the object and passes the rest to the Restaurant constructor. This process climbs the hierarchy until the top-level constructor is called and the complete object is created.

Overriding Parent Methods

As you may have already seen, with inheritance, you can "override" a method from a superclass inside of a subclass. The @Override annotation is used to signal this process.

How to Override a Java Parent Method

To override a parent method, you simply need to declare a method with the same exact method signature in the child class as exists in the parent class. This is often done to modify the behavior of the parent method when it is invoked via a specific child class.

How to Use the Override Annotation

The @Override annotation is a Java annotation that communicates that this method overrides a method in a parent class. If no method with the same exact name and parameters is found in any of the parent classes, it is a compilation error.

It is not necessary to use the @Override annotation. If the child class method signature matches the parent class method signature exactly, the child class method will override the parent class method with or without the @Override annotation. The reason you use @Override is to enforce the functionality. Basically, if one of your coworkers modifies either method (therefore breaking the override functionality), an error will be raised if the @Override annotation is present. If @Override is not present, the change will not raise an error, but your application will be broken.

Override Example in Java

Below is an example of using the @Override keyword.

// parent class Vehicle
class Vehicle {
    int mpg;
    int fuel_capacity;
    String type;

    // parent method start()
    public void start(){
        System.out.println("Vehicle starting...");
        // do steps to start a vehicle ie,
        // push clutch with left foot
        // turn key with right hand
       // give a little gas with right foot
    }
}

// child class Motorcycle
class Motorcycle extends Vehicle {
    Motorcycle(){
        mpg = 30;
        fuel_capacity = 10;
        type = "motorcycle";
    }

    // the method below overrides the behavior of 
    // the start() method in the Vehicle class
    @Override
    public void start(){
        System.out.println("Motorcycle starting...");
        // do steps to start a motorcycle
        // lift kick stand
        // compress clutch with left hand
        // push ignition buttom with right thumb
        // slightly twist throttle with right hand
    }
}

class OverrideDemo {
    public static void main(String[] args){
        Vehicle vehicle = new Vehicle();
        // you can instantiate a new Motorcycle as a Vehicle as seen below
        // you could also say Motorcycle moto = new Motorcycle();
        //  they will both work
        Vehicle moto = new Motorcycle();
        // now invoke the start() method on the Motorcycle
        // which overrides the start() method in the Vehicle class
        moto.start();
        // now invoke the start() method on the Vehicle object 
        // (which will call the start() method in the Vehicle class)
        vehicle.start();
    }
}
/*
Output: 
Motorcycle starting...  
Vehicle starting...
*/

Notice how both classes are of type Vehicle. But the moto object actually uses the subclass Motorcycle. When you call the start() method on the vehicle object, it uses the start() method in the Vehicle class. When you call the start() method on the moto object, it uses the start() method in the Motorcycle class. This is an example of method overriding, which is polymorphism in action (more on this idea a little later).

The Java language is built on inheritance, and it is essential to many programs. The concept is easy, yet the results are incredibly powerful and stable. When a class can be inherited (aka "extended"), the code can be reused in many places without worrying about functional issues. 

Summary: What is inheritance in Java?

  • Inheritance is when one class inherits fields and methods from another class
  • The superclass can be called the parent class
  • The subclass can be called the child class
  • A child class has access to all public and protected elements of the parent class
  • private elements in the parent class are not inherited by the child class
  • A class can only inherit one class, and never more
  • Inheritance is achieved using the extends keyword
  • Overriding happens when a subclass overrides its superclass' method
  • @Override is written before the method that will be overriding
  • @Override is not required by the program
  • @Override is great for enforcing functionality and collaborating with other developers
  • A subclass can inherit from any number of superclasses
  • Multilevel inheritance is quite common in real-world applications
  • Both subclasses and superclasses can have constructors
  • The this keyword is used to reference fields and methods from the current class
  • The super keyword is used to reference fields and methods from a superclass
  • The super() method refers specifically to the parent constructor
  • A superclass constructor must be invoked before the subclass since a child can't exist before the parent

Syntax

Here's the syntax for doing inheritance, where you can substitute the variables starting with your_ with your values.

class YourChildClass extends YourParentClass { 
}