Hierarchical inheritance occurs when one superclass has multiple subclasses. This forms a tree-like structure where the superclass serves as the root, and the subclasses branch out from it. Each subclass inherits the attributes and methods of the superclass, allowing them to share common functionality while also defining their specific behaviors.
Single Parent, Multiple Children: A superclass can have multiple subclasses, which makes it a powerful way to share common functionality across different types of objects.
Code Reusability: By inheriting from a common superclass, subclasses can reuse existing code, reducing redundancy and making it easier to maintain.
Clear Structure: The hierarchical relationship provides a clear organizational structure, making the code more readable and maintainable.
Efficiency: Common properties and methods are defined in one place (the superclass), avoiding duplication across subclasses.
Flexibility: New subclasses can be added easily without affecting the existing class structure. This allows for the evolution of the system without major refactoring.
Clear Relationships: The inheritance structure clearly defines relationships between classes, making it easier for developers to understand how different classes interact.
Complexity: If the hierarchy becomes too deep or complicated, it may become difficult to manage and understand the relationships between classes.
Dependency: Changes made in the superclass can impact all subclasses, which may lead to unexpected behavior if not managed carefully.
In Java, hierarchical inheritance is implemented using the extends
keyword. Here’s a basic structure:
class Superclass {
// Members of Superclass
}
class Subclass1 extends Superclass {
// Members of Subclass1
}
class Subclass2 extends Superclass {
// Members of Subclass2
}
// Additional subclasses can be added as needed
Let’s explore a detailed example of hierarchical inheritance involving a hierarchy of vehicles. We will create a superclass called Vehicle
and multiple subclasses like Car
, Bike
, and Truck
.
// Superclass
class Vehicle {
private String brand;
private String model;
// Constructor
public Vehicle(String brand, String model) {
this.brand = brand;
this.model = model;
}
// Method to display vehicle details
public void displayDetails() {
System.out.println("Brand: " + brand);
System.out.println("Model: " + model);
}
// Method to start the vehicle
public void start() {
System.out.println(brand + " " + model + " is starting.");
}
}
Explanation:
brand
and model
are fields representing the vehicle’s characteristics.displayDetails()
shows the vehicle’s details, and start()
simulates starting the vehicle.
// Subclass Car
class Car extends Vehicle {
private int numberOfDoors;
// Constructor
public Car(String brand, String model, int numberOfDoors) {
super(brand, model); // Call to the superclass constructor
this.numberOfDoors = numberOfDoors;
}
// Method specific to Car
public void honk() {
System.out.println("Car is honking.");
}
// Overriding displayDetails method
@Override
public void displayDetails() {
super.displayDetails(); // Call to superclass method
System.out.println("Number of Doors: " + numberOfDoors);
}
}
Explanation:
numberOfDoors
is specific to cars.honk()
simulates the car’s horn.displayDetails()
method is overridden to include information specific to the Car
class.
// Subclass Bike
class Bike extends Vehicle {
private boolean hasCarrier;
// Constructor
public Bike(String brand, String model, boolean hasCarrier) {
super(brand, model);
this.hasCarrier = hasCarrier;
}
// Method specific to Bike
public void ringBell() {
System.out.println("Bike bell rings.");
}
// Overriding displayDetails method
@Override
public void displayDetails() {
super.displayDetails();
System.out.println("Has Carrier: " + hasCarrier);
}
}
Explanation:
hasCarrier
indicates whether the bike has a carrier.ringBell()
simulates ringing the bike’s bell.displayDetails()
to include bike-specific information.
// Subclass Truck
class Truck extends Vehicle {
private int loadCapacity;
// Constructor
public Truck(String brand, String model, int loadCapacity) {
super(brand, model);
this.loadCapacity = loadCapacity;
}
// Method specific to Truck
public void load() {
System.out.println("Truck is loading.");
}
// Overriding displayDetails method
@Override
public void displayDetails() {
super.displayDetails();
System.out.println("Load Capacity: " + loadCapacity + " kg");
}
}
Explanation:
loadCapacity
specifies how much weight the truck can carry.load()
simulates loading cargo onto the truck.displayDetails()
to include truck-specific information.
public class Main {
public static void main(String[] args) {
// Creating instances of different vehicles
Car car = new Car("Toyota", "Camry", 4);
Bike bike = new Bike("Yamaha", "YZF-R15", true);
Truck truck = new Truck("Volvo", "FH", 20000);
// Displaying details and calling methods for Car
System.out.println("Car Details:");
car.displayDetails();
car.start();
car.honk();
System.out.println();
// Displaying details and calling methods for Bike
System.out.println("Bike Details:");
bike.displayDetails();
bike.start();
bike.ringBell();
System.out.println();
// Displaying details and calling methods for Truck
System.out.println("Truck Details:");
truck.displayDetails();
truck.start();
truck.load();
}
}
When you run the Main
class, you will see the following output:
Car Details:
Brand: Toyota
Model: Camry
Number of Doors: 4
Toyota Camry is starting.
Car is honking.
Bike Details:
Brand: Yamaha
Model: YZF-R15
Has Carrier: true
Yamaha YZF-R15 is starting.
Bike bell rings.
Truck Details:
Brand: Volvo
Model: FH
Load Capacity: 20000 kg
Volvo FH is starting.
Truck is loading.
Vehicle Class: This superclass defines the common characteristics and behaviors of vehicles. It provides a foundation for subclasses like Car
, Bike
, and Truck
.
Car Class: This subclass extends Vehicle
, inheriting its properties and methods. It adds specific behaviors and overrides the displayDetails()
method to include the number of doors.
Bike Class: Similar to Car
, this subclass inherits from Vehicle
, adding bike-specific behaviors such as ringing a bell and overriding the display method.
Truck Class: This subclass represents another type of vehicle, inheriting from Vehicle
and defining its unique behavior related to load capacity.
Main Class: The main
method creates instances of each subclass and demonstrates how they can call both inherited and specific methods.
Hierarchical inheritance is widely applicable across various domains:
Software Development: In software libraries and frameworks, hierarchical inheritance allows for a clear organization of classes. For instance, in a GUI library, you might have a base class Component
with subclasses like Button
, TextField
, and Checkbox
.
Game Development: In games, you can create a superclass Character
with subclasses like Player
, Enemy
, and NPC
(non-player character). Each subclass can inherit common attributes (like health and position) while implementing unique behaviors (like attacking or defending).
E-commerce Applications: In an e-commerce application, a superclass Product
can have subclasses like Electronics
, Clothing
, and Groceries
, each inheriting properties like price
and description
, while adding their specific attributes (like warranty for electronics).
Educational Systems: In an educational system, a superclass Person
can have subclasses Student
and Teacher
, allowing them to share common attributes (like name and age) while defining unique behaviors (like grading assignments for teachers).