Inheritance with Java

 

As an object-oriented programming language, Java supports inheritance. Inheritance is the concept of deriving new classes from a base or parent class and it is incorporated into the Java language. extends keyword is used to derive a new class from a parent class.

public class A{} – Parent class

public class B extends A {} – Child class

In Java, java.lang.Object class is the parent of every object. In other words, every Java class implicitly extends java.lang.Object and every Java object is an instance of java.lang.Object. Java.lang.Object class has no superclass. The parent class can be an abstract class.

What is Java association?

The relationship between two classes is called association.

So, Student and Backpack classes are associated with each other.

What is composition

Has-A and Is-A relationships between classes

When a class A owns an instance of class B, then the relationship between classes is referred to as a Has-A relationship, in the form of A Has-A B.

public class Backpack { }

public class Student {

private Backpack backpack;

}

Here in this example, every Student instance owns a backpack. So, Student class Has-A backpack class.

Has-A relationship type is not directly linked to inheritance. It has more to do with following good Object-oriented programming principles.

If a class A implements an interface B or extends a class B, then the relationship between A and B is Is-A relationship, in the form of A Is-A B.

public class Animal {}

public class Reptile extends Animal {}

In this case, Reptile Is-A Animal.

public interface Mammal {

void printRangeInfo();

}

public Lion implements Mammal {

public void printRangeInfo() {

System.out.println(“Central and south Africa, some parts of India.”);

}

}

Here in this example, a Lion Is-A Mammal.

Is-A relationship is fundamental to Inheritance in Object-Oriented programming. A class has this relationship with every class that it inherits from. In Java, a class can implement multiple interfaces but can extend only one class. The parent class might be extending other classes or implementing other interfaces as well. In the end, the child class has the Is-A relationship with all these interfaces and parent classes that are before it in its inheritance tree.

Initializing a Child Class and Constructors

In Java, A class’ constructor implicitly invokes the constructor of the parent with the same arguments when it runs. If the parent does not have a constructor with the same arguments, the child constructor is required to explicitly call one of the existing constructors of the parent. Calling a parent constructor is done using super() method. Inside the child constructor, if it exists, the super() call is always the first statement.

Let’s take a closer look at the different variations of this.

public class A {

}

public class B extends A{

}

In this case, parent class A does not define a constructor. Therefore, it only has the default no-arg constructor. Class B extends A and does not define a constructor, either. So, everything is good.

Now, let’s add a parameterized constructor to B.

public class B extends A {

public B(int i) {

}

}

In this case, B’s constructor would implicitly have a call to its parent’s constructor with the same argument list, (int i). Class A does not define such a constructor. So, class B would not compile. For Class B to compile, it needs to call one of the existing constructors of A explicitly. A has only the public no-arg constructor. Therefore, B is required to call this constructor inside its constructor. This call is done using super() and it has to be the first statement inside the constructor method.

public class B extends A {

public B(int i) {

super();

}

}

Now, let’s consider class A does not have a default no-arg constructor but it has a parameterized constructor.

public class A {

public A(String s) {

}

}

public class B extends A {

}

B again would not compile because it has only the default no-arg constructor. This constructor implicitly calls A’s constructor with the same argument list but A does not have such a constructor. Therefore, B is required to call one of the existing constructors of its parent again. Since A has only one constructor, B’s constructor is required to make an explicit call to it with super(). This time, the parent constructor has arguments, so super() is called with arguments. B needs to call super class’ constructor with an integer. For this example, let’s consider it is convenient for B to call its parent’s constructor with integer value 2.

public class B extends A {

public B() {

super(2);

}

}

In a real example, it would make more sense to have a parameterized constructor for B.

public class B extends A {

public B(int i) {

super(i);

}

}

Now, let’s go back to Person and Employee classes and see in which order constructors are called.

Public class Person {

public firstName;

public lastName;

public age;

public Person(String firstName, String lastName, int age) {

System.out.println(“Initializing Person…”);

this.firstName = firstName;

this.lastName = lastName;

this.age = age;

}

protected void printPersonalInfo() {

System.out.println (”First name: “ + firstName + “, Last name: “ + lastName + “ “ + “, age: “ + age + “ years old.”);

}

}

public class Employee extends Person {

public double salary;

public String companyName;

public Employee(String firstName, String lastName, int age), double salary, String companyName) {

System.out.println(“Initializing Employee…”);

}

public void printEmploymentInfo() {

super.personalInfo();

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName + “ with salary $“ + salary);

}

public static void main(String [] args) {

System.out.println(“Personal information”);

Employee employee = new Employee(“James”, “West”, 48);

employee.salary = 85000;

employee.companyName = “My Company Inc.”;

employee.printEmploymentInfo();

}

}

The output would be

Personal information

Initializing Person…

Initializing Employee…

First name: James, LastName: West, Age: 48

James West works at My Company with salary $85000.

This time Person has a constructor with 3 arguments. Employee defines a constructor with 3 arguments.The Employee constructor makes a call to Person’s constructor on the first line to set firstName, lastName and age properties using Person’s constructor as the call to parent’s constructor needs to be the first statement in the child’s constructor. At that point, salary and companyName fields have their default values. Following that, salary and companyName fields are set on the new Employee objects in the main method and printEmploymentInfo method is invoked.

When we look at the output, we see that even though there’s no explicit call, the Employee constructor first calls its parent’s constructor implicitly before it runs.

Initializing Person… → Person constructor is invoked first

Initializing Employee… → Employee constructor runs after the Person constructor runs

Instead of setting the fields of Employee object first through parents constructor and then explicitly, it would make more sense to modify Employee constructor to set all the fields.

public class Employee extends Person {

public double salary;

public String companyName;

public Employee(String firstName, String lastName, int age), double salary, String companyName) {

super(firstName, lastName, age);

System.out.println(“Initializing Employee…”);

this.salary = salary;

this.companyName = companyName;

}

public void printEmploymentInfo() {

super.personalInfo();

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName + “ with salary $“ + salary);

}

public static void main(String [] args) {

System.out.println(“Personal information”);

Employee employee = new Employee(“James”, “West”, 48, 85000, “My Company Inc.”);

employee.firstName = “James”;

employee.lastName = “West”;

employee.age = 48;

employee.company = “My Company Inc.”

employee.salary = 85000;

employee.printEmploymentInfo();

}

}

This time Employee defines a constructor with 5 arguments. The Employee constructor makes a call to Person’s constructor on the first line to set firstName, lastName and age properties using Person’s constructor as the call to parent’s constructor needs to be the first statement in the child’s constructor. Following that, the Employee constructor itself sets salary and company fields.

The output of the two programs would be the same.

In an inheritance tree, when a child object’s constructor is called, its highest parent’s constructor runs first, followed by the constructor of its immediate subclass and this goes on this way until the child object’s class completes running.

Method overriding

In Java, a child class can redefine the body of an instance method that was declared by one of its parent. This feature is called method overriding. Method overriding gives the child class to redefine a behavior defined by its parent according to its own needs.

A child class can override a method defined in its parent class based on following conditions:

  • The method to be overridden is accessible by the child class. That means, its access modifier should be public or protected. Private methods cannot be overridden.
  • The child method declares the overriding method with the same name and the same list of arguments
  • The access modifier of the overriding method cannot be more restrictive that the parent class method’s. If the child class declares a method that has the same name and argument list as a parent class method, that causes a compiler error.

Let’s now define an Employee class.

public class Employee {

void printEmployeeInfo(String firstName, String lastName, String companyName) {

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName);

}

}

public class FulltimeEmployee extends Employee {

public void printEmployeeInfo(String firstName, String lastName, String companyName) {

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName + “ full time”);

}

public static void main(String [] args) {

Employee employee = new Employee();

employee.(“Michael”, “Moore”, “OldCompany Inc.”);

FulltimeEmployee fulltimeEmployee = new FulltimeEmployee();

fulltimeEmployee.printEmployeeInfo(“Jennifer”, “Owen”, “MyCompany Inc.”);

}

}

Here FulltimeEmployee class’ printEmployeeInfo method overrides that of the Employee class. printEmployeeInfo() method of the parent class is declared with default access, so it is accessible to its subclasses. FulltimeEmployee class overrides the method as public which is less restrictive than default. Here, in this case, the child class might declare the overriding method with the default access or protected, too, not making it more restrictive. But if the access modifier in the child class for the method was private, that would cause a compiler error.

The output from running Fulltimemployee class would be:

Michael Moore works at OldCompany Inc.

Jennifer Owen works at MyCompany Inc. fulltime.

When the method is called through an instance of the parent class, the original version is called. However, if it is called through an instance of the subclass, the overridden version is called.

Method hiding

Method overriding applies only to instance methods. The static methods defined by a parent class belong to all instances of the parent class. Because all children of a class have Is-A relationship with their parent, they can call the static methods declared by the parent class as long as they have access to it. If the child class redefines a static method defined in the parent class, this is called method overriding. In this case, the child class does not override but hides the original static method. Which version is invoked depends on whether it is called from the parent class or the child class.

Let’s add a static method to the Employee class and its subclass.

public class Employee {

static void printSalaryInfo(double salary) {

System.out.println(“The employee’s salary is $“ + salary);

}

void printEmployeeInfo(String firstName, String lastName, String companyName) {

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName);

}

}

public class FulltimeEmployee extends Employee {

public void printEmployeeInfo(String firstName, String lastName, String companyName) {

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName + “ full time”);

}

public static void main(String [] args) {

Employee.printSalaryInfo(85000);

FulltimeEmployee.printSalaryInfo(100000);

}

}

Because printSalaryInfo has default access, it is accessible by FulltimeEmployee class and it can be called by this class in a static way. The output would be:

The employee’s salary is $85000

The employee’s salary is $100000

Now, let’s add hide this method in the child class.

public class FulltimeEmployee extends Employee {

public static void printSalaryInfo(double salary) {

System.out.println(“The employee’s full time salary is $“ + salary);

}

public void printEmployeeInfo(String firstName, String lastName, String companyName) {

System.out.println(firstName + “ “ + lastName + “ works at “ + companyName + “ full time”);

}

public static void main(String [] args) {

Employee.printSalaryInfo(85000);

FulltimeEmployee.printSalaryInfo(100000);

}

}

The employee’s salary is $85000

The employee’s full time salary is $100000

FulltimeEmployee class now has its version of the printSalaryInfo method. When it calls the printSalaryInfo method, it calls the hiding version. Employee class still calls its own version. Because Employee is not a FulltimeEmployee, it can’t call its child’s version of printEmployeeInfo.

Accessing superclass methods

A subclass has access to the public and protected fields and methods of its parent class.

super keyword

super keyword in Java is used to refer to the immediate super class of a class. A method declared public, protected or with default access can be called directly from the subclass using super keyword. Super acts as a reference to an instance of the parent object and using the . operator, instance methods of the parent class can be invoked.

An method declared public, protected or with default access can be called directly from the subclass using super keyword. Super acts as a reference to an instance of the parent object and using the . operator, instance methods of the parent class can be invoked.

Let’s change FulltimeEmployee class to make use of the methods defined by its parent, instead of overriding them.

public class FulltimeEmployee extends Employee {

public void printFulltimeEmployeeInfo(String firstName, String lastName, String company, double salary, int teamSize) {

System.out.println(“This information is for a fulltime employee”);

super.printEmployeeInfo(firstName, lastName, company);

super.printSalaryInfo(salary);

System.out.println(“This employee works in a team of “ + teamSize + “ people.”);

}

public static void main(String [] args) {

FulltimeEmployee fulltimeEmployee =new FulltimeEmployee();

fulltimeEmployee.printFulltimeEmployeeInfo(“Jennifer”, “Owen”, “MyCompany Inc.”, 85000, 10);

}

}

Running FulltimeEmployee class would give the output

This information is for a full time employee

Jennifer Owen works at MyCompany Inc. full time

The employee’s full time salary 85000

This employee works in a team of 10 people.

In FulltimeEmployee class, inside printFulltimeEmployee method, Employee class’ printEmployeeInfo and printSalaryInfo methods are called using super as a reference to Employee. These two methods are visible to FulltimeEmployee class. super cannot be used to call private methods of a superclass.

%d bloggers like this: