8 Inheritance

Inheritance, Specialization, and Generalization

Objective

  • Apply inheritance in application development.
  • Write classes with overridden methods.

Exercise 1*

  1. Create a new project, a package named model, and a package named test.

  2. In the model package, create a class called Person that has two data members: id: int and name: String. Add corresponding setter/getter methods.

  3. Create a new class named Employee that inherits (specializes) class Person and has one additional data member: noOfChildren.

  4. Add setter/getter method for this new field.

    According to this the superclass (parent) is _______ and the subclass (child) is _______.

  5. In the model package, create a new class AppTest with a main() method. In the main() method, create an object of type Employee.

  6. Using setter methods, set the object’s data as follows: id to 123, name to "Khaled", and noOfChildren to 2.

    Note that the methods setId() and setName() are not defined in the Employee class but inherited from Person.

  7. Output the name, ID, and number of children for the above employee.

  8. In class Employee, add a constructor that receives one parameter (int) to initialize the field noOfChildren. This results in an error. Why?

    To solve this, add a default constructor in the Employee class.

  9. Add a constructor to Person that receives two parameters to initialize id and name. Add an output statement in this constructor to print "Person constructor called". This results in an error. Why?

    To solve this, add a default constructor in the Person class.

  10. Add a constructor in class Employee that receives three parameters: int, String, and int to initialize all data members.

    • Can you access the id and name fields directly in this constructor?

    • If not, then how to solve this issue?

      One solution is to use the setters of these fields. An alternative way is to explicitly call the constructor of the superclass. How to do that?

    • Use the keyword super to call the superclass’s constructor to initialize the data, in a similar fashion to the use of this() to call an overloaded constructor. Also add output statements in this constructor to print "Employee constructor called".

    • Can you make the superclass constructor call as the last statement?

  11. In the main() method, create a new object as follows:

        Employee emp = new Employee(124, "Ameen", 1);

    Run the program. What is the output? What do you conclude regarding the order of constructor calls?

  12. Change the access modifiers of id and name in class Person to protected instead of private. Now try to access them directly in the Employee class. Are they accessible?

    In the main() method, try to access the id and name of object emp. Are they accessible?

    Notice that AppTest is not a member of the inheritance hierarchy, but it has access to the protected members. Explain and elaborate.

    Refer to Controlling Access to Members of a Class (opens in a new tab) to learn more about access modifiers:

    ModifierClassPackageSubclassWorld
    public
    protected
    private
  13. Move the AppTest class to the test package that you created earlier. Explain the errors you get when you try to run your application and propose ways to fix them.

  14. Create the public method toString() in class Person that returns the person’s id and name as comma-separated values (CSV). Output the details of emp using toString().

  15. In class Employee, create a public method toString() to return all the employee’s data: ID, name, and number of children as comma-separated values.

    • Having two methods with the same name and signature, one in the superclass and one in the subclass is called _______.
    • How to call the superclass method toString() from the subclass?
  16. Modify the access modifier of toString() in class Employee to protected instead of public. What do you conclude?

  17. Now restore toString()’s access modifier to public. Also make the id and name fields private and fix all references made to them. Also remove the output statements from the constructors of the Person and Employee classes, as they are no longer needed.

modelPerson-id : int-name : String+Person(int, String)+getId() : int+setId(int) : void+getName() : String+setName(String) : void+toString() : StringEmployee-noOfChildren: int+Employee(String, int, int)+getNoOfChildren() : int+setNoOfChildren(int) : void+toString() : String testEmployeeTest+main(String[]) : void

Exercise 2

  1. Add the following three classes to your project:

    Vehicle.java
    package model;
     
    public class Vehicle {
      private int wheels;
      private double weight;
     
      public Vehicle() {}
      public Vehicle(int wheels, double weight) {
        this.wheels = wheels;
        this.weight = weight;
      }
     
      public int getWheels() { return wheels; }
      public void setWheels(int wheels) { this.wheels = wheels; }
     
      public double getWeight() { return weight; }
      public void setWeight(double weight) { this.weight = weight; }
     
      @Override
      public String toString() {
        String dashes = "";
        String className = getClass().getSimpleName();
        for (int i = 0; i < className.length(); i++) { dashes += "-"; }
     
        return className + "\n" +
              dashes + "\n" +
              "Wheels: " + wheels + "\n" +
              "Weight: " + weight + "\n";
      }
    }
    Car.java
    package model;
     
    public class Car extends Vehicle {
      private int passengers;
     
      public Car() {}
      public Car(int wheels, double weight, int passengers) {
        super(wheels, weight);
        this.passengers = passengers;
      }
     
      public int getPassengers() { return passengers; }
      public void setPassengers(int passengers) { this.passengers = passengers; }
     
      @Override
      public String toString() {
        return super.toString() + "Passengers: " + passengers + "\n";
      }
    }
    VehicleTest.java
    package test;
    import model.*;
     
    public class VehicleTest {
      public static void main(String[] args) {
        Vehicle bicycle = new Vehicle(2, 20.0);
        Car sedan = new Car();
        Car toyota = new Car(4, 2000.0, 5);
     
        sedan.setWheels(4);
        sedan.setPassengers(4);
        sedan.setWeight(1500.0);
     
        System.out.println(bicycle);
        System.out.println(sedan);
        System.out.println(toyota);
      }
    }
  2. Run the VehicleTest class’s main() method.

  3. Add to the Vehicle class the public method getAsCSV() that returns the field values as comma-separated values. Let the last value in the comma-separated string be the name of the class preceded with a comma.

    Hint: Use the getClass().getSimpleName() from the Object class. Override this method in the Car class. Display the bicycle, sedan, and toyota objects as comma-separated values.

  4. Add a class called Truck to the model package that inherits from the Vehicle class. Truck objects have the fields:

    • number of wheels (wheels)
    • truck weight (weight)
    • load capacity (capacity)

    and the methods:

    • getters and setters
    • no-argument constructor
    • parametrized constructor
    • getWheelLoad(): returns the wheel load which is equal to (weight + capacity) / wheels.
    • toString(): overrides the superclass method by adding the truck details and the wheel load to the string generated by the superclass. Let the returned string be properly formatted.
    • getAsCSV(): overrides the superclass method by returning all the values of a truck object as comma-separated values without including the wheel load.
  5. Update the main() method in the VehicleTest to perform the following:

    • Create a Truck object named "volvo" with the data:
      • Number of wheels: 12
      • Truck weight: 4,000 kg
      • Load capacity: 12,000 kg
    • Display the "volvo" data using both toString() and getAsCSV() methods.
modelVehicle-wheels : int-weight : double+Vehicle()+Vehicle(int, int)+getWheels() : int+setWheels(int) : void+getWeight() : int+setWeight(double) : void+getAsCSV() : String+toString() : StringCar-passengers: int+Car()+Car(int, double, int)+getPassengers() : int+setPassengers(int) : void+getAsCSV() : String+toString() : StringTruck-capacity: double+Truck()+Truck(int, double, double)+getCapacity() : double+setCapacity(double) : void+getWheelLoad() : double+getAsCSV() : String+toString() : String testVehicleTest+main(String[]) : void

Exercise 3

  1. In the test package, create a new class called PersonTest which contains a main() method that tests the Person class by creating a List of Person instances, where the elements are initialized using the following data:

    IDName
    1318Jane Doe
    2571John Doe
    5376Sara Smith
  2. Write statements to output the contents of the 3 instances then save your file and run it.

modeltestPersonPersonTest+main(String[]) : void

Exercise 4+

  1. In the model package, create a class called Student that inherits from the Person class. A student has three data members: id: int, name: String, and major: String.
  2. Add setter/getter methods for the additional field. Also add a toString() method that returns all the student details as a string.
  3. In the AppTest class, create two Student instances.
  4. Display the details of the two students you have just created.
modelPersonStudent-major : String+Student(int, String, String)+getMajor() : String+setMajor(String) : void+toString() : String