Table of contents
1.
Introduction
2.
How to Create Final Classes?
2.1.
Declare the Class as Final
3.
Example 1: How to Use a Final Class?
3.1.
How to Use This Class
3.2.
Java
4.
Example 2: What Happens if We Try to Inherit from a Final Class?
5.
Why Does Java Prevent Inheritance from Final Classes?
6.
Advantage of the Final Class
7.
Frequently Asked Questions
7.1.
Can a final class include non-final methods?
7.2.
Is it possible to declare a final class as abstract?
7.3.
How does using a final class affect unit testing?
8.
Conclusion
Last Updated: May 25, 2024
Easy

Final Class in Java

Author Riya Singh
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Java programming language includes several keywords that define the nature & behavior of classes & methods. One such keyword is final. A final class in Java is a type of class that cannot be inherited by other classes. This means once a class is declared as final, it serves as the last form in its inheritance hierarchy.Final classes are often used to prevent unintended modifications to the class structure and behavior.

Final Class in Java

In this article, we will learn the concept of final classes in Java, how to create them, and their advantages with proper examples to understand the usage of final classes.

How to Create Final Classes?

Creating a final class in Java is straightforward. When you declare a class as final, you are telling the Java compiler that this class cannot be extended. No other class can inherit from a final class. Here’s how you do it:

Declare the Class as Final

You use the final keyword in the class definition. 

For example:

public final class Car {
    private String model;
    private int year;
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }
    public String getModel() {
        return model;
    }
    public int getYear() {
        return year;
    }
}


In this example, the Car class is declared as final. This means that no other class can inherit from Car. If you attempt to create a class that extends Car, the compiler will throw an error.
 

  • Why Use Final Classes?: The main reason to use a final class is to prevent the class from being subclassed. This is particularly useful when you have a specific functionality that you do not want to be altered or when the class is not designed to be inherited.
     
  • Compiling & Testing: After declaring your class as final, you can compile and run your Java programs as usual. The compiler will ensure that no other classes can extend your final class, thereby preserving its integrity.


Using final classes is a powerful feature in Java that helps maintain your code's stability and prevent unwanted behaviors due to inheritance.

Example 1: How to Use a Final Class?

Using a final class in Java is similar to using any other class, but with the understanding that it cannot be extended. Here's a practical example to illustrate how you might utilize a final class in a real-world scenario:

Suppose you have a final class named Calculator that provides basic arithmetic operations. Since you want to ensure that the behavior of the calculator is consistent and secure without any subclass altering its functionality, you make it final.

public final class Calculator {
    // Method to add two numbers
    public int add(int num1, int num2) {
        return num1 + num2;
    }

    // Method to subtract two numbers
    public int subtract(int num1, int num2) {
        return num1 - num2;
    }

    // Method to multiply two numbers
    public int multiply(int num1, int num2) {
        return num1 * num2;
    }

    // Method to divide two numbers
    public int divide(int num1, int num2) {
        if (num2 == 0) {
            throw new IllegalArgumentException("Cannot divide by zero.");
        }
        return num1 / num2;
    }
}

How to Use This Class

  • Instantiation: You create an object of the Calculator class.
     
  • Operation: You call its methods to perform calculations.
  • Java

Java

public class Main {
public static final class Calculator {
// Method to add two numbers
public int add(int num1, int num2) {
return num1 + num2;
}

// Method to subtract two numbers
public int subtract(int num1, int num2) {
return num1 - num2;
}

// Method to multiply two numbers
public int multiply(int num1, int num2) {
return num1 * num2;
}

// Method to divide two numbers
public int divide(int num1, int num2) {
if (num2 == 0) {
throw new IllegalArgumentException("Cannot divide by zero.");
}
return num1 / num2;
}
}

public static void main(String[] args) {
Calculator myCalc = new Calculator();
int sum = myCalc.add(5, 3);
int difference = myCalc.subtract(5, 3);
int product = myCalc.multiply(5, 3);
int quotient = myCalc.divide(5, 3);

System.out.println("Sum: " + sum);
System.out.println("Difference: " + difference);
System.out.println("Product: " + product);
System.out.println("Quotient: " + quotient);
}
}
You can also try this code with Online Java Compiler
Run Code

Output

Sum: 8
Difference: 2
Product: 15
Quotient: 1


In this example, the Calculator class functions purely to provide arithmetic results. Making it final ensures that no other class can modify its methods, which is crucial for maintaining the calculator’s reliability.

Example 2: What Happens if We Try to Inherit from a Final Class?

In Java, attempting to inherit from a final class will result in a compile-time error. This is because a final class is designed to be a terminal class in the inheritance chain, meaning it cannot be subclassed. This restriction ensures that the original class's behavior remains unchanged and secure throughout its use in any Java application.

Let's look at an example where you might unintentially try to extend a final class:

Assume we have the Calculator class from the previous example declared as final.

public final class Calculator {
    public int add(int num1, int num2) {
        return num1 + num2;
    }

}


Now, suppose you try to create a new class called AdvancedCalculator that extends Calculator to add more features like calculating the square root or power of numbers:

public class AdvancedCalculator extends Calculator {  // This line will cause a compile error
    public double sqrt(int number) {
        return Math.sqrt(number);
    }
    public int power(int base, int exponent) {
        return (int) Math.pow(base, exponent);
    }
}


When you try to compile this code, the Java compiler will stop you right there with an error message similar to:

error: cannot inherit from final Calculator

Why Does Java Prevent Inheritance from Final Classes?

The main reason is to maintain the integrity and security of the class’s intended functionality. By preventing other classes from inheriting from a final class, Java ensures that the class’s methods and properties cannot be altered or extended in potentially harmful ways. This is particularly important for classes that perform critical functions or handle sensitive data.

This design choice by Java helps in creating robust and secure applications, where certain components are kept stable and unchangeable.

Advantage of the Final Class

  • Security: By marking a class as final, you prevent other developers from altering its implementation by extending it. This is crucial for classes that implement security-sensitive functionality. If you have a class that manages authentication, you wouldn’t want its methods overridden in a way that could compromise security.
     
  • Simplicity: Final classes are easier to understand and maintain because they are not burdened with the complexity of subclasses modifying their behavior. There’s no need to consider the effects of inheritance when updating or debugging the class, which simplifies development tasks.
     
  • Creation of Immutable Objects: Classes designed as immutable (whose states cannot be changed once constructed) can be made final to enforce this property. For example, the String class in Java is final and immutable, meaning you can rely on its value never changing once it’s been initialized.
     
  • Performance Optimization: Java compilers can make certain optimizations for final classes. Knowing that these classes cannot be extended, the compiler can perform method invocations faster, sometimes using inline expansions. This is because there's no need to look up methods in a dynamic dispatch table.
     
  • Stable Software Components: When designing large systems, using final classes helps ensure that certain components remain stable as the software evolves. This stability can make it easier to expand or modify the system without worrying about changes to fundamental behaviors dictated by these classes.
     
  • Encourages Composition Over Inheritance: Java’s use of the final keyword encourages developers to use composition instead of inheritance when designing their systems. Composition involves creating systems by combining objects, which is often more flexible than inheritance. This leads to better separation of concerns and more modular code.

Frequently Asked Questions

Can a final class include non-final methods?

Yes, a final class can still have non-final methods. The final designation prevents the class from being extended, but individual methods within the class can still be overridden if they are inherited from a non-final superclass.

Is it possible to declare a final class as abstract?

No, declaring a final class as abstract is not possible in Java. Abstract classes are meant to be extended to complete their implementation, while final classes cannot be extended. Thus, these two keywords are mutually exclusive.

How does using a final class affect unit testing?

Using final classes can sometimes make unit testing challenging because it prevents mocking classes. If you need to test code that uses final classes, you might have to use real instances of those classes, which can complicate tests or reduce their flexibility.

Conclusion

In this article, we have learned about the concept of final classes in Java and their practical applications. We explored how to declare and use final classes with examples, understood the implications of trying to inherit from such a class, and discussed the advantages that make final classes beneficial in certain programming scenarios. Through these discussions, it's clear that final classes play a vital role in creating secure, stable, and efficient Java applications by ensuring that certain classes remain unchangeable and free from unwanted modifications through inheritance. 

You can refer to our guided paths on the Coding Ninjas. You can check our course to learn more about DSADBMSCompetitive ProgrammingPythonJavaJavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithmsCompetitive ProgrammingOperating SystemsComputer Networks, DBMSSystem Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry Experts.

Live masterclass