Inheritance is one of the core principles of Object Oriented Programming. It enables us to establish IS-A relationship between classes/objects and reuse existing code.
It is through the support of inheritance that we can extend a class from another. It’s kind of establishing a parent-child relationship among classes that relate to each other.
Let’s say, we have a Car class with a field color and a method drive(). What if later we wish to define an SUV (a kind of car)? One way would be to create an SUV class and define color and drive() for it along with its other members. Inheritance in Java saves us from such a code duplication.
If we simply extend SUV from the Car class, our SUV will automatically have access to those members of Car. Note that by doing so, we’ll establish an SUV IS-A Car relationship.
The vocabulary of inheritance usually involves using below terms interchangeably:
A child inherits all the visible members of its superclass:
Java allows us to extend one class from another using extends keyword:
class Car { String color = "Blue"; public void drive() { System.out.println("Driving my car"); } } class SUV extends Car { public void displayDetails() { System.out.println("My car is "+ color); drive(); } }
Note that we haven’t created an instance of Car in our SUV. Still, we’re able to invoke drive() method and access the property color in SUV class. So our SUV has inherited those members from Car.
Java supports single-level and multi-level inheritance for both classes and interfaces. However, multiple-inheritance for classes isn’t allowed.
Unlike Java classes, a Java interface can extend multiple interfaces:
interface Car { void drive(); } interface Vehicle { void startIndicator(); } interface SUV extends Car, Vehicle { void displayDetails(); }
In the above code, our SUV interface has three methods – drive(), startIndicator() and displayDetails(). Any class that implements SUV must provide an implementation for all three of them.
Java allows a class to implement an interface:
class Truck implements Vehicle { public void startIndicator() { System.out.println("Starting Truck's indicator"); } }
Please note that:
A class can extend a class. An interface can extend an interface. A class implements an interface
Also when implementing an interface, a class is bound to provide the implementation of the abstract methods defined in an interface. A class can implement multiple interfaces.
We already discussed that Java supports multiple-inheritance through interfaces.
Java 8 onwards, we can define the default implementation of the methods in an interface. Let’s consider a scenario:
interface Vehicle { default void startIndicator() { System.out.println("Starting indicator"); } } interface Car { default void startIndicator() { System.out.println("Car :: Starting indicator"); } }
Now, what if I wish to a create an SUV class implementing both Vehicle and Car interfaces. What will the implementation of SUV‘s startIndicator() look like?
The answer to that is our code won’t compile for such scenarios. The reason being our Java compiler can’t decide which implementation to inherit.
//won't compile class SUV implements Vehicle, Car { }
For the above code to compile, we’ll have to override our startIndicator() method:
class SUV implements Vehicle, Car { @Override public void startIndicator() { System.out.println("SUV :: Starting indicator"); } }
In this article, we learned about Java Inheritance and its types. Note that we must always try to establish only justifiable IS-A relationships.