Detailed Explanation and Example of final Keyword in Java

  • 2021-07-06 10:50:03
  • OfStack

final in Java you can declare member variables, methods, classes, and local variables. 1 Once you declare a reference as final, you cannot change the reference. If you try to initialize the variable again, the compiler will report a compilation error.
The meaning of final varies slightly in different scenarios, but generally speaking, it means "immutable".

1. final variable

Anything that declares final for a member variable or a local variable (called a local variable in a method or in a code block) is called an final variable. The final variable is often used with the static keyword 1 as a constant. A variable modified with the final keyword can only be assigned once, and its value cannot be changed during its lifetime.
However, the effect of the final keyword varies slightly when it comes to primitive and reference types. For example:


class Value {
  int v;
  public Value(int v) {
    this.v = v;
  }
}
public class FinalTest {
  final int f1 = 1;
  final int f2;
  public FinalTest() {
    f2 = 2;
  }
  public static void main(String[] args) {
    final int value1 = 1;
    // value1 = 4;
    final double value2;
    value2 = 2.0;
    final Value value3 = new Value(1);
    value3.v = 4;
  }
}

In the above example, after assigning the initial value to value1, we can no longer modify the value of value1 for the data modified by final in main method, and the final keyword plays a constant role. From value2, we can see that variables modified by final can not be assigned at declaration time, that is, they can be declared first and then assigned. value3 is a reference variable. Here we can see that when final modifies a reference variable, it only limits that the reference of the reference variable cannot be changed, that is, value3 cannot refer to another Value object again, but the value of the referenced object can be changed.
On the other hand, we see the nuances of using final to decorate a member variable, because the value of the data that final decorates is immutable, so we must make sure that we have assigned a value to the member variable before using it. Therefore, for final-modified member variables, we have and only have two places to assign them, one when the member is declared, and the other in the constructor, where we must assign them initial values.
One last point to note is that members decorated with both static and final occupy only one piece of memory that cannot be changed.

2. final method parameters

As we saw earlier, if the variable is created by ourselves, then using final modification means that we will only assign it once and will not change the value of the variable. So if a variable is passed in as a parameter, how can we guarantee that its value will not change? This makes use of the second usage of final, which means that when we write a method, we can add the final keyword before the parameter, which means that we will not (in fact, cannot) change the value of the parameter throughout the method:


public class FinalTest {
  /* ... */
  public void finalFunc(final int i, final Value value) {
    // i = 5;  Can't be changed i Value of 
    // v = new Value();  Can't be changed v Value of 
    value.v = 5; //  You can change the value of the reference object 
  }
}

3. final method

final can also declare methods. Method is preceded by the final keyword, which means that this method cannot be overridden by subclass methods. You can declare a method as final if you think that the function of a method is complete enough that the subclass does not need to be changed. The final method is faster than the non-final method because it is statically bound at compile time and does not require dynamic binding at run time. One more link about the private and final keywords is that all private methods in the class are implicitly specified as final, and since the private method cannot be used outside the class, it cannot be overridden. The following is an example of the final method:


class PersonalLoan{
  public final String getName(){
    return "personal loan";
  }
}
class CheapPersonalLoan extends PersonalLoan{
  @Override
  public final String getName(){
    return "cheap personal loan"; //compilation error: overridden method is final
  }
}

4. Class final

Classes decorated with final are called final classes. final classes are usually functionally complete, and they cannot be inherited. There are many classes in Java that belong to final, such as String, Interger, and other wrapper classes. The following is an example of the final class:


 final class PersonalLoan{
  }
  class CheapPersonalLoan extends PersonalLoan{ //compilation error: cannot inherit from final class

5. Benefits of the final keyword

Here is a summary of one of the benefits of using the final keyword

The final keyword improves performance. Both JVM and Java applications cache final variables. final variables can be safely shared in a multithreaded environment without additional synchronization overhead. Using the final keyword, JVM optimizes methods, variables, and classes.

To create an immutable class, use the final keyword. An immutable class means that its object 1 cannot be changed once it is created. String is the representative of immutable class. Immutable classes have many advantages, such as their objects are read-only, can be shared securely in multithreaded environments, and do not require extra synchronization overhead.

6. A few confusing points

(1) What is the difference between final variable of class and ordinary variable?

When final is used on a member variable of a class, the member variable (note that it is a member variable of a class, and local variables only need to be initialized and assigned before use) must be initialized and assigned at the time of definition or in the constructor, and the final variable 1 cannot be assigned once it is initialized and assigned.
So what is the difference between final variable and ordinary variable? Let's look at an example below:


public class Test {
  public static void main(String[] args) {
    String a = "hello2"; 
    final String b = "hello";
    String d = "hello";
    String c = b + 2; 
    String e = d + 2;
    System.out.println((a == c));
    System.out.println((a == e));
  }
}

Output:

true
false

You can think about the output of this problem first. Why the first comparison result is true and the second comparison result is fasle. This is the difference between final variable and ordinary variable. When final variable is a basic data type and String type, if its exact value can be known during compilation, the compiler will use it as a compile-time constant. That is to say, where the final variable is used, it is equivalent to the constant accessed directly and does not need to be determined at runtime. This is a bit like macro substitution in C language. Therefore, in the above 1 code, since the variable b is modified by final, it will be treated as a compiler constant, so the variable b will be directly replaced with its value where b is used. However, access to the variable d needs to be made through links at runtime. Presumably, everyone should understand the difference, but it should be noted that the compiler will only make such optimization if the value of final variable can be known exactly during compilation. For example, the following code will not be optimized:


public class Test {
  public static void main(String[] args) {
    String a = "hello2"; 
    final String b = getHello();
    String c = b + 2; 
    System.out.println((a == c));
  }
  public static String getHello() {
    return "hello";
  }
}

The output of this code is false.

(2) Is the reference variable modified by final pointing to an object whose content is variable?

As mentioned above, the reference variable 1 modified by final can no longer point to other objects after initialization and assignment, so is the content of the object pointed to by the reference variable variable? Look at this example:


public class Test {
  public static void main(String[] args) {
    final MyClass myClass = new MyClass();
    System.out.println(++myClass.i);
  }
}
class MyClass {
  public int i = 0;
}

This code can be compiled smoothly and has an output result of 1. This shows that the reference variable, after being modified by final, can no longer point to other objects, but the contents of the object it points to are mutable.

(3) final and static

In many cases, it is easy to confuse static and final keywords. static acts on member variables to mean that only one copy is saved, while final is used to ensure that variables are immutable. Look at this example:


public class Test {
  public static void main(String[] args) {
    MyClass myClass1 = new MyClass();
    MyClass myClass2 = new MyClass();
    System.out.println(myClass1.i);
    System.out.println(myClass1.j);
    System.out.println(myClass2.i);
    System.out.println(myClass2.j);
  }
}
class MyClass {
  public final double i = Math.random();
  public static double j = Math.random();
}

When you run this code, you will find that the two j values printed each time are one, but the i values are different. From here, we can know the difference between final and static variables.

7. Summary

Important knowledge points about final are:

The final keyword can be used for member variables, local variables, methods, and classes.
final member variables must be initialized at declaration time or in the constructor, otherwise compile errors will be reported.
You cannot assign a value to the final variable again.
Local variables must be assigned at declaration time.
All variables in an anonymous class must be final variables.
The final method cannot be overridden.
The final class cannot be inherited.
The final keyword is different from the finally keyword, which is used for exception handling.
The final keyword is easily confused with the finalize () method, which is defined in the Object class and is called by JVM prior to garbage collection.
All variables declared in the interface are themselves final.
Since the keywords final and abstract are inversely related, the final class cannot be abstract.
The final method is bound at compile time and is called static binding (static binding).
Null final variables (ES210ES211variable) that do not initialize final variables at declaration time must be initialized in the constructor or by calling this (). Otherwise, the compiler will report an error "final variable (variable name) needs to be initialized".
Declaring classes, methods, and variables as final improves performance, giving JVM the opportunity to estimate and then optimize.
By Java code convention, an final variable is a constant, and usually the constant name is uppercase:


private final int COUNT = 10;

Declaring final for a collection object means that the reference cannot be changed, but you can add, delete, or change content to it. For example:


private final List Loans = new ArrayList();
list.add( " home loan " ); //valid
list.add("personal loan"); //valid
loans = new Vector(); //not valid

Related articles: