Keyword super and its usage

The keyword super represents the parent class object. To demonstrate its usage, let's create a programming model of a vehicle, a truck, and a car. Let's start with a vehicle. The class that models it calculates the speed of the vehicle it can reach in a specified period of time, in seconds. It looks as follows:

public class Vehicle {
private int weightPounds, horsePower;
public Vehicle(int weightPounds, int horsePower) {
this.weightPounds = weightPounds;
this.horsePower = horsePower;
}
protected int getWeightPounds(){ return this.weightPounds; }
protected double getSpeedMph(double timeSec, int weightPounds){
double v =
2.0 * this.horsePower * 746 * timeSec * 32.174 / weightPounds;
return Math.round(Math.sqrt(v) * 0.68);
}
}

The class has two properties set by the constructor and two protected methods. Protected is an access modifier that means the method can be accessed only by the children of this class. We will talk more about access modifiers in Chapter 7Packages and Accessibility (Visibility)

The Car and Truck classes(which model a car and a truck) can extend this class and inherit the two protected methods, so they can be used for calculating the car and truck speed. There are other possible ways to organize code. Generally, using aggregation (setting the Vehicle object as a field value of the Car and Truck classes ) is preferred, unless one has a reason to have a common parent (we will talk about this in Chapter 8, Object-Oriented Design (OOD) Principles). But for now, let's assume that we have a good reason to use inheritance, so we can demonstrate the use of the keyword super. And it sort of makes sense, in general: a car and a truck are both vehicles, aren't they?

So, here is how the class Truck looks:

public class Truck extends Vehicle {
private int payloadPounds;
public Truck(int payloadPounds, int weightPounds, int horsePower) {
super(weightPounds, horsePower);
this.payloadPounds = payloadPounds;
}
public void setPayloadPounds(int payloadPounds) {
this.payloadPounds = payloadPounds;
}
protected int getWeightPounds(){
return this.payloadPounds + getWeightPounds();
}
public double getSpeedMph(double timeSec){
return getSpeedMph(timeSec, getWeightPounds());
}
}

The class has one property: the current payload weight the truck has. It factors in the speed calculations. The heavier the payload, the longer it takes the truck to reach the same speed. Since the payload weight may change any time after the object is created, the setter for the payload weight is provided, and the protected method getWeightPounds() returns the total weight of the vehicle with its payload. The main method and the purpose of all the modeling is the method getSpeedMph(), which returns the truck's speed (in miles per hour) it can reach in timeSec seconds after it starts.

But, we now discuss the use of the keyword super. You probably noticed that it was already included in the constructor. As you can guess, it represents the constructor of the parent class. In such cases, the keyword super has to be the first line of the child constructor. We will talk about it in the next section, Constructors

And here is the class that models car speed:

public class Car extends Vehicle {
private int passengersCount;
public Car(int passengersCount, int weightPounds, int horsePower) {
super(weightPounds , horsePower);
this.passengersCount = passengersCount;
}
public void setPassengersCount(int passengersCount) {
this.passengersCount = passengersCount;
}

protected int getWeightPounds(){
return this.passengersCount * 200 + getWeightPounds(); }
public double getSpeedMph(double timeSec){
return getSpeedMph(timeSec, getWeightPounds());
}
}

It looks very similar to the class Truck. The only difference is the way the payload is calculated. It is assumed that each passenger ways 200 pounds. Thus, when the passenger count is set, the payload is calculated as the number of passengers multiplied by 200.

Both classes—Car and Truck—have a defect (also called a bug, or an error). To discover it, let's try to calculate a truck's speed 10 seconds from the start time by running the following code:

Truck truck = new Truck(500, 2000, 300);
System.out.println(truck.getSpeedMph(10));

If we do that, the result will be a StackOverflowError error:

A stack is the JVM memory area where the chain of method calls is stored. The last method name called is stored on the top. When the last method called is completed, its name is removed from the top and the next method is executed, and so on until the stack is empty—that is, when the main() method is completed—and the application completes its execution (JVM exits). 

In our case, the stack grew uncontrollably and eventually overflowed. The JVM could not add another method name on the top of the stack and exited with an error. The reason for such a condition is a recursive call our code requested in this line:

protected int getWeightPounds(){ 
return this.payloadPounds + getWeightPounds();
}

We wanted to add the truck payload to the weight of the vehicle itself, stored as the property in the parent class, but instead told the JVM to call the same method, which calls itself recursively, because this method is overridden and has the same name in the child class. That is where the keyword super comes to the rescue. By adding it in front of the methogetWeightPounds()we tell the JVM to call not the child's method, but the parent's one: 

protected int getWeightPounds(){ 
return this.payloadPounds + super.getWeightPounds();
}

If  we run the same code again, we will get the expected result:

Well, our speed calculating formula seems over-optimistic. But who knows? Maybe by the time the book is printed, electric trucks will be closing in on this speed or hyperloop traffic will get there.

Also, please notice that we have not added super in front of the same method in the code that calculates speed:

public double getSpeedMph(double timeSec){
return getSpeedMph(timeSec, getWeightPounds());
}

That is because we do not want to call the method of the parent class. Instead, we would like to get the weight from its overridden version in the child class. To make sure, and to avoid confusion by making code more easily readable, we could add the keyword this in front of it: 

public double getSpeedMph(double timeSec){
return getSpeedMph(timeSec, this.getWeightPounds());
}

In fact, that is one of the best practices that we recommend to follow at all times.

That concludes the discussion of the use of the keyword super. We will see it again, and the keyword this, in the Constructors section too, where we are going to explain how the constructors do their job and what a default constructor is.