In object-oriented programming (OOP), Inheritance allows reusing of software by extending an existing class members. When creating a new class, you may want the new class to inherit the properties and members of an existing class instead of implementing the same proprieties and members again in the new class. Here, the existing class is called the superclass, and the new class is called the subclass.
For example, a Circle
is a Shape
. Thus, in Java, class Circle
can be said to inherit from class Shape
. In this context, class Shape
is a superclass and class Circle
is a subclass. Some inheritance examples (superclass:subclasses):
- Student: GraduateStudent, UndergraduateStudent
- Shape: Circle, Triangle, Rectangle, Sphere, Cube
- Bank Account: Checking Account, Savings Account
- Vehicle: Car, Truck, Boat, Bicycle
To demonstrate inheritance in action, first, let us create a Vehicle class
1 2 3 4 5 6 7 |
class Vehicle { protected String licensePlate = null; public void setLicensePlate(String license) { this.licensePlate = license; } } |
In Java inheritance is declared using the extends
keyword. We now extend the Vehicle class to have Car class:
1 2 3 4 5 6 7 |
class Car extends Vehicle { protected int numberOfSeats = 0; public int getNumberOfSeats() { return this.numberOfSeats; } } |
The protected Keyword
In addition to access modifiers public and private, protected
access offers an intermediate level of access between them. Remember that a superclass’s private
members are not accessible for other classes, including its subclasses.
However, the protected
members of a superclass are accessible from its subclasses. Yet, it is different from public members, which can be accessed by any class, regardless of the inheritance relationship. The public and protected members are similar in the fact that their original access modifiers are retained in the subclasses – public members of the superclass become public members of the subclass, and protected members of the superclass become protected members of the subclass.
Overriding Method and the super
Keyword
In a subclass, Java allows the code to override (redefine) methods defined in the superclass. Using the super
keyword a subclass can access the methods in its superclass. Here is an example of using the super
keyword in a constructor and a method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Car extends Vehicle { public Car(int i_NumberOfSeats) { super(); //perform other initialization here numberOfSeats = i_NumberOfSeats; } public void setLicensePlate(String license) { super.setLicensePlate(license); } public String toString() { return "The car has " + numberOfSeats + " seats. Its license is " + licensePlate; } } |
The SportsCar class can be created by extending Car class
1 2 3 4 5 6 7 8 9 10 |
class SportsCar extends Car { double maxSpeed = 0; public SportsCar(int i_NumberOfSeats, double d_MaxSpeed) { super(i_NumberOfSeats); //perform other initialization here maxSpeed = d_MaxSpeed; } } |
When you override a method in a subclass, it is recommended to use @Override
annotation. This way, if you misspell a method name or not correctly matching the parameters, you will be warned that your method does not actually override the intended methods as you think it does. Secondly, it makes your code easier to understand because it is more obvious about which methods are overwritten.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class SportsCar extends Car { @Override public void setLicensePlate(String license) { this.licensePlate = license.toLowerCase(); } @Override public String toString() { return supper.toString() + ". Its max speed is " + maxSpeed; } } |
The final Keyword
The final
keyword has different semantic depending on the context:
- A
final
class cannot be inherited. It is useful when there is a good reason to prohibit inheritance. Technically speaking, a developer marks a class asfinal
to indicate that he has not considered or do not expect the class to be inherited. - A
final
method cannot be overriden. The design does not expect the method to be changed even in its subclasses. - A
final
variable can only be initialized once, making it safe to ensure the value cannot be changed once assigned.
A complete example
To complete this article, we will test how the objects of Car class and SportsCar class different in behavior.
Vehicle Class : Superclass
1 2 3 4 5 6 7 |
class Vehicle { protected String licensePlate = null; public void setLicensePlate(String license) { this.licensePlate = license; } } |
Car Class extending Vehicle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Car extends Vehicle { protected int numberOfSeats = 0; public Car(int i_NumberOfSeats) { super(); //perform other initialization here numberOfSeats = i_NumberOfSeats; } public void setLicensePlate(String license) { super.setLicensePlate(license); } public String toString() { return "The car has " + numberOfSeats + " seats. Its license is " + licensePlate; } public int getNumberOfSeats() { return this.numberOfSeats; } } |
SportsCar Class extending Car Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class SportsCar extends Car { double maxSpeed = 0; public SportsCar(int i_NumberOfSeats, double d_MaxSpeed) { super(i_NumberOfSeats); //perform other initialization here maxSpeed = d_MaxSpeed; } @Override public void setLicensePlate(String license) { this.licensePlate = license.toLowerCase(); } @Override public String toString() { return super.toString() + ". Its max speed is " + maxSpeed; } } |
Main Test Method
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//This class tests the above classes public class VehiclesTest { public static void main(String args[]) { Car personalCar = new Car(4); personalCar.setLicensePlate("PERSONAL-BN123"); System.out.println(personalCar); SportsCar sportsTeam = new SportsCar(2, 200); sportsTeam.setLicensePlate("SPORTS-AB989"); System.out.println(sportsTeam); } } |
Notice that the SportsCar
has it’s license lowercased and its toString()
method appends the Car
‘s toString()
with its own max speed.
The above code produce:
The car has 4 seats. Its license is PERSONAL-BN123
The car has 2 seats. Its license is sports-ab989. Its max speed is 200.0
Summary
- Inheritance reduces development time through reusing of existing code base in a hierarchical manner.
- A superclass protected members have an intermediate level of protection between public and private access. They can be accessed by its subclasses.
- Java allows overriding methods of the superclass. We can use the
super
keyword to access the superclass methods.