Java #13 - Inheritance (Part - 1)

Introduction

Inheritance is a fundamental concept in object-oriented programming that enables you to create new classes derived from existing classes. It allows you to reuse and extend the functionality of existing classes, which helps to reduce code duplication and improve code maintainability.

Inheritance is one of the critical features of object-oriented programming and is used to represent the is-a relationship between objects. The derived class, known as the subclass, inherits the properties and behaviors of the base class, known as the superclass. The subclass can add its own properties and behaviors to the inherited ones and can also override the methods of the superclass to change its behavior.

By using inheritance, we can reduce code duplication, increase code reuse, and improve the overall design and structure of your code. It is an essential tool for building complex and flexible software systems.

In Java, a class that is inherited is called a superclass and the class that inherits is called a superclass i.e. a subclass is a specialized version of a superclass. To inherit one class into another we need to use extends keyword.

class subclass-name extends superclass-name{
    //body of class 
}

Important Points

  1. A subclass can access a non-private member of a superclass directly.

  2. A class can only inherit one superclass. Java does not support the inheritance of multiple super classes into a single subclass.

  3. No class can be a superclass in itself.

Example

We are creating 3 classes as shown below, where the Person class is in the superclass of Student and Employee. Below are details of the respective fields and methods.

Person.java

public class Person {
    private String name;
    private int age;
    private String address;

    public Person(String name,int age,String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public void introduce(){
        System.out.println("My name is "+name+ ", I am "+age+" years old and my address is "+address);
    }
}

Student.java

public class Student extends Person{
    private int semester;
    private float gpa;

    public Student(String name,int age,String address,int semester,float gpa){
        super(name,age,address); //**
        this.semester = semester;
        this.gpa = gpa;
    }

    public void studentDetails(){
        System.out.println("I study at "+semester+ " semester and my gpa is "+gpa);
    }
}

**super keyword is explained in the below section.

Employee.java

public class Employee extends Person{
    private String department;
    private float yearOfExperience;

    public Employee(String name,int age,String address,String department,float yearOfExperience){
        super(name,age,address);
        this.department = department;
        this.yearOfExperience = yearOfExperience;
    }

    public void employeeDetails(){
        System.out.println("I work at "+department+ " department and having "+yearOfExperience+" years of experience");
    }
}

StudentAndEmployeeDemo.java

public class StudentAndEmployeeDemo {
    public static void main(String[] args) {
        Student student = new Student("XYZ",21,"India",7,8);
        student.introduce();
        student.studentDetails();
        Employee employee = new Employee("ABC",30,"India","Eng",6);
        employee.introduce();
        employee.employeeDetails();
    }
}

Output

A superclass variable can reference a subclass object

A reference variable of a superclass can be assigned a reference to any subclass derived from that superclass.

Let's say we have below class hierarchy, where A is a superclass and B is the subclass.

A <- B

In this case, we can write the following statement

A a = new B(); //OR

B b = new B();
a = b;

How this works in Java?

A superclass variable can reference a subclass object through a process called upcasting. Upcasting is the act of casting a subclass object to a superclass type, allowing the superclass variable to reference the object.

It is important to note that it is the type of reference variable - not the type of object that it refers to - that determines what members can be accessed. When a reference to a subclass object is assigned to a superclass reference variable, it will have access only to those parts of the object defined by the superclass as the superclass does not have knowledge of any members that are only defined in the subclass.

Let's see an example of the above statement. In the below code of the previous section example, we are using the reference variable of superclass Parent and assigning it a reference to Student subclass and accessing introduce a () method which was defined in superclass but it cannot access studentDetails() which is defined in Student (subclass) class.

super keyword

The super keyword is used to refer to the superclass of a subclass. Below are uses of 'super' keyword in Java:

Call a superclass constructor

  • Using the super keyword, we can call the superclass constructor from the subclass constructor using the below statement:

  •   super(arg-list);
    
  • super() must always be the first statement executed inside a subclass constructor.

  • When a subclass calls super(), it is calling the constructor of its immediate superclass.

Call a superclass member (method or variable)

  • The super keyword can also be used to call a method and variables defined in the parent class.

  • It is useful in a situation where member names of a subclass hide members by the same name in the superclass.

Multilevel Inheritance

Multi-level inheritance is a type of inheritance where a derived class is inherited from a base class, and this derived class is then used as the base class for another derived class. This creates a hierarchy of classes with a parent-child relationship. Multi-level inheritance can be useful for creating complex class hierarchies and reusing code across different levels of the hierarchy.

  • Each subclass inherits all of the traits found in all of its superclasses.

For example, let's say we have 3 classes A, B, and C where A is the parent of B and B is the parent of C.

C inherits all aspects of B & A

A.java

public class A {
    int a;

    A(int a){
        System.out.println("Inside class A constructor");
        this.a =a;
    }

    void displayA(){
        System.out.println("Value of a is: "+a);
    }
}

B.java

public class B extends A{
    int b;

    B(int a, int b) {
        super(a);
        System.out.println("Inside class B constructor");
        this.b = b;
    }

    void displayB(){
        System.out.println("Value of b is: " + b);
    }
}

C.java - In class C, all non-private members of A&B are accessible as shown in displayAll() method.

public class C extends B{
    int c;

    C(int a, int b,int c) {
        super(a,b);
        System.out.println("Inside class C constructor");
        this.c = c;
    }

    void displayC(){
        System.out.println("Value of c is: " + c);
    }

    void displayAll(){
        displayA();
        displayB();
        display();
    }
}

MultilevelInheritanceDemo.java

public class MultilevelInheritanceDemo {
    public static void main(String[] args) {
        C c = new C(10,20,30);
        c.displayAll();
    }
}

Output

Inside class A constructor
Inside class B constructor
Inside class C constructor
Value of a is: 10
Value of b is: 20
Value of c is: 30

As you can see in the above output, below are the order of execution of the constructor

  1. The constructor of the topmost superclass (A) is executed first.

  2. Then, the constructor of the immediate superclass (B) is executed.

  3. Finally, the constructor of subclass (C) is executed.

This order ensures that all the super classes are initialized before the subclass. It's worth noting that the constructors of each class can also call their superclass constructor using the super() keyword, which allows them to perform additional initialization that's defined in their superclass.

Did you find this article valuable?

Support subodh's blog by becoming a sponsor. Any amount is appreciated!