Inheritance in Java is a modern concept that every Java developer may encounter early on. It is about building relationships between classes to enable reuse of existing code and structure application logically. Do you know how? This blog explains everything about inheritance in Java, including its definition, key terminologies, types, and more. Let's begin with a basic introduction to inheritance in Java.
Inheritance in Java is a mechanism where one class acquires the properties (fields) and behaviors (methods) of another class. Think of it as passing down traits from a parent to a child in the real world. In terms of object-oriented programming, this means a child class can automatically get access to the code defined in a parent class.
This relationship is often referred to as an is-a relationship like a Java is-a programming language. The class that inherits features is called the subclass and the class whose features are inherited is known as the superclass. In this programming language, one should use the extends keyword to establish this relationship between classes.
Now you might be wondering why inheritance is such an important concept of the Java programming language. Here are the perfect use cases and benefits of this concepts:
Code reusability is one of the biggest advantages. With this benefit, developers can use the same code multiple times across different classes. They can also define common attributes and methods in a superclass and subclasses that can be simply reused. This helps to save time and minimize potential errors.
Inheritance facilitates method overriding, which is a key aspect of polymorphism. It allows a subclass to provide a specific implementation for a method that is already defined in its superclass. This means you can have a general method in the parent and specialized versions in children.
When code is reused, it is easier to maintain. If one needs to change a common behavior, they only have to change it in the superclass and all subclasses automatically get the update. It also makes the code more extensible, as they can easily add new subclasses that inherit common functionalities.
Inheritance helps in organizing classes into a logical, tree-like structure that reflects real-world hierarchies. For instance, car, bike and truck can all inherit from a common vehicle class.
Moving forward comes the key terminologies related to inheritance in Java. It is important to understand them to make good use of this powerful mechanism. Consider the following:
Related Article- How to Learn Java from Scratch
Inheritance works by creating a connection between two classes. When a subclass extends a superclass, it effectively gains access to all the public and protected members of the superclass. It also inherits default members if both classes are in the same package. private members of the superclass are not inherited by the subclass; they remain encapsulated within the superclass.
On creating an object of the subclass memory is allocated for both the subclass's own unique members and for the inherited members from the superclass. However, a subclass's constructor must explicitly or implicitly invoke a constructor of its superclass using the super() call. If you don't explicitly call super(), the compiler automatically inserts a call to the superclass's default (no-argument) constructor.
Here is an example of using inheritance in Java:
// Superclass
class Animal {
void eat() {
System.out.println("Animal eats food.");
}
}
// Subclass
class Dog extends Animal {
void bark() {
System.out.println("Dog barks.");
}
}
public class InheritanceDemo {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.eat(); // Inherited method from Animal
myDog.bark(); // Own method of Dog
}
}
Output:
|
Animal eats food. Dog barks. |
Explanation:
Here the Dog class extends the Animal class. This means Dog inherits the eat() method from Animal. When we create a Dog object, we can call both its own bark() method and the inherited eat() method. It demonstrates how the Dog gains behaviors from Animal.
Inheritance is widely used in real-world software applications to reduce duplicate code and build logical relationships between classes. Consider an online shopping application where different types of users share common functionalities.
// Parent Class
class User {
void login() {
System.out.println("User logged in.");
}
}
// Child Class
class Customer extends User {
void placeOrder() {
System.out.println("Order placed.");
}
}
public class EcommerceDemo {
public static void main(String[] args) {
Customer c = new Customer();
c.login();
c.placeOrder();
}
}
In this example, the Customer class inherits the login() method from the User class. This avoids writing the same login functionality repeatedly in multiple classes.
Still confused about how different inheritance types work or having some doubts? This section will help you gain a good understanding with examples. Java supports several types of inheritance, but it is important to note how multiple and hybrid inheritance are achieved.
Single inheritance involves a class extending only one other class. It is the simplest form of inheritance that represents a straightforward is-a relationship. For instance:
// Superclass
class Vehicle {
void start() {
System.out.println("Vehicle started.");
}
}
// Subclass
class Car extends Vehicle {
void drive() {
System.out.println("Car is driving.");
}
}
public class SingleInheritanceDemo {
public static void main(String[] args) {
Car myCar = new Car();
myCar.start(); // Inherited from Vehicle
myCar.drive(); // Own method
}
}
Output:
|
Vehicle started. Car is driving. |
Multilevel inheritance involves a class inheriting from a class, which in turn inherits from another class. This forms a chain of inheritance. For instance:
// Grandparent Class
class Animal {
void breathe() {
System.out.println("Animal is breathing.");
}
}
// Parent Class
class Dog extends Animal {
void bark() {
System.out.println("Dog is barking.");
}
}
// Child Class
class Labrador extends Dog {
void play() {
System.out.println("Labrador is playing.");
}
}
public class MultilevelInheritanceDemo {
public static void main(String[] args) {
Labrador myLab = new Labrador();
myLab.breathe(); // Inherited from Animal
myLab.bark(); // Inherited from Dog
myLab.play(); // Own method
}
}
Output:
|
Animal is breathing. Dog is barking. Labrador is playing. |
Hierarchical inheritance involves multiple classes inherited from a single parent class. This is useful when you have several specialized classes that share common base functionality. For instance:
// Parent Class
class Shape {
void draw() {
System.out.println("Drawing a shape.");
}
}
// Child Class 1
class Circle extends Shape {
void calculateArea() {
System.out.println("Calculating circle area.");
}
}
// Child Class 2
class Rectangle extends Shape {
void calculatePerimeter() {
System.out.println("Calculating rectangle perimeter.");
}
}
public class HierarchicalInheritanceDemo {
public static void main(String[] args) {
Circle myCircle = new Circle();
myCircle.draw(); // Inherited from Shape
myCircle.calculateArea();
Rectangle myRectangle = new Rectangle();
myRectangle.draw(); // Inherited from Shape
myRectangle.calculatePerimeter();
}
}
Output:
|
Drawing a shape. Calculating circle area. Drawing a shape. Calculating rectangle perimeter. |
Java does not directly support multiple inheritance. This means a class cannot directly extend more than one superclass to avoid complex issues like the Diamond Problem. However, it achieves the concept of multiple inheritance using interfaces. It allows classes to follows multiple contracts. For instance:
// Interface 1
interface Swimmer {
void swim();
}
// Interface 2
interface Walker {
void walk();
}
// Class implementing multiple interfaces
class Duck implements Swimmer, Walker {
@Override
public void swim() {
System.out.println("Duck is swimming.");
}
@Override
public void walk() {
System.out.println("Duck is walking.");
}
}
public class MultipleInheritanceDemo {
public static void main(String[] args) {
Duck myDuck = new Duck();
myDuck.swim();
myDuck.walk();
}
}
Output:
|
Duck is swimming. Duck is walking. |
Hybrid inheritance is generally a suite of two or more than two types of inheritance. Since Java does not support multiple inheritance through classes, hybrid inheritance involving multiple class extensions is also not directly possible. For instance:
// Grandparent Class (for hierarchical part)
class Creature {
void exist() {
System.out.println("Creature exists.");
}
}
// Parent Class (for hierarchical part)
class Bird extends Creature {
void fly() {
System.out.println("Bird is flying.");
}
}
// Interface 1 (for 'multiple' part)
interface Singer {
void sing();
}
// Interface 2 (for 'multiple' part)
interface Dancer {
void dance();
}
// Child Class (combining hierarchical and multiple interface implementation)
class Nightingale extends Bird implements Singer, Dancer {
@Override
public void sing() {
System.out.println("Nightingale sings melodiously.");
}
@Override
public void dance() {
System.out.println("Nightingale dances gracefully.");
}
}
public class HybridInheritanceDemo {
public static void main(String[] args) {
Nightingale myBird = new Nightingale();
myBird.exist(); // From Creature
myBird.fly(); // From Bird
myBird.sing(); // From Singer interface
myBird.dance(); // From Dancer interface
}
}
Related Article: Methods in Java Programming
Still wondering whether to use inheritance or not? This table will help you make a good understanding.
| Feature | Pros | Cons |
| Code Reusability | Minimizes code replications and promotes structured development. | Can lead to over-reliance on inheritance, missing alternative patterns. |
| Polymorphism | Enables method overriding for specific behaviors in subclasses. | Can make code harder to debug if method resolution is unclear. |
| Maintainability | Changes in the superclass propagate to all subclasses. | The "Fragile Base Class" problem: superclass changes can break subclasses. |
| Extensibility | Easy to add new functionalities by creating new subclasses. | Deep inheritance hierarchies can become rigid and hard to manage. |
| Code Organization | Provides a logical, hierarchical structure for classes. | Can lead to complex, tightly coupled relationships. |
| No Multiple Inheritance | Avoids the "Diamond Problem" of ambiguity. | Limits direct class inheritance from multiple sources. |
| Tight Coupling | Subclasses are tightly coupled to their superclasses. | Makes it harder to change or refactor superclasses without affecting children. |
Apart from Inheritance, composition is also a fundamental concept in Java that facilitates code reuse and effective application design. Many beginners often get confused about when to use which, as both aim to reduce duplication but in different ways. Choosing the right approach is important for writing clean, flexible, and maintainable Java applications. Let's understand their differences clearly.
| Basis | Inheritance | Composition |
| Relationship | Represents an is-a relationship between classes. | Represents a has-a relationship between objects. |
| Implementation | Achieved using the extends keyword. | Achieved by creating objects of other classes. |
| Coupling | Creates tight coupling between parent and child classes. | Promotes loose coupling between classes. |
| Flexibility | Less flexible as changes in the superclass affect subclasses. | More flexible and easier to modify or extend. |
| Code Reusability | Reuses code through class hierarchy. | Reuses code by delegating work to other objects. |
| Maintenance | Harder to maintain in deep inheritance hierarchies. | Easier to maintain and refactor. |
| Best Use Case | When there is a clear and stable is-a relationship. | When behavior needs to change or combine dynamically. |
In general, inheritance should be used carefully and only when there is a strong logical relationship between classes. Composition is often preferred in real-world applications because it offers better flexibility and reduces the risk of unexpected issues when the code evolves over time.
Read Also- Introduction to Encapsulation in Java
While inheritance is powerful, modern Java development encourages using it carefully. Overusing inheritance can lead to rigid and tightly coupled code. Here are some best practices every developer should follow:
In modern software design, inheritance is used selectively and often combined with interfaces and composition for better flexibility.
The final keywords play an important role in controlling inheritance in Java. It helps prevent unwanted modification or extension of classes and methods.
This is widely used in real-world applications to ensure security, immutability, and stable design.
This article has provided a comprehensive explanation of inheritance in Java, covering its definition, why and how it's used, key terminologies, and the different types supported. Understanding this concept is fundamental for every Java developer. To gain more knowledge and build better skills, refer to our Java tutorial for beginners. It will help you to understand all the essential concepts of this programming language.
Related Articles
It promotes code reusability, achieves runtime polymorphism through method overriding, and establishes a clear is-a relationship between classes. This all leads to better organized and more maintainable code.
It does not directly support multiple inheritance. The ability to implement multiple behaviors are achieved through interfaces where a class can implement multiple interfaces.
The extends keyword is used for inheritance between classes, indicating that one class is a subclass of another. The implements keyword is used when a class adopts the contract of an interface.
Java does not support multiple inheritance using classes. It can be achieved using interfaces.
Inheritance in OOP allows one class to use the features of another class. It helps reuse code and organize programs better.