Java Inheritance Tutorial: explained with examples
Tags: java, tutorial, oop
Published: 2021-01-28 18:55:34

Inheritance is the process of building a new class based on the features of another existing class. It is used heavily in Java, Python, and other object-oriented languages to increase code reusability and simplify program logic into categorical and hierarchical relationships. 

However, each language has its own unique way of implementing inheritance that can make switching difficult.

Today, we'll give you a crash course on the uses of inheritance in Java programming and show you how to implement the core inheritance tools like typecasting, method overriding, and `final` entities.

**Here’s what we’ll cover today:**

* [What is Inheritance?](#what)
* [Inheritance in Java](#java)
* [Java inheritance examples](#examples)
* [Advanced concepts to learn next](#next)

<br>

<h4><b> Adopt Java in half the time </b> </h4>

Get hands-on practice with our best Java content tailored to current developer skill levels.

<b> [Java for Programmers](https://www.educative.io/path/java-for-programmers) </b>

<br>


<br>
 
<a name="what"></a>
## What is Inheritance?
Inheritance is a mechanism that **allows one class to inherit properties** or behaviors from another class.  Multiple classes can inherit from the same parent class, forming a tree-like hierarchy structure. Inheriting classes can add features beyond those inherited from the parent class to allow for unique behavior.

 Inheritance is essential to advanced [Object Oriented Programming](https://www.educative.io/blog/object-oriented-programming) (OOP) as it allows you to reuse one class's features across your program without replicating code.

Inheritance is often used to represent categories (parent classes) and sub-categories (subclasses). The parent class sets the features present in all objects regardless of subcategory, while each subclass represents a smaller, more specific category.

For example, you could create the class `Car` that specifies `wheels = 4` and a subclass `Sedan` that includes the attribute `doors = 4`. The flow of inheritance relationships often reflects the logical relationship similar to squares and rectangles; in this case, all sedans are cars, but not all cars are sedans.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/113l5su22mfwxk3jv3ew.PNG)

Inheritance has three main advantages:

1. **Reusability:** Inheritance allows you to reuse the features of an existing class an unlimited number of times across any class that inherits that class. You can keep consistent functionality across all objects of the same type without rewriting the code.
2. **Code Structure:** Inheritance provides a clear, drawable logic structure for your program. It allows developers to understand your code as a collection of related but unique categories rather than simply a block of code.
3. **Data Hiding:** The base class can be set to keep some data private so that it cannot be altered by the derived class. This is an example of encapsulation, where access to data is restricted to only the classes that need it for their role.

<br>
 
<a name="java"></a>

## Inheritance in Java

Each programming language has slightly different terminology for inheritance.
In Java, the parent class is called the **superclass**, and the inheritor class is called the **subclass**. Developers may also call superclasses base or parent classes and subclasses derived or child classes. 

Subclasses are linked to superclasses using the `extends` keyword during their definition.  Subclasses can define new local methods or fields to use or can use the **`super`** keyword to call inherited methods or the super constructor.

```java
class b {
// implementation of inheritedMethod()
}
class a extends b
{  
   inheritedMethod();
}  
```

<br>

### When to use `super` keyword

`super` is essentially a "previous value" button called from within a child class that allows you to read and access features from the parent class regardless of their value in the current child class.

The `super` keyword is used to:
- **Access parent class fields**: `super.var` reads the value of `var` set in the parent class, while `var` alone reads the modified value from the child.
- **Calling a parent class method**: `super.method()` allows the child to access the parent class implementation of `method()`. This is only required if the child class also has a method with the same name.
- **Using Constructors**: This allows you to create new instances of the parent class from within a child class.

As a refresher, [constructors](https://www.educative.io/blog/object-oriented-programming-concepts-java#constructors) in Java are special methods used to initialize objects. Calling the super constructor creates a new object that requires all the fields defined in the parent class constructor. 

You can then add additional fields in other statements to make the child instance more specific than the parent. Essentially, it allows you to use the parent class constructor as a template for your child class constructor.

```java
    public Car(String make, String color, int year, String model, String bodyStyle) {
        super(make, color, year, model);  //parent class constructor
        this.bodyStyle = bodyStyle;       
    }
```

<br>

### Types of Inheritance

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xkfxp9ir3yk46cay5mcx.PNG)

There are several types of inheritance available in Java:

* **Single inheritance** is when a single subclass inherits from a superclass, forming one layer of inheritance.

* **Multilevel Inheritance** is when a superclass is inherited by an intermediate class, which is then inherited by a derived class, forming 3 or more levels of inheritance.

* **Hierarchical inheritance** is when one superclass serves as a baseline for multiple specific subclasses. This is the most common form of inheritance.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yrj4k6ek3x60jdty1fyl.PNG)

There are also two other types of inheritance that are only available in Java through a combination of class and interface inheritance.

* **Multiple inheritance**, when a single subclass inherits from multiple parent classes.

* **Hybrid inheritance**, a mix of two or more of the above kinds of inheritance.

Java does **not support multiple inheritance** with classes, meaning both of these types of inheritance are impossible with Java classes alone. However, a subclass can inherit more than one interface (an abstract class). You can therefore simulate multiple inheritance if you combine the use of interfaces and classes.

<br>
 
<a name="examples"></a>

## Java inheritance examples

To help you understand inheritance more, let's jump into some code examples. Look for the syntax components of inheritance we've seen so far, like `super` and shared methods.

To declare inheritance in Java, we simply add `extends [superclass]` after the subclass's identifier. 

Here's an example of a class `Car` that inherits from base class `Vehicle` using private strings and getter/setter methods to achieve encapsulation.

```java
// Base Class Vehicle
class Vehicle {

  // Private Fields
  private String make; 
  private String color; 
  private int year;      
  private String model;   


  // Parameterized Constructor
  public Vehicle(String make, String color, int year, String model) {
    this.make = make;
    this.color = color;
    this.year = year;  
    this.model = model; 
  }

  // public method to print details
  public void printDetails() {
    System.out.println("Manufacturer: " + make);
    System.out.println("Color: " + color);
    System.out.println("Year: " + year);
    System.out.println("Model: " + model);
  }
  
}

// Derived Class Car
class Car extends Vehicle {

  // Private field
  private String bodyStyle;

  // Parameterized Constructor
  public Car(String make, String color, int year, String model, String bodyStyle) {
    super(make, color, year, model);  //calling parent class constructor
    this.bodyStyle = bodyStyle;       
  }

  public void carDetails() {  //details of car
    printDetails();         //calling method from parent class
    System.out.println("Body Style: " + bodyStyle);
  }
  
}

class Main {

  public static void main(String[] args) {
    Car elantraSedan = new Car("Hyundai", "Red", 2019, "Elantra", "Sedan"); //creation of car Object
    elantraSedan.carDetails(); //calling method to print details
  }
  
}
```

This is an example of single inheritance, as only one object inherits from the parent class. On **line 37**, you can see that we use `super` to call the superclass constructor that simplifies our `Car` constructor. You can also see how `Car` has access to the `Vehicle` class `printDetails()` method on **line 42**.

> `printDetails()` can be called without `super` because `Car` does not have its own implementation of `printDetails()`. The `super` keyword is only needed when the program must decide which version of the method is being used.

<br>

### Typecasting in Java
Java also allows you to reference a subclass as an instance of its superclass, essentially treating the subclass as if it were of the superclass type. This process is known as **typecasting**. It is a great way to create modular code as you can write code that will work for any subclass of the same parent.  For example, you can reference a `Car` type variable as a `Vehicle` type object. 

```java
Car car     = new Car();
Vehicle vehicle = car;
```

We first create a `Car` instance then assign that instance to a `Vehicle` type variable. Now the `Vehicle` variable reference points to the `Car` instance. This allows you to treat any subclass of `Vehicle` as the same `Vehicle` type, even if you don't know which subclass of `Vehicle` it is. 
The two types of typecasting are upcasting and downcasting.

**Upcasting** is when you treat a child class as if it were an instance of the parent class, like our previous example. Any fields unique to the child class will be hidden to let them fit the mold of the parent class.

**Downcasting** is when you treat an instance of the parent class as if it were one of its child classes. While any subclass can be upcast, only objects that were originally subclass typed can be downcast. 

In other words, an object can be downcast if the object was originally of the subclass type but was later upcast to the parent class. 

```java
//valid code
Car car = new Car();
// upcast to Vehicle
Vehicle vehicle = car;
// downcast to car again
Car car2 =  (Car) vehicle;
```

The upcast object still retains the fields it had and therefore can be added back to make it a valid object of the child class type again. 

However, objects that were originally of the parent class do not have values for any essential fields unique to the child class. As a result, it will compile but will throw an error at runtime.

<br>

### Overriding methods in Java

Sometimes we'll need one of our subclasses to edit the behavior of an inherited method. Java lets us do this by overriding existing methods by creating new methods of the same name. It also allows us to provide class implementations of abstract methods from interfaces.

```java
class Parent {
  void myMethod() {
    //original implementation
  }
}
class Child extends Parent {
  @override
  void myMethod() {
    //new implementation
  }
}
```


Method overriding is a fundamental tool when implementing polymorphism, a design principle that allows for different classes to have unique implementations for the same method. If we break down the word, "poly" means many, and "morph" means form. 

In simplest terms, [polymorphism](https://www.educative.io/blog/object-oriented-programming#four) means having many class-specific forms of a process to accomplish the same task.

Here are the features a program must have to allow method overriding:

- Method Overriding needs inheritance and there should be at least one derived class.
- Derived class(es) must have the same declaration, i.e., access modifier, name, same parameters, and same return type of the method as of the base class.
- The method in the derived class or classes must each have a different implementation from each other.
- The method in the base class must need to be overridden in the derived class.
- Base class/method must not be declared as the `Final` class.
To override a method in Java, define a new method with the same name as the method you wish to override and add the `@Override` tag above it.

Here, you can see an example of how we can create class-specific behavior for the same method call. Our method call is always `getArea()` however the implementation of the method depends on the class of shape being evaluated.

```java
// A sample class Shape which provides a method to get the Shape's area
class Shape {
  public double getArea() {
    return 0;
  }
}
// A Rectangle is a Shape with a specific width and height
class Rectangle extends Shape {   // extended form the Shape class
  private double width;
  private double height;
  public Rectangle(double width, double height) {
    this.width = width;
    this.height = height;
  }
  public double getArea() {
    return width * height; 
  }
}
// A Circle is a Shape with a specific radius
class Circle extends Shape {
  private double radius;
  public Circle(double radius) {
    this.radius = radius; 
  }
  public double getArea() {
    return 3.14 * radius * radius; 
  }
}
class driver {
  public static void main(String args[]) {
    Shape[] shape = new Shape[2]; // Creating shape array of size 2
    shape[0] = new Circle(2); // creating circle object at index 0
    shape[1] = new Rectangle(2, 2); // creating rectangle object at index 1
    // Shape object is calling children classes method
    System.out.println("Area of the Circle: " + shape[0].getArea());
    System.out.println("Area of the Rectangle: " + shape[1].getArea());
  }
}
```


The advantages of method overriding are:

- Each derived class can give its own specific implementations to inherited methods, without modifying the parent class methods.
- For any method, a child class can use the implementation in the parent class or make its own implementation. This option offers you more flexibility in designing solutions.


<br>

### The `final` keyword

In Java, the `final` keyword can be used while declaring a variable, class, or method to make the value unchangeable. The value of the entity is decided at initialization and will remain immutable throughout the program. Attempting to change the value of anything declared as `final` will throw a compiler error.

```java
// declaring a final variable
class FinalVariable {
        final int var = 50;
        var = 60 //This line would give an error
}
```

The exact behavior of `final` depend on the type of entity:
- **`final` Parameter** cannot be changed anywhere in the function
- **`final` Method** cannot be overridden or hidden by any subclass
- **`final` Class** cannot be a parent class for any subclass

```java
final boolean immutable = true;
boolean mutable = immutable;
```

While the value of `final` entities cannot be changed, they can be used to set the value of non-`final` variables. This property makes it helpful for solving data mutability problems where multiple sections of code need to reference the same entity to function. 

You can set the sections to reference the `final` version of the entity, use it to create a non-`final` entity copy, then manipulate that for any operations. Using `final` ensures that the original shared reference remains the same so that each piece can behave consistently.

<br>
 
<a name="next"></a>


## Advanced concepts to learn next

Inheritance is a powerful tool in Java and is essential to understand advanced OOP designs. Some next concepts to explore on your Java development journey are:

- Abstraction and interfaces
- Aggregation
- Composition
- [Java 8 APIs](https://www.educative.io/blog/master-stream-api-and-beyond)
- Advanced access modifiers

To help you understand these and other advanced concepts, we've created the [**Java for Developers Path**](https://www.educative.io/path/java-for-programmers). Within, you'll find a collection of our finest Java content on topics like OOP, multithreading, recursion, and new Java 8 features. These lessons are chosen from across our course library, allowing you to learn from our best material for each concept.

By the end, you'll have the skills and hands-on experience needed to ace your next Java interview.

*Happy learning!*

<br>

### Continue reading about Java

- [Java Multithreading & Concurrency: Cracking senior interviews](https://www.educative.io/blog/java-multithreading-and-concurrency-what-to-know-for)
- [Java Agile Development: Data management with Java domain models](https://www.educative.io/blog/java-agile-development)
- [Ace the top 15 Java algorithm questions for coding interviews](https://www.educative.io/blog/ace-top-15-java-algorithm-questions)