Java > Object-Oriented Programming (OOP) > Inheritance > Super and Subclasses

Inheritance Example: Animal and Dog

This example demonstrates inheritance in Java, where a Dog class extends an Animal class. The Dog class inherits properties and methods from the Animal class and can also define its own unique characteristics and behaviors. The use of super() is also demonstrated to call the parent class's constructor.

Base Class: Animal

This is the base class, Animal. It has a name property and a makeSound() method. The constructor takes a name as an argument and initializes the animal's name.

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
        System.out.println("Animal constructor called for " + name);
    }

    public String getName() {
        return name;
    }

    public void makeSound() {
        System.out.println("Generic animal sound");
    }
}

Subclass: Dog

This is the subclass, Dog, which extends Animal. It inherits the name property and the makeSound() method. It also has its own breed property and a fetch() method. The @Override annotation indicates that the makeSound() method is overriding the method from the Animal class. The super(name) call ensures the Animal constructor is called to initialize the inherited name property. The Dog constructor takes both a name and a breed to initizalize a Dog object.

public class Dog extends Animal {
    private String breed;

    public Dog(String name, String breed) {
        super(name); // Call the constructor of the Animal class
        this.breed = breed;
        System.out.println("Dog constructor called for " + getName() + ", breed: " + breed);
    }

    public String getBreed() {
        return breed;
    }

    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }

    public void fetch() {
        System.out.println(getName() + " is fetching the ball!");
    }
}

Main Method (Example Usage)

This Main class demonstrates how to create instances of both Animal and Dog. It shows how the Dog object can use the overridden makeSound() method and its own fetch() method, as well as the inherited getName() method.

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal("Generic Animal");
        animal.makeSound(); // Output: Generic animal sound

        Dog dog = new Dog("Buddy", "Golden Retriever");
        dog.makeSound(); // Output: Woof!
        dog.fetch(); // Output: Buddy is fetching the ball!

        System.out.println("Dog's name: " + dog.getName()); // Output: Dog's name: Buddy
        System.out.println("Dog's breed: " + dog.getBreed()); // Output: Dog's breed: Golden Retriever
    }
}

Concepts Behind the Snippet

Inheritance is a fundamental concept in OOP that allows a class (subclass or derived class) to inherit properties and methods from another class (superclass or base class). It promotes code reuse and establishes an 'is-a' relationship between classes (e.g., a Dog 'is a' Animal). super() is used to call the constructor of the parent class from the constructor of the child class.

Real-Life Use Case

Consider a game development scenario. You might have a base class called GameObject with properties like x, y, and health. Then, you could create subclasses like Player and Enemy that inherit these properties and add their own specific behaviors (e.g., Player might have a move() method, while Enemy might have an attack() method). This avoids redundant code and makes it easier to manage the game entities.

Best Practices

  • Favor composition over inheritance when possible. Deep inheritance hierarchies can become difficult to maintain.
  • Use the @Override annotation when overriding methods to help catch errors at compile time.
  • Ensure that the base class is well-designed and provides a solid foundation for its subclasses.
  • Avoid inheriting from classes that are not designed for inheritance (e.g., classes marked as final).

Interview Tip

Be prepared to explain the 'is-a' relationship in the context of inheritance. For example, a Dog 'is a' Animal, but a Wheel 'is not a' Car (composition would be more appropriate for the Wheel-Car relationship). Also, understand the difference between inheritance and polymorphism.

When to Use Them

Use inheritance when you have a clear 'is-a' relationship between classes and you want to reuse code from a base class. It's especially useful when you want to create a hierarchy of related classes with shared functionality.

Memory Footprint

Inheritance can slightly increase the memory footprint of objects because subclasses inherit the properties of their superclasses. However, the memory overhead is usually minimal compared to the benefits of code reuse and organization.

Alternatives

  • Composition: Instead of inheriting from a class, a class can contain an instance of another class as a member variable. This allows for greater flexibility and avoids the tight coupling that can occur with inheritance.
  • Interfaces: Interfaces define a contract that classes can implement. This allows for multiple inheritance of behavior (but not state).

Pros

  • Code Reuse: Avoids duplication of code by inheriting properties and methods from a base class.
  • Organization: Helps organize code into a hierarchy of related classes.
  • Polymorphism: Allows objects of different classes to be treated as objects of a common type.

Cons

  • Tight Coupling: Can lead to tight coupling between classes, making it harder to modify or extend the code.
  • Fragile Base Class Problem: Changes to the base class can have unintended consequences for its subclasses.
  • Increased Complexity: Deep inheritance hierarchies can become difficult to understand and maintain.

FAQ

  • What is the difference between inheritance and composition?

    Inheritance establishes an 'is-a' relationship, while composition establishes a 'has-a' relationship. Inheritance is a stronger form of coupling than composition. Composition is generally preferred when possible, as it offers greater flexibility and reduces the risk of the fragile base class problem.
  • What is the purpose of the super() keyword?

    The super() keyword is used to call the constructor of the parent class from the constructor of the child class. It ensures that the parent class's initialization logic is executed. It can also be used to access members (methods or variables) of the superclass that have been hidden by members of the subclass.
  • Can a class inherit from multiple classes in Java?

    No, Java does not support multiple inheritance of classes. A class can only inherit from one direct superclass. However, a class can implement multiple interfaces, which allows it to inherit multiple behaviors but not state.