Object-oriented programming (OOP) is a paradigm that models computer programs as a collection of objects that interact with one another. OOP differs from other programming approaches in its implementation of reusable code in the form of classes.
To make this reusability possible, OOP-style programs use a mechanism called inheritance. The main idea behind inheritance is to create new classes (known as “child classes” or “children”) that inherit the attributes and methods of preexisting classes (known as “parent classes”) without the need to rewrite code.
Inheritance is an intuitive and useful tool for modeling the real world. For example, consider the concept of children inheriting certain physical attributes and behaviors from their parents. Inheritance is especially well-suited to model many such real-world phenomena.
For instance, imagine that you want to develop a game about penguins. For this, you’ll need a parent class — penguin — that specifies the attributes and methods that all child classes of penguin will have. You can then create these child classes with more unique attributes and methods, in addition to those already acquired from the more generic parent class. This eliminates the need to copy and paste code from the parent class into each child class.
For this reason, many programming languages implement OOP, including Java, the focus of this article. Java popularized the use of OOP in the 1980s by facilitating the implementation of the four core OOP principles: inheritance, encapsulation, abstraction, and polymorphism.
In this article, you’ll learn how inheritance works in Java, explore the five types of Java inheritance, and better understand how it works for representing real-world things in code.
What is inheritance in Java?
In general, inheritance occurs when one or more children — or subclasses — extend the attributes and functionalities of one or more parents, or superclasses. In Java, there are five types of inheritance: single, multilevel, hierarchical, multiple, and hybrid.
Types of Inheritance in Java
Let’s now take a look at the various forms of inheritance and how they appear in Java programs.
Java uses the keyword extends to indicate that a Java class is inheriting attributes from another one. Inheritance means that the Penguin class will contain the grandParentMain method of the Animal class without having to rewrite it inside the Penguin class.
To understand single inheritance, in which the child class inherits from a single base class, consider the generic example below:
You can easily test this idea by creating a simple program that instantiates a subclass and calls both methods (click the “output” tab to view the output of the code).
Using the code above, you can confirm the child class’s ability to use its parent’s methods.
Multilevel inheritance occurs when one class inherits from a second class that already inherits from a third class.
To illustrate this concept, consider the two classes introduced in the previous section. You’ll now add a third class to describe a species within the Penguin class. This class will be called Emperor to represent an Emperor penguin. Because it inherits from Penguin, the Emperor class has access to all the attributes and methods of both the Penguin child class and the Animal base class.
Adding this specificity requires adding new levels to the “object tree.” As the name suggests, this is multilevel inheritance.
The following code sample tests this concept by instantiating an Emperor object and demonstrating that it can access all three methods:
Suppose that you now want to add more species of penguins to your game to accompany the Emperor penguins. You’ll create a new class for Gentoo penguins, who are distinguished primarily by their orange beaks:
As you can see, the Gentoo class inherits the same methods that Emperor does, but it adds a few customized attributes that characterize Gentoo penguins. Furthermore, since it isn’t inheriting from the Emperor class, trying to access the childMain method of the Emperor class will raise an error. This is called architecture hierarchical inheritance.
Multiple inheritance occurs when a single child class inherits from two parent classes. This style of inheritance is often very cumbersome and generates complicated problems. For example, the compiler is unable to distinguish or prioritize between two methods that have the same ID signature. For this reason, Java doesn’t support this type of multiple inheritance.
However, Java 8 presented an alternative — to implement multiple inheritance using Java interfaces and default methods. Interfaces are abstract classes that are often used to group related methods. This approach allows the implementing class to specify which method to use via a special keyword.
Furthermore, using default methods within interfaces helps to mitigate a common challenge of multiple inheritance: confusing the compiler. If two parents have a method with the same ID signature (meaning the function name), the compiler can’t determine which parent’s method to use. The Java keyword super allows the child class to access the methods of a specific parent class, therefore helping eliminate the ambiguity for the compiler.
The example above uses an interface (instead of a class) to represent each parent. Both parents have a method with the same identifier: show. The TestClass class inherits from both parents.
To achieve multiple inheritance, you implement a third show method in the child class to override both methods. Then, using the keyword super, you specify which parent’s method you want to call. Therefore, you first call show from Penguin1 and then from Penguin2.
For more flexibility, developers often combine two methods of inheritance. This practice is called hybrid inheritance. The goal of using hybrid inheritance is to modularize the codebase and develop well-defined classes.
Suppose you introduce a new class:
You’ll then change the method names in your previous classes to show. You now have a hierarchical inheritance since both Penguin and Catbird inherit from Animal. You also have a multilevel inheritance because Gentoo inherits from Penguin.
This example also demonstrates the usage of protected members. Looking back at the Animal class, you used the keyword protect to restrict the accessibility of the featherColor attribute. This keyword makes it available only to methods within the class or those that inherit from it.
Polymorphism Versus Inheritance
Inheritance simplifies code reusability, which allows you to create different instances of a parent class without rewriting code. Inheritance is a similar concept to polymorphism, so it’s easy to confuse the two. However, they’re not the same.
The difference is that polymorphism allows for customization. With polymorphism, you let child classes apply slight changes to the inherited methods and later identify which one to compile based on the input parameters. Check out our article on polymorphism in Java to learn more.
Using Java Inheritance in Your Code
Inheritance is a great tool to improve code reusability and model the real world, and Java gives you the right tools to seamlessly incorporate inheritance into your toolkit. The flexibility that its five types provide makes it extremely useful for representing real-world characteristics.
Moreover, you can use the super keyword and interfaces to implement multiple inheritance techniques. This enhances the abilities of inheritance to model real-world phenomena, making it very useful for developing video games and virtual reality programs.