Last time we looked at the Employee class as superclass, Secretary, Lawyer, etc, as its subclasses, using the code online. This time we looked at the code in the book, which is somewhat different, but covers the same ideas.
Be sure you understand the terminology on pg. 561 and 563.
Pg. 566: There is a rule that the LegalSecretary should get a salary 5000 above that of an ordinary employee. To code this rule, we need to access getSalary in Employee in the code for getSalary in LegalSecretary. How do we do this?
Answer: use “super”, already seen in use for calling the superclass constructor in ColoredPoint last time.
See the code on pg. 566.
We need a meatier example, one that has fields as well as methods (i.e., state as well as behavior). Let’s redo the Vehicle-Automobile-Truck example using inheritance.
Setup
· An Automobile IS-A Vehicle, a Truck IS-A Vehicle
· Automobile and Truck both have a make and a VIN, so have methods getMake() and getVIN() in common.
· An Automobile additionally has a model and a year, so methods getModel() and getYear(().
· A Truck additionally has a truckClass (a number 1-8), so method getTruckClass().
Previously, we used the two methods that are in common to define an interface Vehicle, and added “implements Vehicle” to both Automobile and Truck.
Note that we still needed code for getMake() and getVIN() in both Automobile.java and Truck.java—this is duplicated code (although quite simple code, so not so much a crime).
Now, let’s make Vehicle.java a base class, i.e. a superclass to Automobile.java and Truck.java, and see the resulting code reuse. These files are available in vehicleInheritance
Vehicle.java now has code for the common methods, not just method headers as we had in the old interface. Also it has its own constructor, not allowed in an interface. In other words, it’s a normal class describing a Vehicle, the common part of Automobile and Truck:
public class Vehicle
{
private String
make;
private String vin;
public Vehicle(String
make0, String vin0)
{
make = make0;
vin = vin0;
}
public String
getMake() { return make;
}
public String getVIN() {
return vin; }
}
Automobile now can obtain getMake and getVIN by inheritance, so it doesn’t have code for them. It doesn’t need make and vin, because they are held in Vehicle and thus are in Automobile as well, also obtained by inheritance. The Automobile constructor needs to specify all four fields to fully define an Automobile, and two of these belong to the Vehicle part, so they need to be passed into the superclass constructor, called using the “super” keyword.
public class Automobile extends Vehicle
{
private String model;
private int year;
public Automobile(String make0, String model0, int year0, String vin0)
{
super(make0, vin0); // call the superclass constructor to save make and vin for this object
model = model0;
year = year0;
}
public String getModel() { return model; }
public int getYear() { return year; }
}
Similarly Truck only needs its specific field and specific method:
public class Truck extends Vehicle
{
private int tClass;
public Truck(String make0, int class0, String vin0)
{
super(make0, vin0);
tClass = class0;
}
public int getTruckClass() { return tClass; }
}
Note there is no overriding going on here. We are seeing code reuse, because the getMake() and getVIN() code in Vehicle.java is also being used for Automobile and Truck.
Client Code for
Vehicle
We can construct an Automobile and a Truck:
Automobile car1 = new Automobile(“Ford”, “Taurus”, 2010, “1G2…”);
Truck truck1 = new Truck(“Chevrolet”, 3, “1G1…”);
(We can also construct a Vehicle object, using a make and VIN)
Now since an Automobile IS-A Vehicle, we can put:
Vehicle v1 = car1; // end up with Vehicle ref v1 pointing to an Automobile object
Vehicle v2 = truck1; // end up with Vehicle ref v2 pointing to a Truck object
With v1 and v2, we can call the methods of Vehicle: v1.getMake() for example. We can’t do v1.getModel(), however, even though the object is in fact an Automobile, because the reference is of type Vehicle.
We can cast back to Automobile and call getModel, however: ((Automobile)v1).getModel() will work, assuming v1 is pointing to an Automobile object. If it is actually pointing to a Truck, an exception will be thrown.
The ability to call the Vehicle methods across Automobiles and Trucks is very useful, as we have already seen with interfaces. We can write a method to count all the Fords in an ArrayList<Vehicle>, or locate a Vehicle by VIN.