Inheritance and overriding inherited methods

 

Overview

Object-oriented design implements two simple relationships:

"has a"    and    "is a"

You have already seen many examples of the "has a" relationship. It is implemented by the instance variables of a class. For example, consider the following class for maintaining and processing certain Vehicle data:

class Vehicle {
 
private String description;
  private int capacity;
  private double maxSpeed;

  public Vehicle(String iDescription, int iCapacity, double iMaxSpeed) {
    setDescription(iDescription);
    setCapacity(iCapacity);
    setMaxSpeed(iMaxSpeed);
  }
  public void setDescription(String nDescription) {
    description = nDescription;
  }
  public boolean setCapacity(int nCapacity) {
    if (nCapacity >= 0) {
      capacity = nCapacity;
      return true;
    }
    else
      return false;
    }
  public boolean setMaxSpeed(double nMaxSpeed) {
    if (nMaxSpeed > 0) {
      maxSpeed = nMaxSpeed;
      return true;
    }
    else
      return false;
  }
  public String getDescription() {
    return description;
  }
  public int getCapacity() {
    return capacity;
  }
  public double getMaxSpeed() {
    return maxSpeed;
  }
}

According to this class definition, a Vehicle "has a" description, "has a" passenger capacity, and "has a" maximum speed. Notice that the relationship can be implemented by either a primitive variable or a reference to an object of another class (a String object is used to maintain the Vehicle description).

While the "has a" relationship is implemented through the instance variables of a class, the "is a" relationship is implemented by extending an existing class.

 

Extending a class

The class hierarchy would actually be

Object

\

Vehicle

 

\

Bicycle

indicating that a Bicycle "is a" Vehicle and a Vehicle "is an" Object. As a custom class, the Vehicle class is automatically an extension of Java's Object class and inherits all its features. The Object class is the "root" of the class hierarchy.

In Java, a class can never have more than one superclass. This is called "single inheritance" and is a fundamental difference between Java and C++ (which permits "multiple inheritance).

While a Java class can have only one superclass, it can be extended to have any number of subclasses. For example, the Vehicle class can be extended to create classes such as AirPlane, Automobile, HotAirBalloon, OxCart, etc.

A class inherits all features of the classes above it in the class hierarchy. Such classes are referred to as its "ancestors".

  class Bicycle extends Vehicle

To accomplish this, the first thing each subclass constructor MUST do is call its superclass constructor as shown by this diagram:

 

Bicycle

Vehicle

Object

constructor

constructor

constructor

1) Call superclass constructor

-->

1) Call superclass constructor

-->

Complete construction

2) Complete construction

<--

2) Complete construction

<--

 

The call to the default (no argument) superclass constructor is automatically generated by the Java compiler. This makes it easy to define a first-generation custom class, such as Vehicle. It needn't be concerned with calling the constructor of the Object class because it happens automatically.

When extending a class, it is necessary to call a superclass constructor that accepts parameters. To do so, the call must be explicitly coded as the first statement within the constructor. The syntax of the call is as follows:

super(arguments);

The keyword super always references the immediate superclass of the current object. When used as a method name, it indicates a call to the superclass constructor. Based upon the arguments being passed, the correct overloaded superclass constructor will be called.

public class App {
  public static void main(String[] args) {
    Bicycle bike = new Bicycle("Mary's old bike", 1, 15.5, 14, true);
    Utility.skip();
    System.out.println("        Description: " + bike.getDescription());
    System.out.println("     Wheel diameter: " + bike.getWheelDiameter());
    System.out.println("          Top speed: " + bike.getMaxSpeed());
    bike.setDescription("Mary's modified bike");
    bike.setWheelDiameter(18);
    bike.setMaxSpeed(22.5);
    Utility.skip();
    System.out.println("        Description: " + bike.getDescription());
    System.out.println("     Wheel diameter: " + bike.getWheelDiameter());
    System.out.println("          Top speed: " + bike.getMaxSpeed());
    Utility.skip();
    System.out.println(" Object information: " + bike.toString());
  }
}

class Vehicle {
  private String description;
  private int capacity;
  private double maxSpeed;
  public Vehicle(String iDescription, int iCapacity, double iMaxSpeed) {
    setDescription(iDescription);
    setCapacity(iCapacity);
    setMaxSpeed(iMaxSpeed);
  }
  public void setDescription(String nDescription) {
    description = nDescription;
  }
  public boolean setCapacity(int nCapacity) {
    if (nCapacity >= 0) {
      capacity = nCapacity;
      return true;
    }
    else
      return false;
    }
  public boolean setMaxSpeed(double nMaxSpeed) {
    if (nMaxSpeed > 0) {
      maxSpeed = nMaxSpeed;
      return true;
    }
    else
      return false;
  }
  public String getDescription() {
    return description;
  }
  public int getCapacity() {
    return capacity;
  }
  public double getMaxSpeed() {
    return maxSpeed;
  }
}


class Bicycle extends Vehicle {
  private int wheelDiameter;
  private boolean hasBell;
  public Bicycle(String iDescription, int iCapacity, double iMaxSpeed,
                 int iWheelDiameter, boolean iHasBell) {
   
super(iDescription, iCapacity, iMaxSpeed);
    setWheelDiameter(iWheelDiameter);
    setHasBell(iHasBell);
  }
  public boolean setWheelDiameter(int nWheelDiameter) {
    if (nWheelDiameter >= 12 && nWheelDiameter <= 26) {
      wheelDiameter = nWheelDiameter;
      return true;
    }
    else
      return false;
  }
  public void setHasBell(boolean nHasBell) {
    hasBell = nHasBell;
  }
  public int getWheelDiameter() {
    return wheelDiameter;
  }
  public boolean hasBell() {
    return hasBell;
  }
}

Notes:

  1. When the application instantiates the Bicycle object, the Bicycle constructor passes the description, capacity, and maximum speed through to the superclass (Vehicle) constructor.

  2. As the application acts upon the Bicycle object (bike), it calls the object's instance methods without regard to their class. For example, the getDescription() method is in the Vehicle class, the setWheelDiameter() method is in the Bicycle class, and the toString() method is in the Object class. The inherited toString() method isn't very useful, but we are about to change that.

 

Overriding an inherited method

For example, all classes inherit the toString() method of the Object class. The default behavior of the method is to return a String containing general information about the object (its class name and the value of its object reference). To override the inherited method to provide other information, a class could contain the method

public String toString() {
    custom code goes here...
}

where the custom code would build and return a String to the caller.

public class App {
  public static void main(String[] args) {
    Bicycle bike = new Bicycle("Mary's old bike", 1, 15.5, 14, true);
    Utility.skip();
    System.out.println("        Description: " + bike.getDescription());
    System.out.println("     Wheel diameter: " + bike.getWheelDiameter());
    System.out.println("          Top speed: " + bike.getMaxSpeed());
    bike.setDescription("Mary's modified bike");
    bike.setWheelDiameter(18);
    bike.setMaxSpeed(22.5);
    Utility.skip();
    System.out.println("        Description: " + bike.getDescription());
    System.out.println("     Wheel diameter: " + bike.getWheelDiameter());
    System.out.println("          Top speed: " + bike.getMaxSpeed());
    Utility.skip();
    System.out.println(" Object information: " + bike.toString());
  }
}

class Vehicle {
  private String description;
  private int capacity;
  private double maxSpeed;
  public Vehicle(String iDescription, int iCapacity, double iMaxSpeed) {
    setDescription(iDescription);
    setCapacity(iCapacity);
    setMaxSpeed(iMaxSpeed);
  }
  public void setDescription(String nDescription) {
    description = nDescription;
  }
  public boolean setCapacity(int nCapacity) {
    if (nCapacity >= 0) {
      capacity = nCapacity;
      return true;
    }
    else
      return false;
    }
  public boolean setMaxSpeed(double nMaxSpeed) {
    if (nMaxSpeed > 0) {
      maxSpeed = nMaxSpeed;
      return true;
    }
    else
      return false;
  }
  public String getDescription() {
    return description;
  }
  public int getCapacity() {
    return capacity;
  }
  public double getMaxSpeed() {
    return maxSpeed;
  }
}


class Bicycle extends Vehicle {
  private int wheelDiameter;
  private boolean hasBell;
  public Bicycle(String iDescription, int iCapacity, double iMaxSpeed,
                 int iWheelDiameter, boolean iHasBell) {
    super(iDescription, iCapacity, iMaxSpeed);
    setWheelDiameter(iWheelDiameter);
    setHasBell(iHasBell);
  }
  public boolean setWheelDiameter(int nWheelDiameter) {
    if (nWheelDiameter >= 12 && nWheelDiameter <= 26) {
      wheelDiameter = nWheelDiameter;
      return true;
    }
    else
      return false;
  }
  public void setHasBell(boolean nHasBell) {
    hasBell = nHasBell;
  }
  public int getWheelDiameter() {
    return wheelDiameter;
  }
  public boolean hasBell() {
    return hasBell;
  }
    public String toString() {
    String result = "[ " + getDescription() + ", " +
                           getCapacity() + ", " +
                           getMaxSpeed() + ", " +
                           getWheelDiameter() + ", " +
                           hasBell() +
                    " ]";
    return result;
  }

}

 

Review questions

  1. You have been given the specification for a personnel system to be implemented in Java. Part of it states:

"An employee has an employee number, a name, and a hire date. A sales representative is an employee who has a commission rate and a district."

Given that the Employee class has already been defined, code the class header of the SalesRep class so that it can be referenced from any class.

  1. You have been given the specification for a personnel system to be implemented in Java. Part of it states:

"An employee has an employee number, a name, and a hire date. A sales representative is an employee who has a commission rate and a district."

Given that the Employee class has already been defined, which of the following fields would be appropriate for inclusion in the SalesRep class as members?  (choose two)

  1. Employee theEmployee;

  2. double commissionRate;

  3. String district;

  4. String name;

  5. Date hireDate;

  1. Assume that class Nothing has been defined with a single constructor that accepts a String. Which one of the following legally define a class that extends Nothing?

  1. class DoesNothing extends Nothing {
      private int value;
      public DoesNothing(String iName, int iValue) {
        super(iName);
        value = iValue;
      }
    }

  2. class DoesNothing extends Nothing {
      private int value;
      public DoesNothing(String iName, int iValue) {
        value = iValue;
        super(iName);
      }
    }

  3. class DoesNothing extends Nothing {
      private int value;
      public DoesNothing(String iName, int iValue) {
        Nothing(iName);
        value = iValue;
      }
    }

  4. class DoesNothing extends Nothing {
      private int value;
      public DoesNothing(String iName, int iValue) {
        super();
        value = iValue;
      }
    }

  5. class DoesNothing extends Nothing {
      private int value;
      public DoesNothing(String iName, int iValue) {
        int y = 5;
        super(iName);
        value = iValue * y;
      }
    }

  1. Assume that a class inherits a single method named calcAmount that has the following method header:

public double calcAmount(double discount, boolean preferred)

Which of the following is the header of a method that can legally be coded within the class?

  1. public float calcAmount(float d, boolean p)

  2. public double calcAmount(double d)

  3. public double calcAmount(double d, boolean p)

  4. public float calcAmount(float d)

  5. all of the above