Inheritance in Java

Inheritance is one of the core concepts of an object-oriented language such as Java. Inheritance allows a new class to extend from an existing class known as the parent class.

So when do we use inheritance? Consider a scenario where a vehicle describes a very general transportation model, then comes a car, bicycle, and truck. These vehicles are specialized, so they have the general characteristics of a vehicle. To understand this concept in simple terms, the vehicle is a base class, and car, bicycle, and truck are the derived classes.

Syntax of Inheritance

In Java, when we want to inherit a class we use the extends keyword as shown below.

public class bicycle extends vehicle

In this code, the vehicle is the superclass or the base class and the bicycle is a subclass or a derived class. Let’s discuss a small chunk of code to see how inheritance really works in java.

/**
 A class that holds a grade for a graded activity.
 */

 public class GradedActivity
 {
 private double score; // Numeric score

 /**
 The setScore method sets the score field.
 @param s The value to store in score.
 */

 public void setScore(double s)
 {
 score = s;
 }

 /**
 The getScore method returns the score.
 @return The value stored in the score field.
 */
public double getScore()
 {
 return score;
 }

 /**
 The getGrade method returns a letter grade
 determined from the score field.
 @return The letter grade.
 */

 public char getGrade()
 {
 char letterGrade;

 if (score >= 90)
 letterGrade = 'A';
 else if (score >= 80)
 letterGrade = 'B';
 else if (score >= 70)
 letterGrade = 'C';
 else if (score >= 60)
 letterGrade = 'D';
 else
 letterGrade = 'F';

 return letterGrade;
 }
 }

/**
 This class determines the grade for a final exam.
 */

 public class FinalExam extends GradedActivity
 {
 private int numQuestions; // Number of questions
 private double pointsEach; // Points for each question
 private int numMissed; // Questions missed

 /**
 The constructor sets the number of questions on the
 exam and the number of questions missed.
 @param questions The number of questions.
 @param missed The number of questions missed.
 */

 public FinalExam(int questions, int missed)
 {
 double numericScore; // To hold a numeric score

 // Set the numQuestions and numMissed fields.
 numQuestions = questions;
 numMissed = missed;

 // Calculate the points for each question and

 // the numeric score for this exam.
 pointsEach = 100.0 / questions;
 numericScore = 100.0 - (missed * pointsEach);

 // Call the inherited setScore method to
 // set the numeric score.
 setScore(numericScore);
 }

 /**
 The getPointsEach method returns the number of
 points each question is worth.
 @return The value in the pointsEach field.
 */

 public double getPointsEach()
 {
 return pointsEach;
 }

 /**
 The getNumMissed method returns the number of
 questions missed.
 @return The value in the numMissed field.
 */

 public int getNumMissed()
 {
 return numMissed;
 }
 }

Notice that the GradedActivity class’s score field is not among the variables of the FinalExam class because the score field is private. You will also notice that the GradedActivity’s constructor is not listed among the members of the FinalExam class. This is because superclass constructors are not inherited. After all, their purpose is to construct objects of the base class.

Let’s dive deeper in this example of inheritance.

The constructor of the FinalExam class accepts two arguments: the number of test questions on the exam and the number of questions missed by the student. These values are assigned to the numQuestions and numMissed fields of the class. The numeric score is also calculated in the constructor. Finally, a function is called with the name of setScore, and it has been inherited from the base class, i.e., gradedActivity.

How constructors work

How do the constructors work together when one class inherits from another? Interesting question!

In an inheritance relationship, the base class constructor always executes before the constructor of the derived class. In this scenario, the GradedActivity class has only one constructor, which is the default constructor that Java automatically generated. Thus, when a FinalExam object is created, the default constructor of the base class(GradedActivity) is executed just before the constructor of the derived class(FinalExam).

The working of the constructors is demonstrated by the code below

public class SuperClass1
 {
 /**
 Constructor
 */

 public SuperClass1()
 {

  System.out.println("This is the " +
 "superclass constructor.");
 }
 }

 public class SubClass1 extends SuperClass1
 {
 /**
 Constructor
 */

 public SubClass1()
 {
 System.out.println("This is the " +
 "subclass constructor."); }
}

/**
This program demonstrates the order in which
 superclass and subclass constructors are called.
 */

 public class ConstructorDemo1
 {
 public static void main(String[] args)
 {
   //creating base class object
 SubClass1 obj = new SubClass1();
 }
 }

Program Output
This is the superclass constructor.
This is the subclass constructor.

Applying Polymorphism(Overloading & Overriding)

Let’s start with the concept of overriding. So overriding is when a derived class may have a method with the same signature as a base class method. In Java @override annotation is used to override functions of the base class however, it is not necessary. Overloading is when a method has the same name as one or more other
methods, but a different parameter list. However, overloading occurs within the function of the same class and overriding occurs between the functions of the base and the derived class.

The distinction between overloading and overriding is important because it can affect the accessibility of base class methods in a derived class. For example, when a derived class overloads a superclass method, both methods may be called the derived class object. However, when a base class overrides a derived class method, only the derived class’s version can be called with a derived class object.

The concept of polymorphism is demonstrated in the code below.

public class SuperClass3
 {
 /**
 This method displays an int.
 @param arg An int.
 */

 public void showValue(int arg)
 {
 System.out.println("SUPERCLASS: " +
 "The int argument was " + arg);
 }

 /**
 This method displays a String.
 @param arg A String.
 */

 public void showValue(String arg)
 {
 System.out.println("SUPERCLASS: " +
 "The String argument was " + arg);
 }
}

public class SubClass3 extends SuperClass3
 {
 /**
 This method overrides one of the superclass methods.
 @param arg An int.
 */

 @Override
 public void showValue(int arg)
 {
 System.out.println("SUBCLASS: " +
 "The int argument was " + arg);
 }

 /**
 This method overloads the superclass methods.
 @param arg A double.
 */

 public void showValue(double arg)
 {
 System.out.println("SUBCLASS: " +
 "The double argument was " + arg);
 }
}

/**
 This program demonstrates the methods in the
 SuperClass3 and SubClass3 classes.
 */

 public class ShowValueDemo
 {
public static void main(String[] args)
{
  
 // Create a SubClass3 object.
 SubClass3 myObject = new SubClass3();
//When an int argument is passed to showValue, the subclass's method is called because it
//overrides the superclass method
 myObject.showValue(10); // Pass an int.
 myObject.showValue(1.2); // Pass a double.
 myObject.showValue("Hello"); // Pass a String.
 }
 }

Multilevel Inheritance

Multilevel inheritance is like a chain of inheritance in which one class inherits from a second class, inheriting from a third class. A good example of multilevel inheritance is shown below.

 /**
 This class holds a numeric score and determines
 whether the score is passing or failing.
 */

 public class PassFailActivity extends GradedActivity
 {
 private double minPassingScore; // Minimum passing score

 /**
 The constructor sets the minimum passing score.
 @param mps The minimum passing score.
 */

 public PassFailActivity(double mps)
 {
 minPassingScore = mps;
 }

 /**
 The getGrade method returns a letter grade
 determined from the score field. This
 method overrides the superclass method.
 @return The letter grade.
 */

 @Override
 public char getGrade()
 {

 char letterGrade;

 if (super.getScore() >= minPassingScore)
 letterGrade = 'P';
 else
 letterGrade = 'F';

 return letterGrade;
 }
 }
 
/**
 This class determines a passing or failing grade for
 an exam.
 */

 public class PassFailExam extends PassFailActivity
 {
 private int numQuestions; // Number of questions
 private double pointsEach; // Points for each question
 private int numMissed; // Number of questions missed

 /**
 The constructor sets the number of questions, the
 number of questions missed, and the minimum passing
 score.
 @param questions The number of questions.
 @param missed The number of questions missed.
 @param minPassing The minimum passing score.
 */

 public PassFailExam(int questions, int missed,
 double minPassing)
 {
 // Call the superclass constructor.
 super(minPassing);

 // Declare a local variable for the score.
 double numericScore;

 // Set the numQuestions and numMissed fields.
 numQuestions = questions;
 numMissed = missed;

 // Calculate the points for each question and
 // the numeric score for this exam.
 pointsEach = 100.0 / questions;
 numericScore = 100.0 - (missed * pointsEach);

 // Call the superclass's setScore method to
 // set the numeric score.
 setScore(numericScore);
 }

 /**
 The getPointsEach method returns the number of
 points each question is worth.
 @return The value in the pointsEach field.
 */

 public double getPointsEach()
 {
 return pointsEach;
 }

 /**
 The getNumMissed method returns the number of
 questions missed.
 @return The value in the numMissed field.
 */

 public int getNumMissed()
 {
 return numMissed;
 }
 }
 
import java.util.Scanner;

 /**
 This program demonstrates the PassFailExam class.
 */

 public class PassFailExamDemo
 {
 public static void main(String[] args)
 {
 int questions; // Number of questions
 int missed; // Number of questions missed
 double minPassing; // Minimum passing score

 // Create a Scanner object for keyboard input.
 Scanner keyboard = new Scanner(System.in);

 // Get the number of questions on the exam.
 System.out.print("How many questions are " +
 "on the exam? ");
 questions = keyboard.nextInt();

 // Get the number of questions missed.
 System.out.print("How many questions did " +
 "the student miss? ");
 missed = keyboard.nextInt();

 // Get the minimum passing score.
 System.out.print("What is the minimum " +
 "passing score? ");
 minPassing = keyboard.nextDouble();

 // Create a PassFailExam object.
 PassFailExam exam =
 new PassFailExam(questions, missed, minPassing);

 // Display the points for each question.
 System.out.println("Each question counts " +
 exam.getPointsEach() + " points.");

 // Display the exam score.
 System.out.println("The exam score is " +
 exam.getScore());

 // Display the exam grade.
 System.out.println("The exam grade is " +
 exam.getGrade());
 }
 }

Conclusion

Inheritance is a very vast topic when discussing object-oriented principles, and it also involves a foundation to other principles like polymorphism and abstraction. Therefore, the examples in this article are elaborate and discuss the in-depth approach to inheritance and polymorphism.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *