What is Inheritance?
Inheritance is a mechanism in object-oriented programming (OOP) where a new class (subclass or derived class) inherits the properties and behaviors (fields and methods) of an existing class (superclass or base class). This allows for code reuse and establishes a natural hierarchical relationship between classes.
Types of Inheritance
Single Inheritance: A class inherits from one superclass.
Multilevel Inheritance: A class inherits from a class, which in turn inherits from another class.
Hierarchical Inheritance: Multiple classes inherit from one superclass.
Multiple Inheritance (via Interfaces): A class implements multiple interfaces, allowing for multiple inheritances since Java does not support direct multiple inheritance.
Importance of Inheritance
Code Reuse: Inherits common functionality from the superclass.
Method Overriding: Allows subclasses to modify inherited methods.
Polymorphism: Subclasses can be treated as instances of their superclass, enabling flexible code.
Why Use Inheritance?
To create a logical class hierarchy.
To facilitate code reuse and reduce redundancy.
To enhance code maintenance and scalability.
Simple Examples
Example 1: Without Inheritance
class Car {
String brand;
int speed;
void display() {
System.out.println("Brand: " + brand + ", Speed: " + speed);
}
}
class Truck {
String brand;
int speed;
int loadCapacity;
void display() {
System.out.println("Brand: " + brand + ", Speed: " + speed + ", Load Capacity: " + loadCapacity);
}
}
Explanation: In this example, both Car
and Truck
classes have similar fields and methods, causing code duplication.
Example 1: With Inheritance
class Vehicle {
String brand;
int speed;
void display() {
System.out.println("Brand: " + brand + ", Speed: " + speed);
}
}
class Car extends Vehicle {
// Additional properties and methods specific to Car
}
class Truck extends Vehicle {
int loadCapacity;
@Override
void display() {
System.out.println("Brand: " + brand + ", Speed: " + speed + ", Load Capacity: " + loadCapacity);
}
}
Explanation: Here, Vehicle
is the superclass, and Car
and Truck
are subclasses that inherit fields and methods from Vehicle
. This reduces code duplication and centralizes common functionality.
Complex Examples
Example 1: Polymorphism with Inheritance
class Animal {
void makeSound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Cat meows");
}
}
public class TestPolymorphism {
public static void main(String[] args) {
Animal myAnimal = new Dog();
myAnimal.makeSound(); // Outputs: Dog barks
myAnimal = new Cat();
myAnimal.makeSound(); // Outputs: Cat meows
}
}
Explanation: In this example, Dog
and Cat
are subclasses of Animal
. Polymorphism allows myAnimal
to reference an object of either Dog
or Cat
, and the correct method (makeSound
) is called based on the actual object type.
Example 2: Using Abstract Classes
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing Rectangle");
}
}
public class TestAbstractClass {
public static void main(String[] args) {
Shape s1 = new Circle();
Shape s2 = new Rectangle();
s1.draw(); // Outputs: Drawing Circle
s2.draw(); // Outputs: Drawing Rectangle
}
}
Explanation: Shape
is an abstract class with an abstract method draw
. Circle
and Rectangle
are concrete subclasses that provide implementations for draw
. This demonstrates how abstract classes enforce method implementation in subclasses.
Example 3: Interface Implementation
interface Drivable {
void drive();
}
class Car implements Drivable {
public void drive() {
System.out.println("Car is driving");
}
}
class Bike implements Drivable {
public void drive() {
System.out.println("Bike is driving");
}
}
public class TestInterface {
public static void main(String[] args) {
Drivable myCar = new Car();
Drivable myBike = new Bike();
myCar.drive(); // Outputs: Car is driving
myBike.drive(); // Outputs: Bike is driving
}
}
Explanation: Drivable
is an interface with a drive
method. Car
and Bike
implement this interface, providing specific implementations for drive
. This allows objects of Car
and Bike
to be used interchangeably through the Drivable
interface.
Conclusion
Inheritance in Java is a powerful tool for promoting code reuse, modularity, and polymorphism. It allows developers to create a logical class hierarchy, centralize common functionality, and write more maintainable and scalable code. By understanding and leveraging inheritance, you can significantly improve the structure and efficiency of your Java applications.