Inheritance in Java
This article covers an important OOP principle: inheritance.
Inheritance is an important OOP principle because it allows you to create a new class from an existing class. The existing class is known as the base class, superclass, or parent class and the new class is the derived class, sub-class, or child class.
Why would we need to do this? Whenever we come across an IS-A relationship between objects, that's a good opportunity to implement inheritance. Examples include:
Mammal
IS ANAnimal
.A
Car
IS AVehicle
.A
Smartphone
IS ADevice
.
In these cases, the base classes are Animal
, Vehicle
, and Device
while the derived classes are Mammal
, Car
, and Smartphone
respectively.
Derived classes inherit ALL public member variables and methods.
Another good example is class
. Class
actually inherits its implementation from the Java Object
class. Find out more about Object here.
Note: Some classes cannot be inherited. Such classes are defined with the keyword, final
. An example of such a class is the built-in Integer class
.
extends
keyword
To implement inheritance, you have to use the keyword extends
.
Example:
// Base Class Vehicle
class Vehicle {
// Private Fields
private String manufacturer;
private String make;
private int year;
private int engineSize;
// Parameterized Constructor
public Vehicle(String manufacturer, String make, int year, int engineSize) {
this.manufacturer = manufacturer;
this.make = make;
this.year = year;
this.engineSize = engineSize;
}
// public method to print details
public void printCarDetails() {
System.out.println("Manufacturer: " + make);
System.out.println("Make: " + color);
System.out.println("Year: " + year);
System.out.println("Engine Size: " + model);
}
}
// Derived Class Car
class Car extends Vehicle {
// Private field
private String bodyShape;
// Parameterized Constructor
public Car(String manufacturer, String make, int year, int engineSize, String bodyShape) {
super(manufacturer, make, year, engineSize); //call parent class constructor
this.bodyShape = bodyShape;
}
public void carDetails() { //added specific details of the car
printCarDetails(); //call method from parent class
System.out.println("Body Shape: " + bodyShape);
}
}
class Main {
public static void main(String[] args) {
Car mercedes = new Car("Mercedes", "Black", 2022, "S63", "Coupe"); //creation of car Object
mercedes.carDetails(); //call method to print details
}
}
super
keyword
In this article, we talked about the this
keyword and how it refers to an instance of the current class. Similarly, we introduce the super
keyword. The super
keyword is used to refer to all the members and methods of the base class inside the derived class.
It's mainly used to implement inheritance.
Let's look at some use cases.
Access super class members
Example:
class Vehicle { // Super class
int topSpeed = 180; // Top Speed defined inside the super class
}
class Car extends Vehicle { // Sub class extending from super class
int topSpeed = 260; // Top Speed defined inside the sub class
public void displayMaxSpeed() {
// Access the super class field inside the sub class
System.out.println("Top speed from the Vehicle class: " + super.topSpeed);
// Without using super
System.out.println("Top speed from the Car class: " + topSpeed);
}
}
class Main {
public static void main(String[] args) {
Car mercedes = new Car();
mercedes.displayMaxSpeed();
}
}
Access super class methods
Example:
class SuperDisplay { // Super class
public void display() { // display method inside SuperClass
System.out.println("I am from the Super Class");
}
}
class SubDisplay extends SuperDisplay { // sub class SubDisplay extending from SuperDisplay
public void display() { // display method inside SubClass
System.out.println("I am from the Sub Class");
}
public void print(){
System.out.println("The display() method with super:");
super.display(); //call the display() of SuperDisplay(SuperClass)
System.out.println("The display() method without super:");
display(); //call the display() of SubDisplay(SubClass)
}
}
class Main {
public static void main(String[] args) {
SubDisplay childclass = new SubDisplay();
childclass.print();
}
}
Access constructors
In this article, we cover how constructors are fundamental to creating objects from classes. super
can also be used to access constructors from a superclass inside a subclass.
Note: In a constructor, we can include a call to super()
or this()
but not both.
Example:
// Base Class Vehicle
class Vehicle {
// Private Fields
private String manufacturer;
private String make;
private int year;
private int engineSize;
// Parameterized Constructor
public Vehicle(String manufacturer, String make, int year, int engineSize) {
this.manufacturer = manufacturer;
this.make = make;
this.year = year;
this.engineSize = engineSize;
}
// public method to print details
public void printCarDetails() {
System.out.println("Manufacturer: " + make);
System.out.println("Make: " + color);
System.out.println("Year: " + year);
System.out.println("Engine Size: " + model);
}
}
// Derived Class Car
class Car extends Vehicle {
// Private field
private String bodyShape;
// Parameterized Constructor
public Car(String manufacturer, String make, int year, int engineSize, String bodyShape) {
super(manufacturer, make, year, engineSize); //call parent class constructor
this.bodyShape = bodyShape;
}
public void carDetails() { //added specific details of the car
printCarDetails(); //call method from parent class
System.out.println("Body Shape: " + bodyShape);
}
}
class Main {
public static void main(String[] args) {
Car mercedes = new Car("Mercedes", "Black", 2022, "S63", "Coupe"); //creation of car Object
mercedes.carDetails(); //call method to print details
}
}
super
can be used with no arguments to refer to a default constructor or with parameters (super(parameters))
to render to a parameterized constructor.
Types of inheritance
There are 5 types of inheritance:
Single
Multi-level
Hierarchical
Multiple
Hybrid
Single Inheritance
In single inheritance, there is only a single class extending from another class. Throughout this article, we have only covered single inheritance.
Multi-level inheritance
When a derived class inherits from a derived which itself inherits from a base class, this type of inheritance is called Multilevel Inheritance. Classes can be extended to any further levels per requirements.
Let's implement the following:
A
Car
IS AVehicle
A
Tesla
IS ACar
class Vehicle { //Base class
private int topSpeed;
public void setTopSpeed(int topSpeed) {
this.topSpeed=topSpeed;
System.out.println("Top Speed: "+ topSpeed);
}
}
class Car extends Vehicle { // Derived from Vehicle, Base for Tesla
public void pushToStart() {
System.out.println("The car has started.");
}
}
class Tesla extends Car { // Derived from Car and can be a base to any further class
public void chargeVehicle() {
System.out.println("The car is charging");
}
}
class Main {
public static void main(String[] args) {
Tesla modelS = new Tesla();
modelS.setTopSpeed(260);
modelS.pushToStart();
modelS.chargeVehicle();
}
}
Hierarchical inheritance
When more than one class extends from the same base class, it is referred to as hierarchical inheritance.
A
Mammal
IS ANAnimal
A
Reptile
IS ANAnimal
Multiple Inheritance
When a class is derived from more than one base class, i.e. when a class has more than one immediate parent class, this type of inheritance is called Multiple Inheritance.
A
Human
IS ANAnimal
A
Human
IS AMammal
also
Hybrid Inheritance
A combination of Multiple and Multi-level inheritance.
A
Male
IS AHuman
A
Female
IS AHuman
A
Child
comes fromMale
andFemale
Multiple and Hybrid inheritances are applicable using interfaces only.
Conclusion
Inheritance is useful for several reasons.
Inheritance can help you avoid duplicating your code which makes re-usability and maintenance easier. You don't have to write the same code over and over. You can simply inherit from the base class and it will propagate to all objects you create from that class. This saves time and effort.
In addition, inheritance makes your code extensible. Using inheritance, one can extend the base class logic in the derived class. This is an easy way to upgrade or enhance specific parts of a product without changing the core attributes. An existing class can act as a base class to derive a new class having upgraded features.
We can also implement encapsulation by keeping members private and only allowing methods in the derived class to interact with these private members.