final keyword in Java

There are times when you want to control the normal behaviour of classes, methods and variables. Like you may not want the classes to be inherited or methods to be overriden or even variables to lose thier value. final keyword helps you with those purposes.

Based on the use of the final keyword, you can have:

  1. final classes
  2. final methods
  3. final variables

1. final class

When a class is declared final, it can’t be inherited i.e it cannot be used as a superclass for another class. Any attempt to inherit a final class will result in compile time error. It is sometimes desired for safety reasons.

The syntax to declare a class final is:

Depending upon your need you can keep or drop the access modifiers like public or private.


1.1 Example : A final class cannot be inherited

In the example below, Human class is declared final. So this class cannot be extented. Any attempt to do so, would result in a compilation error.

Also note that declaring a class final is solely related to inheritance. It doen’t affect the objects of the class in any way. It doesn’t make them final. Its objects can be manipulated in normal way. E.g: human object of the Human class can be modified like any other object.

The output is :

 


1.2 Example : A class inheriting some other class can be made final

A final class cannot be inherited but a class that inherits another class can be made final. i.e.  it can inherit a class but it cannot be inherited by any other class.

In the example below; Dog, Wolf and Fox inherit a class named Canine but they themselves cannot be inherited because they are declared final.

The output is :

 


1.3 : abstract class vs final class

A class cannot be declared abstract and final at the same time. The reason for this is: Abstract classes are specificially built to be inherited and extended by other classes while a final class cannot be inherited at all. They both serve opposite needs.


2. final method

A method that has been declared final cannot be overriden. You cannot have another method in the inheriting class that has the same name and type signature as the method declared final in the superclass.

Syntax to declare a method final is:

 


2.1 Example : Using final keyword to prevent method overriding

Method overriding : When name and type signatures of a method in the subclass matches the name and type signatures of a method in the superclass, method overriding occurs. The method defined in the subclass hides the method defined in the superclass.

It is a very poweful feature of the Java programming language. But sometimes, it is desirable that a method work and behave in a fixed predefined way and developers must not override that definiton. It may be designed so for security and safety reasons. In those cases a method is declared final.

Example below defines a bird class: It has a method getFeatures() that returns “Lay eggs“.  Since all birds in general lay eggs, it is declared final so that the method cannot be overriden by a class that inherits this class. It has another method getColor() that returns the color of the bird. Since birds can be of any color, it is not declared final. In fact the subclasses override this method depending on the color of the bird.

The output is :

 


2.2 final methods and  inlining

Inlining is a performance enhancement technique. It is the process of replacing the method calls with the bytecode of the subroutine.

If improves performance only when the method is small. Method calls are costly but as the method size increases, the performance benefits of inlining decreases. After the bytecode of the method reaches certain length method calls become cheap as compared to inlining.

Inlining is only possible with final methods. Since Java resolves the calls to methods at run time, the compiler has no way to know bytecodes of which method to use for replacing method calls. But with final methods the definition is fixed as no method overrding is allowed for final methods.

Lets understand this with an example.

The output is :

This is all work of the compiler, You don’t have to do anything for this.


2.3 Difference between a final method and a final class
 final classfinal method
Inheritance:A class which is final cannot be inherited at all.A class that has a final method but itself is not final can be  inherited.
Method overriding:No methods of a final class can be overriden. Since it cannot be inherited, no alternate definition of methods can be provided.A final method is explicitly made for this purpose.

These two can be mix up as well. A final class can have a final method.

 


2.4 Example: A class that has a final method but itself is not final can be inherited.

In the example below, class M has two methods. One of them is final and they both would be inherited by another class N that subclasses M. However the final method could not be overriden.

The output is :

 


3. final Variables

A variable can be declared final to make them constant. Once a final variable has been assigned a value, it cannot be changed. The syntax to declare a variable final is:


In general final fields are written in Upper case to distinguish them from non-constant variables. Like :

 


3.1 final instance variables

A final instance variable can be initialized in two ways:

  • At the time of variable declaration
  • Inside the constructor:

The output is :

Any attempt to initialize a final instance variable anywhere else would result in a compilation error.


The option to initialize an instance variable inside the constructor is very useful. It allows the user to declare some fields which can be initialized only once at the time of object creation, after that they can’t be modified.

It has many practical uses; like creating a Student class and making the roll number field final which is initialized inside the constructor. So when an object is created, it is given a roll number which will be fixed for its entire life.

Output :

 


3.2 final static variables

A final static / class variable can be initialized in two ways:

  • At the time of variable declaration.
  • Inside a static block.

The output is :

Any attempt to initialize a final static variable anywhere else would result in a compilation error.

Note: A final static variable cannot be initialized inside a constructor because a static variable is shared by all the instances of a class. And any attempt to initialize that static variable inside any constructor would result in re-initialization of the same static variable.

 


3.3 final local variable in a method

A local variable of a method that is declared final, can be assigned a value only once. It may be initialized at the time of declaration or at some other point but only once.

The output is :

 


3.4 final parameters to a method

The method parameter that has been declared final cannot be changed inside the method body.

The output is :

Note : If the parameter is of reference type then this reference is constant i.e. it cannot be assigned to any other object inside the method body.


3.5 final primitive variables

Primitive variables like int, double, char etc can be declared final. And they are essentially constant. Once they have been assigned a value, it cannot be changed. Any attempt to modify the variable results in a compilation error.

Output :

 


3.6 final reference variables

When a variable of a reference type is declared final, it cannot be reassigned to any other variable. The reference is essentially constant i.e. the reference cannot be changed.

Note : A object reference declared final cannot change but the object itself can be modified.

Output :

 


3.7 final arrays

Arrays are implemented as objects. So same features of final apply to arrays as well. When an array is declared final, the array variable cannot be assigned any other array. But the individual members inside the array can be modified.

Output :

 


3.8 Example : How to make a reference variable fully final

You can make a reference variable fully final by doing two things :

  1. Declare all the instance variables of the class as final.
  2. When making an instance of that class make the variable reference final.

After these two steps, you can expect the behaviour of a reference variable like that of primitive variable as far as constantness is concerned.

In the example below neither the reference p1 can be changed nor the variables inside that reference can be changed.

Output :

 


Miscellaneous topics:

1. Blank final variables

A final variable which has been declared but not initialized is known as blank final variable. A blank final variable can be assigned only once. Any attempt to re-initialize a blank final variable results in compilation error.

It comes in three forms:

  1. Blank instance varaible : can be initialized inside a constructor.
  2. Blank static variable : can be initialized inside a static block
  3. Blank local variable : can be initialized at any one position within the method.

2. foreach loop and final

We can use final with the iterator of the foreach loop. It works like this :

A value is assigned to the iterator variable. The variable is constant for any one iteration. It cannot be modified within the body of the for loop. Then it goes out of scope and a new variable with the same name and different value is created.

Output :

 


Some Points to Remember

  • A constructor cannot be declared final.
  • Any variable declared inside an interface is implictly final. No need to use final keyword.
  • final, finally and finalize are three different keywords. finally is used for exception handling and finalize is used during garbage collection.

For C++ programmers : final in Java vs const in C++

C, C++ offer a construct similar to final keyword in Java. This is const keyword. const in C++ for the most part behaves similar to final in Java, but they have some significant differences. So be careful.


Summary

  • final classes cannot be inherited.
  • final methods cannot be overloaded.
  • final variables cannot be re-initialized.
  • All type of final variables can be either initialized at the time of declaration or
    • Inistnace variables can be initialized inside a constructor.
    • Static variables can be initialized inside the a static block.
    • Local variables can be initialized later, but only once.
    • Method parameters have no other ways for initialization.
  • Behaviour of final primitive and final reference variables differs:
    • In case of primitive variables, it is essentially constant.
    • In case of reference variables, only reference is constant, referred objects can be modified.