Inheritance is another fundamental concept in Object-Oriented Programming(OOP)in Java.It allows a new class(called a subclass or child class)to inherit the properties and behavior(fields and methods)of an existing class(called a superclass or parent class).This promotescode reuseand establishes a natural hierarchy between classes.

Key Points of Inheritance:1.Superclass(Parent Class):The

class whose properties and methods are inherited.2.Subclass (Child Class): The class that inherits from the superclass.

  1. extends Keyword: Used by a subclass to inherit from a superclass.
  2. Single Inheritance: In Java, a class can inherit from only one superclass (Java does not support multiple inheritance directly).
  3. Multilevel Inheritance: A class can inherit from another subclass, forming a chain of inheritance.

Types of Inheritance in Java:

  • Single Inheritance: One class inherits from another class.
  • Multilevel Inheritance: A class is derived from a class that is also derived from another class.
  • Hierarchical Inheritance: Multiple classes inherit from a single class.

Java doesn’t support multiple inheritance (where a class inherits from multiple classes) to avoid the diamond problem, but it can be achieved using interfaces.

Example 1: Basic Inheritance Example

// Superclass (Parent class)
class Animal {
    void eat() {
        System.out.println("This animal eats food.");
    }
}
 
// Subclass (Child class)
class Dog extends Animal {
    void bark() {
        System.out.println("The dog barks.");
    }
}
 
public class InheritanceExample1 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // Inherited from Animal class
        dog.bark(); // Defined in Dog class
    }
}

Example 2: Single Inheritance

// Superclass
class Vehicle {
    void start() {
        System.out.println("Vehicle is starting...");
    }
}
 
// Subclass
class Car extends Vehicle {
    void drive() {
        System.out.println("Car is driving...");
    }
}
 
public class InheritanceExample2 {
    public static void main(String[] args) {
        Car car = new Car();
        car.start();  // Inherited from Vehicle class
        car.drive();  // Defined in Car class
    }
}

Example 3: Multilevel Inheritance

// Superclass
class Animal {
    void sleep() {
        System.out.println("Animal is sleeping...");
    }
}
 
// Intermediate class
class Mammal extends Animal {
    void feedMilk() {
        System.out.println("Mammal is feeding milk...");
    }
}
 
// Subclass
class Human extends Mammal {
    void speak() {
        System.out.println("Human is speaking...");
    }
}
 
public class InheritanceExample3 {
    public static void main(String[] args) {
        Human human = new Human();
        human.sleep();      // Inherited from Animal
        human.feedMilk();   // Inherited from Mammal
        human.speak();      // Defined in Human
    }
}

Example 4: Hierarchical Inheritance

// Superclass
class Shape {
    void draw() {
        System.out.println("Drawing a shape...");
    }
}
 
// Subclass 1
class Circle extends Shape {
    void draw() {
        System.out.println("Drawing a circle...");
    }
}
 
// Subclass 2
class Square extends Shape {
    void draw() {
        System.out.println("Drawing a square...");
    }
}
 
public class InheritanceExample4 {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();  // Calls the Circle's draw method
        
        Square square = new Square();
        square.draw();  // Calls the Square's draw method
    }
}

Example 5: Constructor Chaining in Inheritance

// Superclass
class Animal {
    Animal() {
        System.out.println("Animal constructor called");
    }
}
 
// Subclass
class Dog extends Animal {
    Dog() {
        super();  // Calls the constructor of the superclass (Animal)
        System.out.println("Dog constructor called");
    }
}
 
public class InheritanceExample5 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        // Output will show the Animal constructor being called first, then the Dog constructor.
    }
}

Example 6: Using the super Keyword

// Superclass
class Animal {
    String name = "Animal";
 
    void display() {
        System.out.println("This is an animal.");
    }
}
 
// Subclass
class Dog extends Animal {
    String name = "Dog";
 
    void display() {
        System.out.println("This is a dog.");
    }
 
    void showNames() {
        System.out.println(name);       // Refers to Dog's name
        System.out.println(super.name); // Refers to Animal's name
    }
}
 
public class InheritanceExample6 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.display();   // Calls Dog's display method
        dog.showNames(); // Demonstrates the use of 'super' to access Animal's name
    }
}

Example 7: Method Overriding

// Superclass
class Animal {
    void sound() {
        System.out.println("Animals make different sounds");
    }
}
 
// Subclass
class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("The cat meows");
    }
}
 
public class InheritanceExample7 {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.sound();  // Calls Animal's sound method
 
        Cat cat = new Cat();
        cat.sound();  // Calls Cat's overridden sound method
    }
}

Example 8: Upcasting and Downcasting

// Superclass
class Animal {
    void sound() {
        System.out.println("Animal makes sound");
    }
}
 
// Subclass
class Dog extends Animal {
    void sound() {
        System.out.println("Dog barks");
    }
 
    void fetch() {
        System.out.println("Dog is fetching...");
    }
}
 
public class InheritanceExample8 {
    public static void main(String[] args) {
        Animal animal = new Dog(); // Upcasting (Animal reference to a Dog object)
        animal.sound();            // Calls Dog's sound method (polymorphism)
        
        Dog dog = (Dog) animal;    // Downcasting (Converting Animal reference back to Dog)
        dog.fetch();               // Now Dog-specific method can be called
    }
}

Example 9: Final Classes and Methods (Preventing Inheritance)

// Superclass
class Animal {
    final void sound() {
        System.out.println("Animal makes sound");
    }
}
 
// Subclass
class Dog extends Animal {
    // The following would result in a compile-time error because sound() is final:
    // void sound() { 
    //     System.out.println("Dog barks");
    // }
}
 
public class InheritanceExample9 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sound();  // Calls Animal's sound method
    }
}

Example 10: Inheritance with Interfaces

interface Animal {
    void eat();
}
 
class Dog implements Animal {
    public void eat() {
        System.out.println("Dog eats meat.");
    }
}
 
class Cat implements Animal {
    public void eat() {
        System.out.println("Cat eats fish.");
    }
}
 
public class InheritanceExample10 {
    public static void main(String[] args) {
        Animal dog = new Dog();
        dog.eat();  // Calls Dog's eat method
 
        Animal cat = new Cat();
        cat.eat();  // Calls Cat's eat method
    }
}

Example 11: Abstract Classes in Inheritance

// Abstract superclass
abstract class Animal {
    abstract void sound();  // Abstract method with no body
 
    void sleep() {
        System.out.println("Animal is sleeping");
    }
}
 
// Subclass
class Dog extends Animal {
    void sound() {
        System.out.println("Dog barks");
    }
}
 
public class InheritanceExample11 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sound();  // Calls Dog's implementation of the sound method
        dog.sleep();  // Calls inherited sleep method from Animal
    }
}

Example 12: Multiple Inheritance via Interfaces

interface Swimmer {
    void swim();
}
 
interface Runner {
    void run();
}
 
class Triathlete implements Swimmer, Runner {
    public void swim() {
        System.out.println("Triathlete is swimming");
    }
 
    public void run() {
        System.out.println("Triathlete is running");
    }
}
 
public class InheritanceExample12 {
    public static void main(String[] args) {
        Triathlete athlete = new Triathlete();
        athlete.swim();  // Calls swim method
        athlete.run();   // Calls run method
    }
}

Example 13: Overriding toString() Method (Inheritance from Object Class)

class Person {
    String name;
    int age;
 
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Name: " + name + ", Age: " + age;
    }
}
 
public class InheritanceExample13 {
   
 
 public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        System.out.println(person.toString());  // Calls overridden toString method
    }
}

Example 14: Protected Access Modifier in Inheritance

class Animal {
    protected void eat() {
        System.out.println("Animal is eating");
    }
}
 
class Dog extends Animal {
    void eat() {
        System.out.println("Dog is eating");
    }
}
 
public class InheritanceExample14 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // Calls Dog's eat method
    }
}

Example 15: Inheritance and Exception Handling

class Animal {
    void sound() throws Exception {
        System.out.println("Animal makes sound");
    }
}
 
class Dog extends Animal {
    @Override
    void sound() throws Exception {
        System.out.println("Dog barks");
    }
}
 
public class InheritanceExample15 {
    public static void main(String[] args) {
        try {
            Animal animal = new Dog();
            animal.sound();  // Calls Dog's sound method
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Inheritance in Java allows for the design of more modular, reusable, and hierarchical systems by extending the functionality of existing classes without having to rewrite the code. This is essential for code reuse, polymorphism, and maintaining the DRY (Don't Repeat Yourself) principle.