Introduction to Java | Inheritance

What is Inheritance in Java?

Inheritance is a mechanism in object-oriented programming (OOP) that allows one class (called the subclass or child class) to inherit the properties and methods of another class (called the superclass or parent class). This allows for code reuse, improves maintainability, and supports a hierarchical class structure.

In Java, inheritance is implemented using the extends keyword, and it helps in establishing relationships between classes. The child class can:

Advantages of Inheritance

Types of Inheritance in Java

Java supports several types of inheritance, allowing you to design classes in different ways. These include:

1. Single Inheritance

Single inheritance is the simplest form of inheritance where a class can inherit from one superclass only. This means that the subclass inherits fields and methods from just one parent class.

Example: Below is a simple example where class Dog inherits from class Animal:

Code Example


        class Animal {
            void eat() {
                System.out.println("This animal eats food.");
            }
        }
        
        class Dog extends Animal {
            void bark() {
                System.out.println("Dog is barking.");
            }
        }
        
        public class Main {
            public static void main(String[] args) {
                Dog dog = new Dog();
                dog.eat();  // Inherited from Animal class
                dog.bark(); // Specific to Dog class
            }
        }
                    

2. Multi-Level Inheritance

Multi-level inheritance occurs when a class inherits from a subclass of another class. This creates a chain of inheritance where each subclass inherits from its immediate parent, which is itself a subclass of another class.

Example: In this example, class Grandchild inherits from class Child, and class Child inherits from class Parent.

Code Example


        class Parent {
            void display() {
                System.out.println("This is the Parent class.");
            }
        }
        
        class Child extends Parent {
            void show() {
                System.out.println("This is the Child class.");
            }
        }
        
        class Grandchild extends Child {
            void greet() {
                System.out.println("This is the Grandchild class.");
            }
        }
        
        public class Main {
            public static void main(String[] args) {
                Grandchild grandchild = new Grandchild();
                grandchild.display();  // Inherited from Parent class
                grandchild.show();     // Inherited from Child class
                grandchild.greet();    // Specific to Grandchild class
            }
        }
                    

3. Hierarchical Inheritance

In hierarchical inheritance, multiple subclasses inherit from a single superclass. This allows different classes to share common functionality defined in the parent class, reducing redundancy.

Example: In this example, class Dog and class Cat both inherit from class Animal, demonstrating how hierarchical inheritance works.

Code Example


        class Animal {
            void eat() {
                System.out.println("This animal eats food.");
            }
        }
        
        class Dog extends Animal {
            void bark() {
                System.out.println("Dog is barking.");
            }
        }
        
        class Cat extends Animal {
            void meow() {
                System.out.println("Cat is meowing.");
            }
        }
        
        public class Main {
            public static void main(String[] args) {
                Dog dog = new Dog();
                dog.eat();  // Inherited from Animal class
                dog.bark(); // Specific to Dog class
                
                Cat cat = new Cat();
                cat.eat();  // Inherited from Animal class
                cat.meow(); // Specific to Cat class
            }
        }
                    

4. Multiple Inheritance (via Interfaces)

Java does not support multiple inheritance through classes, as it could lead to the "diamond problem" (ambiguity in method resolution). However, Java achieves multiple inheritance through interfaces. A class can implement multiple interfaces, allowing it to inherit methods from multiple sources.

Example: In the following example, class Dog implements two interfaces, Animal and Pet, to achieve multiple inheritance.

Code Example


        interface Animal {
            void makeSound();
        }
        
        interface Pet {
            void play();
        }
        
        class Dog implements Animal, Pet {
            public void makeSound() {
                System.out.println("Bark");
            }
            
            public void play() {
                System.out.println("Dog is playing.");
            }
        }
        
        public class Main {
            public static void main(String[] args) {
                Dog dog = new Dog();
                dog.makeSound(); // Output: Bark
                dog.play();      // Output: Dog is playing.
            }
        }
                    

Method Overriding

Method overriding is a feature in Java that allows a subclass to provide a specific implementation of a method that is already defined in its superclass. The method in the subclass should have the same signature (name, parameters, and return type) as the one in the superclass.

Overriding is important for implementing runtime polymorphism, where the JVM dynamically determines which method to call based on the actual object type at runtime, not the reference type.

Code Example


        class Animal {
            void makeSound() {
                System.out.println("Some generic animal sound");
            }
        }
        
        class Dog extends Animal {
            @Override
            void makeSound() {
                System.out.println("Bark");
            }
        }
        
        public class Main {
            public static void main(String[] args) {
                Animal myDog = new Dog();
                myDog.makeSound();  // Output: Bark (overridden method)
            }
        }
                    

5. Abstract Classes and Inheritance

Abstract classes provide a way to declare classes that cannot be instantiated on their own but can serve as a superclass for other classes. An abstract class can contain abstract methods, which are methods that do not have a body and must be implemented by any subclass. This allows you to create a template for other classes to follow, enforcing a structure while providing some shared functionality.

Abstract classes are particularly useful when you want to define a base class that provides common functionality, but you also want to allow subclasses to implement certain methods according to their specific needs.

Code Example


    abstract class Animal {
        abstract void makeSound();
    }
    
    class Dog extends Animal {
        void makeSound() {
            System.out.println("Bark");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Animal dog = new Dog();
            dog.makeSound(); // Output: Bark
        }
    }