Inheritance in Java

In Java, inheritance is a mechanism by which a class can be derived from another class, inheriting all of its attributes and methods. The class that is being inherited from is called the superclass or parent class, and the class that is inheriting from it is called the subclass or child class.

To implement inheritance in Java, you use the extends keyword in the class declaration of the subclass, followed by the name of the superclass. For example, if you wanted to create a subclass called Student that inherits from a superclass called Person, you would declare the class like this:

public class Student extends Person {
    // class body
}

The extends keyword indicates that Student is inheriting from Person.

The subclass inherits all of the attributes and methods of the superclass, including any public or protected members. The subclass can also add its own attributes and methods, and it can override any methods from the superclass that it wants to change.

To call a method from the superclass in the subclass, you can use the super keyword. For example, if the Person class has a method called getName(), you can call it from the Student class like this:

public class Student extends Person {
    public void printName() {
        System.out.println(super.getName());
    }
}

In this example, printName() is a method in the Student class that calls the getName() method from the Person class using super.getName().

Inheritance is a powerful feature of Java that allows you to reuse code and create hierarchies of related classes. It is a fundamental concept in object-oriented programming and is used extensively in Java programming.

Why use inheritance in java:

Inheritance is a key concept in object-oriented programming, and Java is an object-oriented programming language that fully supports inheritance. There are several reasons why you might use inheritance in Java:

  1. Code Reusability: Inheritance allows you to reuse code from an existing class by creating a new class that inherits all of its attributes and methods. This saves time and effort because you do not have to rewrite code that has already been implemented.
  2. Polymorphism: Inheritance is closely related to the concept of polymorphism, which allows you to write code that works with objects of different classes as if they were all of the same class. Polymorphism is particularly useful in situations where you want to write code that can work with a variety of different objects that share some common characteristics.
  3. Maintainability: Inheritance can improve code maintainability because it promotes code reuse and reduces the amount of code that needs to be written. This means that when changes are made to the superclass, those changes will automatically apply to all subclasses that inherit from it, which can reduce the likelihood of bugs and other issues.
  4. Flexibility: Inheritance allows you to create hierarchies of related classes that can be used to model complex real-world scenarios. For example, you might create a class hierarchy that represents different types of vehicles, with subclasses for cars, trucks, and motorcycles. This can make it easier to design and implement software that deals with these types of objects.

Overall, inheritance is a powerful and flexible feature of Java that can be used to improve code reusability, promote maintainability, and support the development of complex object-oriented applications.

Terms used in Inheritance:

Here are some key terms used in inheritance:

  1. Superclass: A superclass, also known as a parent class or base class, is the class that is being inherited from. It provides the basic implementation that will be inherited by the subclass.
  2. Subclass: A subclass, also known as a child class or derived class, is the class that inherits from the superclass. It can add new attributes and methods, override existing methods, or inherit and use methods and attributes from the superclass.
  3. Inheritance hierarchy: An inheritance hierarchy is a tree-like structure that represents the relationship between a superclass and its subclasses. Each node in the tree represents a class, with the root node representing the superclass and the child nodes representing the subclasses.
  4. Extends keyword: In Java, the extends keyword is used to create a subclass that inherits from a superclass. It is followed by the name of the superclass, as in public class Subclass extends Superclass {...}.
  5. Super keyword: The super keyword in Java is used to refer to the superclass from within a subclass. It can be used to call superclass constructors, methods, and attributes, and is often used when a subclass needs to override a method from the superclass.
  6. Overriding: Overriding is the process of providing a new implementation for a method that already exists in the superclass. When a subclass overrides a method from the superclass, it provides a new implementation that will be used instead of the original implementation in the superclass.
  7. Polymorphism: Polymorphism is the ability of objects of different classes to be treated as if they are objects of the same class. Inheritance is one of the mechanisms that supports polymorphism in Java, allowing objects of a subclass to be treated as objects of the superclass.

The syntax of Java Inheritance:

In Java, inheritance is implemented using the extends keyword in the class declaration of the subclass, followed by the name of the superclass. Here’s the basic syntax for implementing inheritance in Java:

class Superclass {
    // superclass implementation
}

class Subclass extends Superclass {
    // subclass implementation
}

In this example, Subclass is the subclass that inherits from Superclass, which is the superclass. The extends keyword indicates that Subclass is inheriting from Superclass.

To access the methods and fields of the superclass, you can use the super keyword. Here’s an example of how to use super to call a method from the superclass:

class Superclass {
    public void printMessage() {
        System.out.println("Hello from superclass!");
    }
}

class Subclass extends Superclass {
    public void printMessage() {
        super.printMessage();
        System.out.println("Hello from subclass!");
    }
}

In this example, Subclass overrides the printMessage() method from Superclass, but also calls the printMessage() method from Superclass using super.printMessage(). This allows the Subclass implementation to include the behavior from the Superclass implementation, in addition to any new behavior.

Note that in Java, a class can only inherit from one superclass at a time, although a superclass can itself inherit from another superclass. Additionally, a class can only inherit non-private members from its superclass.

Java Inheritance Example:

Here’s an example of Java inheritance:

public class Vehicle {
    private String make;
    private String model;
    private int year;

    public Vehicle(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    public void printInfo() {
        System.out.println("Make: " + make);
        System.out.println("Model: " + model);
        System.out.println("Year: " + year);
    }
}

public class Car extends Vehicle {
    private int numDoors;

    public Car(String make, String model, int year, int numDoors) {
        super(make, model, year);
        this.numDoors = numDoors;
    }

    public void printInfo() {
        super.printInfo();
        System.out.println("Number of doors: " + numDoors);
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle("Toyota", "Camry", 2021);
        Car car = new Car("Honda", "Civic", 2022, 4);

        vehicle.printInfo(); // prints vehicle information
        car.printInfo(); // prints car information (including vehicle information)
    }
}

In this example, we have a Vehicle class that has attributes for the make, model, and year of a vehicle, as well as a method to print out this information. We also have a Car class that inherits from Vehicle, and adds an attribute for the number of doors, as well as a modified printInfo() method that includes the number of doors.

In the Main class, we create instances of both Vehicle and Car, and call the printInfo() method on each. We see that the printInfo() method of Car includes the information from Vehicle, as well as the number of doors. This demonstrates how inheritance can be used to extend and modify the behavior of a superclass.

Types of inheritance in java:

In Java, there are 5 types of inheritance:

  1. Single inheritance: Single inheritance is the simplest form of inheritance, in which a subclass extends a single superclass. In single inheritance, the subclass inherits all the non-private members of the superclass.
  2. Multilevel inheritance: Multilevel inheritance involves creating a subclass that extends a subclass. In other words, a subclass can inherit from a class, which in turn inherits from another class. This creates a hierarchy of classes where each class inherits from the class above it.
  3. Hierarchical inheritance: Hierarchical inheritance involves creating multiple subclasses that inherit from a single superclass. In other words, a superclass can have multiple subclasses, each with its own unique attributes and behaviors.
  4. Multiple inheritance (not supported in Java): Multiple inheritance is the ability to inherit from multiple classes at the same time. This feature is not supported in Java, as it can lead to problems such as the diamond problem.
  5. Hybrid inheritance (not supported in Java): Hybrid inheritance is a combination of two or more types of inheritance. It is also not supported in Java for the same reason as multiple inheritance.

Single Inheritance Example:

Here’s an example of single inheritance in Java:

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public void makeSound() {
        System.out.println("The animal makes a sound.");
    }

    public void eat() {
        System.out.println("The animal is eating.");
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    public void makeSound() {
        System.out.println("The dog barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal("Generic Animal");
        Dog dog = new Dog("Fido");

        animal.makeSound(); // prints "The animal makes a sound."
        dog.makeSound(); // prints "The dog barks."
        animal.eat(); // prints "The animal is eating."
        dog.eat(); // prints "The animal is eating."
    }
}

In this example, we have a Animal class that has attributes for the name of the animal, as well as methods for making a sound and eating. We also have a Dog class that inherits from Animal, and overrides the makeSound() method to bark.

In the Main class, we create instances of both Animal and Dog, and call the makeSound() and eat() methods on each. We see that the makeSound() method of Dog overrides the behavior of Animal, but the eat() method is inherited directly from Animal. This demonstrates how single inheritance can be used to extend and modify the behavior of a superclass.

Multilevel Inheritance Example:

Here’s an example of multilevel inheritance in Java:

public class Vehicle {
    private String make;
    private String model;
    private int year;

    public Vehicle(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    public void printInfo() {
        System.out.println("Make: " + make);
        System.out.println("Model: " + model);
        System.out.println("Year: " + year);
    }
}

public class Car extends Vehicle {
    private int numDoors;

    public Car(String make, String model, int year, int numDoors) {
        super(make, model, year);
        this.numDoors = numDoors;
    }

    public void printInfo() {
        super.printInfo();
        System.out.println("Number of doors: " + numDoors);
    }
}

public class SportsCar extends Car {
    private boolean isConvertible;

    public SportsCar(String make, String model, int year, int numDoors, boolean isConvertible) {
        super(make, model, year, numDoors);
        this.isConvertible = isConvertible;
    }

    public void printInfo() {
        super.printInfo();
        System.out.println("Convertible: " + isConvertible);
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle("Toyota", "Camry", 2021);
        Car car = new Car("Honda", "Civic", 2022, 4);
        SportsCar sportsCar = new SportsCar("Ferrari", "458 Italia", 2023, 2, true);

        vehicle.printInfo(); // prints vehicle information
        car.printInfo(); // prints car information (including vehicle information)
        sportsCar.printInfo(); // prints sports car information (including car and vehicle information)
    }
}

In this example, we have a Vehicle class that has attributes for the make, model, and year of a vehicle, as well as a method to print out this information. We also have a Car class that inherits from Vehicle, and adds an attribute for the number of doors, as well as a modified printInfo() method that includes the number of doors. Finally, we have a SportsCar class that inherits from Car, and adds an attribute for whether the car is convertible, as well as a modified printInfo() method that includes this information.

In the Main class, we create instances of Vehicle, Car, and SportsCar, and call the printInfo() method on each. We see that the printInfo() method of SportsCar includes the information from both Car and Vehicle, as well as the convertible attribute. This demonstrates how multilevel inheritance can be used to create a hierarchy of classes where each class inherits from the class above it.

Hierarchical Inheritance Example:

Here’s an example of hierarchical inheritance in Java:

public class Shape {
    public void draw() {
        System.out.println("Drawing a generic shape.");
    }
}

public class Circle extends Shape {
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

public class Square extends Shape {
    public void draw() {
        System.out.println("Drawing a square.");
    }
}

public class Triangle extends Shape {
    public void draw() {
        System.out.println("Drawing a triangle.");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle();
        Shape square = new Square();
        Shape triangle = new Triangle();

        circle.draw(); // prints "Drawing a circle."
        square.draw(); // prints "Drawing a square."
        triangle.draw(); // prints "Drawing a triangle."
    }
}

In this example, we have a Shape class that has a method to draw the shape. We also have three classes that inherit from Shape: Circle, Square, and Triangle. Each of these classes overrides the draw() method to draw the specific shape.

In the Main class, we create instances of Circle, Square, and Triangle, but we assign them to variables of type Shape. This allows us to call the draw() method on each of these instances using the same variable name. We see that the draw() method of each class is called appropriately, even though the variable type is Shape. This demonstrates how hierarchical inheritance can be used to create a hierarchy of classes where each class shares a common superclass, but has its own specific behavior.

Why multiple inheritance is not supported in java?

Multiple inheritance is the feature of object-oriented programming where a class can inherit properties and methods from more than one class. Java does not support multiple inheritance with classes, but it does support multiple inheritance with interfaces. There are a few reasons why multiple inheritance with classes is not supported in Java:

  1. Complexity: Multiple inheritance can make the code complex and harder to understand, as it creates ambiguity when two or more parent classes have methods or properties with the same name. This can result in unpredictable behavior at runtime.
  2. Diamond problem: The diamond problem is a common problem that arises in multiple inheritance when two classes that are not related inherit from the same superclass. In this case, if both of these classes override a method from the superclass, it is not clear which method should be used when an object of the child class calls the method.
  3. Java’s design philosophy: Java was designed to be a simple, easy-to-learn language that is suitable for developing large-scale applications. Multiple inheritance can make the code complex and harder to maintain, which goes against Java’s design philosophy.

To avoid these problems, Java supports single inheritance with classes, where a class can inherit properties and methods from only one parent class. However, Java does support multiple inheritance with interfaces, where a class can implement multiple interfaces to inherit properties and methods from them. This allows for the benefits of multiple inheritance, such as code reuse and abstraction, without the complexity and ambiguity of multiple inheritance with classes.