9.5 - Creating References Using Inheritance Hierarchies
Inheritance Hierarchies is the idea that:
- If we have a public superclass (A) that then has a public subclass (B) and that public subclass then has another public subclass (C), then the subclass C is also a subclass of the superclass A and so subclass C is extending superclass A
Here is an example of this:
// Class Declarations:
// Superclass (A)
public class Vehicles{}
// Subclass (B)
public class Car extends Vehicles{}
// Subclass (C)
public class Sedan extends Car{}
// Subclass (D)
public class Truck extends Vehicles{}
Here is a diagram displaying the relationship:
-
This diagram shows the the vehicle superclass which then has two subclasses: Car and Truck, however, Car has another subclass called Sedan
-
Based on this diagram, we know that Truck has a “is-a” relationship with Vehicle, Car also has a “is-a” relationship with Vehicle, and since Car has an “is-a” relationship with Vehicle, so does Sedan
-
So Sedan also has a “is-a” relationship with Vehicle
If we assume that all of the class contain a constructor with no arguments, this then allows for us to declare a superclass reference variable to hold a subclass object:
Vehicles v1 = new Truck();
Vehicles v2 = new Car();
// instead of doing
Car v3 = new Sedan();
// We have the option to do this instead
Vehicles v4 = new Sedan();
However, it is important to remember that you can’t declare a Subclass variable and put in a Superclass object
// dont do this
Sedan v5 = new Vehicle();
Popcorn Hack: Using a superclass and subclasses of your choice, assuming that the classes contain a constructor with no arguments, create Class Declarations and Superclass References
// show here
Why would we want to do this?
-
When doing object oriented programming, we are able to create a superclass with common attributes and then have subclasses with more specific traits
-
By doing this, we get rid of code redundancy and it also makes the easier to reuse common aspects without needing to write them out every time while still presenting the option to override any attribute from the superclass to better represent the subclass
-
All the subclasses adhere to one superclass so this makes updates to code much easier and allows you to take advantage of polymorphism to unify the code and allow for more flexible and manageable code (more about this in 9.6)
Here is a Complete Example of the Inheritance Hierarchy from above:
class Vehicle {
private String brand; // private instance variable
private int year; // private instance variable
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
public void displayInfo() { // common variables for each vehicle
System.out.println("Brand: " + brand);
System.out.println("Year: " + year);
}
}
class Truck extends Vehicle {
// feature that only a truck can have
private double maxLoadCapacity;
public Truck(String brand, int year, double maxLoadCapacity) {
super(brand, year); // Inherits the variables from superclass
this.maxLoadCapacity = maxLoadCapacity;
}
@Override // Override allows for displayInfo to now also show the trait specific to the Truck while still keeping the main variables
public void displayInfo() {
super.displayInfo(); // Reuse the displayInfo method from the superclass
System.out.println("Max Load Capacity: " + maxLoadCapacity + " tons");
}
}
class Car extends Vehicle {
// something that cars have
private int numberOfDoors;
public Car(String brand, int year, int numberOfDoors) {
super(brand, year);
this.numberOfDoors = numberOfDoors;
}
@Override // Override allows for displayInfo to now also show the trait specific to the Car while still keeping the main variables
public void displayInfo() {
super.displayInfo(); // Reuse the displayInfo method from the superclass
System.out.println("Number of Doors: " + numberOfDoors);
}
}
class Sedan extends Car {
// Sedan is luxury so trait specific to sedan
private boolean leatherSeats;
public Sedan(String brand, int year, int numberOfDoors, boolean leatherSeats) {
super(brand, year, numberOfDoors);
this.leatherSeats = leatherSeats;
}
@Override // Override allows for displayInfo to now also show the trait specific to the Sedan while still keeping the main variables
public void displayInfo() {
super.displayInfo(); // Reuse the displayInfo method from the superclass
System.out.println("Leather Seats: " + leatherSeats);
}
}
public class Main {
public static void main(String[] args) {
Vehicle v1 = new Truck("Ford", 2023, 10.5);
Vehicle v2 = new Car("Toyota", 2023, 4);
Vehicle v3 = new Sedan("Honda", 2023, 4, true);
System.out.println("Truck Information:");
v1.displayInfo();
System.out.println("\nCar Information:");
v2.displayInfo();
System.out.println("\nSedan Information:");
v3.displayInfo();
}
}
Main.main(null)
Truck Information:
Brand: Ford
Year: 2023
Max Load Capacity: 10.5 tons
Car Information:
Brand: Toyota
Year: 2023
Number of Doors: 4
Sedan Information:
Brand: Honda
Year: 2023
Number of Doors: 4
Leather Seats: true
Popcorn Hack: In your own words describe the importance of Inheritance Hierarchies