Java Inheritance:
Inheritance in Java is a fundamental feature of object-oriented programming (OOP) that allows a class (the subclass) to inherit properties and behaviors from another class (the superclass). The subclass can reuse the code and functionality of the superclass, promoting code reusability and building relationships between classes.
- In Java, it is possible to inherit attributes and methods from one class to another. We group the “inheritance concept” into two categories:
- subclass (child) – the class that inherits from another class
- If there is a match, the associated block of code is executed.
- superclass (parent) – the class being inherited from
- To inherit from a class, use the extends keyword.
Syntax: In Java, to create a subclass that inherits from a superclass, you use the extends
keyword. The syntax is as follows:
public class Superclass {
// attributes and methods of the superclass
}
public class Subclass extends Superclass {
// attributes and methods of the subclass
}
- Types of Inheritance: Java supports single inheritance, meaning a subclass can inherit from only one superclass. This is to avoid the complications and ambiguities that can arise with multiple inheritance.
- Access Modifiers and Inheritance: The access modifiers (public, protected, private, and default) play a role in determining the visibility and accessibility of inherited members in the subclass. The rules are similar to those mentioned in the previous response:
- public members of the superclass are accessible in the subclass.
- protected members of the superclass are accessible in the subclass, even if they are in a different package.
- private members of the superclass are not accessible in the subclass.
- Default (package-private) members of the superclass are accessible in the subclass only if they are in the same package.
- Method Overriding: Inheritance allows the subclass to override the methods of the superclass. This means the subclass can provide its own implementation for a method that already exists in the superclass. To achieve method overriding, the method in the subclass must have the same method signature (name and parameters) as the method in the superclass.
- Constructor Chaining: When a subclass is instantiated, its constructor can call the constructor of the superclass using the
super()
keyword. This enables the initialization of the inherited attributes defined in the superclass.
Inheritance is a powerful mechanism in Java that enables code reuse and the creation of class hierarchies, allowing for more efficient and organized software design. However, it should be used thoughtfully, and developers should consider using interfaces, composition, or other design patterns when multiple inheritance is required or when inheritance might lead to complex class hierarchies.
The example below :
// Superclass - Animal class Animal { private String species; public Animal(String species) { this.species = species; } public String getSpecies() { return species; } public void makeSound() { System.out.println("Animal makes a sound."); } } // Subclass - Dog (inherits from Animal) class Dog extends Animal { private String breed; public Dog(String species, String breed) { super(species); this.breed = breed; } public String getBreed() { return breed; } @Override public void makeSound() { System.out.println("Dog barks."); } } // Subclass - Cat (inherits from Animal) class Cat extends Animal { private String color; public Cat(String species, String color) { super(species); this.color = color; } public String getColor() { return color; } @Override public void makeSound() { System.out.println("Cat meows."); } } public class Main { public static void main(String[] args) { Dog dog = new Dog("Dog", "Labrador"); Cat cat = new Cat("Cat", "Gray"); System.out.println("Dog: " + dog.getSpecies() + ", " + dog.getBreed()); dog.makeSound(); System.out.println("Cat: " + cat.getSpecies() + ", " + cat.getColor()); cat.makeSound(); } }
Output:
Dog: Dong, Labrador
Dog barks.
Cat: Cat, Gray
Cat meows.
Animal, Dog, and Cat Classes:
In this code, we have three classes: Animal, Dog, and Cat. They demonstrate the concept of inheritance in Java, where Dog and Cat are subclasses that inherit characteristics and behaviors from the Animal superclass.
- Animal class:
- The Animal class represents a general animal with a species attribute. It has a constructor that takes the species as a parameter.
- It provides two methods: getSpecies() to retrieve the species and makeSound() to make a generic animal sound (in this case, it prints “Animal makes a sound.”).
- Dog class:
- The Dog class is a subclass of Animal. It has an additional attribute, breed.
- The constructor of Dog takes both the species and breed as parameters, and it uses the super keyword to call the constructor of the superclass, Animal.
- It overrides the makeSound() method to provide a specific behavior for a dog (it prints “Dog barks.”).
- It provides a method getBreed() to retrieve the dog’s breed.
- Cat class:
- The Cat class is also a subclass of Animal. It introduces an extra attribute, color.
- The constructor of Cat takes both the species and color as parameters, and it uses super to invoke the superclass constructor, Animal.
- It overrides the makeSound() method to provide a unique behavior for a cat (it prints “Cat meows.”).
- It offers a method getColor() to retrieve the cat’s color.
Main Class:
The Main class contains the main method, which serves as the entry point for the program. In this method:
- An instance of the Dog class, named dog, is created with the species “Dog” and breed “Labrador.”
- An instance of the Cat class, named cat, is created with the species “Cat” and color “Gray.”
- Information about the dog and cat is printed, including their species and additional attributes (breed for the dog and color for the cat).
- The makeSound() method is called for both the dog and cat, which demonstrates polymorphism. Despite being of different subclasses, they both override the makeSound() method to produce their respective sounds.
This code illustrates how inheritance allows you to create specialized subclasses that inherit and customize the behavior of a superclass. It also demonstrates polymorphism, where objects of different classes can be treated uniformly through the superclass reference.
Let’s provide another example of Java inheritance using a real-life scenario with different types of vehicles.
// Superclass (Parent class) class Vehicle { String brand; int year; Vehicle(String brand, int year) { this.brand = brand; this.year = year; } void start() { System.out.println("Starting the vehicle"); } void stop() { System.out.println("Stopping the vehicle"); } } // Subclass (Child class) class Car extends Vehicle { int numDoors; Car(String brand, int year, int numDoors) { super(brand, year); // Call the constructor of the superclass with the 'brand' and 'year' parameters this.numDoors = numDoors; } @Override void start() { System.out.println("Starting the car"); } void drive() { System.out.println("Car is driving"); } } // Subclass (Child class) class Motorcycle extends Vehicle { boolean hasSideCar; Motorcycle(String brand, int year, boolean hasSideCar) { super(brand, year); // Call the constructor of the superclass with the 'brand' and 'year' parameters this.hasSideCar = hasSideCar; } @Override void start() { System.out.println("Starting the motorcycle"); } void ride() { System.out.println("Motorcycle is riding"); } }
Output:
Starting the car
Car is driving
Stopping the vehicle
Starting the motorcycle
Motorcycle is riding
Stopping the vehicle
Explanation:
- vehicle, Car, and Motorcycle Classes:
In this code, there are three classes: Vehicle, Car, and Motorcycle, which demonstrate the concept of inheritance in object-oriented programming.
- Vehicle class: The Vehicle class serves as the superclass or parent class. It represents a general vehicle with attributes brand and year, and it provides methods to start and stop the vehicle. These methods print out messages indicating the actions performed.
- Car class: The Car class is a subclass of Vehicle. It inherits the brand and year attributes from the superclass and introduces an additional attribute, numDoors, representing the number of doors in the car. The constructor of the Car class takes three parameters, including the brand, year, and numDoors. It uses the super keyword to call the constructor of the superclass, passing the brand and year. The start method is overridden to provide a specific behavior for starting a car. Additionally, it has a unique method, drive, which prints a message indicating that the car is driving.
- Motorcycle class: The Motorcycle class is another subclass of Vehicle. It inherits the brand and year attributes and introduces an attribute, hasSideCar, which is a boolean indicating whether the motorcycle has a sidecar. The constructor of the Motorcycle class also uses the super keyword to call the superclass constructor, passing the brand and year. The start method is overridden to provide a specific behavior for starting a motorcycle. The class includes a unique method, ride, which prints a message indicating that the motorcycle is riding.
Inheritance and Method Overriding:
The code showcases inheritance and method overriding, essential concepts in object-oriented programming. The Car and Motorcycle classes inherit attributes and methods from the Vehicle class, allowing for code reuse. They customize the behavior by overriding the start method, making it specific to the type of vehicle.
Polymorphism:
Polymorphism is also demonstrated in this code. Despite having different classes (Car and Motorcycle), objects of these classes can be treated as objects of the superclass, Vehicle. For example, you can create a Vehicle reference and assign it an instance of either Car or Motorcycle. This allows for flexibility and code that can work with different types of vehicles.
Usage in a Unique Scenario:
Suppose you have a car dealership application. You could use these classes to model and manage your inventory of vehicles. The Vehicle class serves as a base class for all vehicles, while Car and Motorcycle classes provide specific details for cars and motorcycles. This organization helps in maintaining a clear structure for your application, allowing you to manage and interact with different types of vehicles seamlessly.
Now, let’s use the Vehicle, Car, and Motorcycle classes in the main method:
public class Main { public static void main(String[] args) { Vehicle vehicle = new Vehicle("Generic Brand", 2023); vehicle.start(); // Output: "Starting the vehicle" Car car = new Car("Toyota", 2022, 4); car.start(); // Output: "Starting the car" car.drive(); // Output: "Car is driving" Motorcycle motorcycle = new Motorcycle("Harley-Davidson", 2021, true); motorcycle.start(); // Output: "Starting the motorcycle" motorcycle.ride(); // Output: "Motorcycle is riding" } }
Explanation:
- Main Class:
The Main class contains the main method, which acts as the entry point for the program. In this method:
- An instance of the Vehicle class, named vehicle, is created with the brand “Generic Brand” and the year 2023. It’s started and outputs “Starting the vehicle.”
- An instance of the Car class, named car, is created with the brand “Toyota,” year 2022, and 4 doors. It’s started and outputs “Starting the car.” It also demonstrates the drive() method, which outputs “Car is driving.”
- An instance of the Motorcycle class, named motorcycle, is created with the brand “Harley-Davidson,” year 2021, and a sidecar (indicated by true). It’s started and outputs “Starting the motorcycle.” It also showcases the ride() method, which outputs “Motorcycle is riding.”
This code demonstrates the power of inheritance in object-oriented programming. Subclasses (Car and Motorcycle) inherit attributes and behaviors from the superclass (Vehicle) and can also customize or add their own attributes and methods. Method overriding allows each subclass to provide its unique implementation of the start() method, illustrating polymorphism where objects of different classes can be treated uniformly through the superclass reference.