Inheritance In Java


OOPS inheritance design pattern

Object oriented programming(OOPS) paradigm enforces code re-usability and avoid redundant code. To implement the code re-usability, OOPS introduces the concept of inheritance. Let see the “Inheritance” definition, A class that is derived from another class is called a subclass (also a derived class, extended class, or child class). The class from which the subclass is derived is called a super class (also a base class or a parent class). Excepting Object, which has no super class, every class has one and only one direct super class (single inheritance). Inheritance is everywhere in Java. It’s safe to say that it’s almost impossible to write even the tiniest Java program without using inheritance. All the classes are ultimately derived from the topmost class “Object”. In simple term, every class is implicitly a subclass of Object.

Super Class    :  The class whose features are inherited is known as super class(or a base class or a parent class).
Sub Class        : The class that inherits the other class is known as sub class(or a derived class, extended class, or child class). The subclass can add its own fields and methods in addition to the  super class fields and methods.
Re-usability     : Inheritance supports the concept of “re-usability”, i.e. when we want to create a new class and there is already a class that includes some of the code that we want, we can derive our new class from the existing class. By doing this, we are reusing the fields and methods of the existing class.
Keywords       : “extends” keyword is used to establish inheritance between super and sub classes. “super” is used to access methods of the super class from sub classes. While “this” is used to access methods of the current class.

Method Overriding : If subclass (child class) has the same method with same method signature ( method name, same argument list and return type) as declared in the super(parent) class, it is known as method overriding .  In other words, If subclass provides the specific implementation of the method that has been provided by one of its parent class, it is known as method overriding. To ensure the method is overridden and to check with parent class method signature, java provides annotation “Override“. This annotation check the method is overridden method or not. If the method is not available in parent class or signature different, it would throw compile time error. Sometimes developer wants to override super class method in sub class,  by mistake they have written method with same name and method signature is different. Developer thinks it is overridden. Actually it is not. In this scenario,if developer annotates sub class overridden method with “@Override” would throw compile time error and it would notify the developer to override the method properly.

Access modifier impact in inheritance:

public       : The member with public modifiers can be accessed by any classes. The public methods, variables or class have the widest scope.
default      : When we do not mention any access modifier, it is treated as default. It is accessible only within same package.
protected : The protected modifier is used within same package. It lies between public and default access modifier. It can be accessed outside the package but through inheritance only.
private      : The private methods, variables and constructor are not accessible to any other class. It is the most restrictive access modifier. private members are not accessible by child classes(sub classes).

Let see an example for inheritance.

package info.javaarch;
import java.util.List;

//Super class
class Insurance {
String planId;
String planName;
String companyName;
int premiumAmount = 0;
double premiumTax = 0;

public Insurance(String name, String id){ //Constructor
this.planName = name;
this.planId = id;
}

//……
public void printInsuranceInfo() {
System.out.print(” Plan name:” + planName + “,plan id:” + planId);
}

public void addPremium(int amount) {
premiumAmount = premiumAmount + amount;
premiumTax = premiumTax + (amount* 0.01); // One percent of amount would be increased in premiumTax
}

}

//Sub class 1
class MedicalInsurance extends Insurance{
List<String> diseaseList; //Lkst of diseases covered in this policy

public MedicalInsurance(String name, String id, diseaseList){
super(name,id);
this.diseaseList = diseaseList;
}
//…………

@Override
public void printInsuranceInfo() {
super.printInsuranceInfo();
System.out.print(” “, number of diseases covered” + diseaseList.size());
}

@Override
public void addPremium(int amount) {  // This implementation is problematic and let us discuss on this in next section.
super.addPremium(amount);
premiumTax = premiumTax + (amount* 0.01); // One percent of amount would be increased in premiumTax
}

}

//Sub class 2
class VehicleInsurance extends Insurance{
List<String> vehiclePartsList;

//…….

@Override
public void printInsuranceInfo() {
super.printInsuranceInfo();
System.out.print(“, vehicle parts covered” + vehiclePartsList.size());
}

@Override
public void addPremium(int amount) {
super.addPremium(amount);
premiumTax = premiumTax + (amount* 0.01); // One percent of amount would be increased in premiumTax
}

}

Here Insurance class in parent class and MedicalInsurance,VehicleInsurance are child classes. MedicalInsurance,VehicleInsurance inherits property and method from parent class. Not all the properties and methods are visible to child classes. Access modifiers of the members exposes the parent class members to child classes. private members are not accessible by child classes(sub classes).

Let us discuss inheritance design principles with above example,

Code Re-usability : Printing the plan name and plan id is only in super classes printInsuranceInfo() method. Sub class printInsuranceInfo() reuse the code by invoking super class method “super.printInsuranceInfo();”.

Access super class members: Super class members can be access by keyword “super”. “this” keyword should used to access the current class members. super keyword always refers the parent class.

Super and sub class constructors : Whenever we create object for sub classes, it would internally call any one of the sub class constructor. Adding to that each sub classes constructors internally calls super class constructor by default. Otherwise we can write sub classes constructor to call any of desired super classes constructor. Invoking super class constructor should be first line in sub class constructor like below,

public MedicalInsurance(String name, String id, diseaseList){
super(name,id);
this.diseaseList = diseaseList;
}

Overridden method and annotation: in this example, printInsuranceInfo and addPremium are overridden methods. It annotated with “@Override” to ensure proper method overridden.

@Override
public void addPremium(double amount) { // “@Override” annotation would throw error as this method with argument “double” is not available in parent class.
//…………….. // So developer can check the issue and correct the method arguments.
}

When to use inheritance: Inheritance should be created only if relationship between classes is in “IS-A” relationship. In above example, MedicalInsurance IS-A Insurance, VehicleInsurance IS-A Insurance. Do not use inheritance blindly for code re-usability.

Inheritance should be used for  Code Re-usability only if it is in “IS-A” relationship

When not to use Inheritance :

In the above example, we assign premium and calculate 1% of the premium as premium tax. Let us create object for medical insurance and addPremium,

MedicalInsurance medicalInsurance = new medicalInsurance(“Medical”,”ID2″, dielist);
medicalInsurance.addPremium(1000);
System.out.print(medicalInsurance.getPremiumAmount + “:” + medicalInsurance.premiumTax);

//Here we expect it would print “1000 : 10”. But it will print “1000 : 20”. Think what is wrong here.

Issue in the code is premiumTax calculated in 2 places one in super class and another one in sub class addPremium() methods. So it calculated twice and increased the premiumTax twice. What is wrong here. Calculating the premiumTax is not required in sub class addPremium() method. So how we can avoid this kind of issues in future? Create inheritance or overriding the super class method after completely understand the super class methods. Read complete documentation of super class implementation or look at super class code implementation. After understand it inherit and override the methods.

    “Do not ever override or use inheritance without understanding the parent(super) class implementation”.

Here we discussed on basic of inheritance in java. In next section we would discuss on multi-level inheritance and abstract classes. Kindly share if you have any comments on this. Happy Coding!!!

You may also like