Basic Inheritance in Java: A Complete Guide

Introduction

Inheritance is one of the four fundamental principles of object-oriented programming (OOP) in Java, alongside encapsulation, polymorphism, and abstraction. It enables a class (called a subclass or child class) to inherit fields and methods from another class (called a superclass or parent class). This mechanism promotes code reuse, establishes hierarchical relationships between classes, and supports the creation of more specialized types from general ones. Understanding basic inheritance—including how to define parent and child classes, use the extends keyword, and manage constructors—is essential for building modular, maintainable, and extensible Java applications.


1. What Is Inheritance?

Inheritance allows a new class to acquire the properties (fields) and behaviors (methods) of an existing class. The existing class is the superclass, and the new class is the subclass.

Key Benefits

  • Code Reusability: Avoid rewriting common code.
  • Method Overriding: Customize or extend inherited behavior.
  • Hierarchical Organization: Model real-world "is-a" relationships (e.g., a Dog is a Animal).

2. Syntax: The extends Keyword

A subclass is declared using the extends keyword followed by the superclass name.

class Superclass {
// Fields and methods
}
class Subclass extends Superclass {
// Additional or overridden members
}

Note: Java supports single inheritance—a class can extend only one direct superclass.


3. Example: Basic Inheritance

// Superclass
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
}
// Subclass
class Dog extends Animal {
public Dog(String name) {
super(name); // Call superclass constructor
}
public void bark() {
System.out.println(name + " is barking.");
}
}
// Usage
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("Buddy");
myDog.eat();  // Inherited from Animal
myDog.bark(); // Defined in Dog
}
}

Output:
Buddy is eating.
Buddy is barking.


4. The super Keyword

The super keyword is used to refer to the immediate parent class. It has three main uses:

A. Calling Superclass Constructor

public Dog(String name) {
super(name); // Must be the first statement
}

Rule: If the superclass has no no-argument constructor, the subclass must explicitly call a superclass constructor using super().

B. Accessing Superclass Members

If a subclass overrides a method or hides a field, super can access the parent version.

class Animal {
protected String sound = "Generic sound";
public void makeSound() {
System.out.println(sound);
}
}
class Cat extends Animal {
private String sound = "Meow"; // Hides superclass field
public void makeSound() {
System.out.println(sound);        // "Meow"
System.out.println(super.sound);  // "Generic sound"
}
}

5. Method Overriding

A subclass can provide a specific implementation of a method already defined in its superclass. This is called method overriding.

Rules for Overriding

  • The method name, return type, and parameter list must be identical.
  • The access modifier cannot be more restrictive (e.g., cannot override a public method with private).
  • The @Override annotation is optional but recommended for clarity and compile-time checking.
class Vehicle {
public void start() {
System.out.println("Vehicle started.");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Car engine started with key.");
}
}

6. Constructor Chaining in Inheritance

When an object of a subclass is created:

  1. The subclass constructor is called.
  2. It immediately calls the superclass constructor (explicitly with super() or implicitly).
  3. This continues up the inheritance chain to java.lang.Object (the root of all classes).
class A {
A() { System.out.println("A constructor"); }
}
class B extends A {
B() { System.out.println("B constructor"); }
}
class C extends B {
C() { System.out.println("C constructor"); }
}
// Creating new C() outputs:
// A constructor
// B constructor
// C constructor

Note: If no super() call is written, Java inserts super() automatically—but only if the superclass has a no-argument constructor.


7. Inheritance and Access Control

A subclass inherits:

  • All public and protected members (fields and methods) of the superclass.
  • Package-private members, but only if the subclass is in the same package.
  • Never inherits private members (though they exist in the object, they are inaccessible).

Example

class Parent {
private int secret = 100;      // Not inherited
protected int visible = 200;   // Inherited
public void show() { ... }     // Inherited
}

8. The Object Class

In Java, every class implicitly extends java.lang.Object if no explicit superclass is declared. Thus, all objects inherit methods like:

  • toString()
  • equals(Object obj)
  • hashCode()
  • getClass()
  • clone()
  • finalize()

Best Practice: Override toString(), equals(), and hashCode() in meaningful classes.


9. Limitations of Inheritance

  • Single Inheritance Only: Java does not allow a class to extend multiple classes (to avoid the "diamond problem").
  • Tight Coupling: Subclasses depend on superclass implementation, which can reduce flexibility.
  • Fragile Base Class Problem: Changes in the superclass can unintentionally break subclasses.

Alternative: Use composition ("has-a" relationship) when inheritance is not appropriate.


10. Best Practices

  • Favor composition over inheritance when there is no true "is-a" relationship.
  • Use inheritance for true specialization (e.g., SavingsAccount is an Account).
  • Keep superclasses general and stable.
  • Document intended extensibility—not all classes are designed to be subclassed.
  • Prefer protected over public for members meant for subclass use.
  • Always call super() explicitly when needed for clarity.

Conclusion

Inheritance is a powerful mechanism in Java that enables code reuse and logical class hierarchies. By allowing subclasses to inherit and extend the functionality of superclasses, it supports the creation of organized, scalable, and maintainable codebases. However, it must be used judiciously—only when a clear "is-a" relationship exists—and with awareness of its limitations. When combined with other OOP principles like encapsulation and polymorphism, inheritance forms the backbone of robust object-oriented design in Java. Mastering basic inheritance is a critical step toward advanced topics such as polymorphism, abstract classes, and interfaces.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper