Analysis of final keyword in Java

1. Basic usage of the final keyword

  In Java, the final keyword can be used to decorate classes, methods, and variables (including member variables and local variables). Let's take a look at the basic usage of the final keyword from these three aspects.

  1. Modified class

  When a class is modified with final, it indicates that this class cannot be inherited. In other words, if you never let a class be inherited, you can modify it with final. Member variables in the final class can be set to final as needed, but it should be noted that all member methods in the final class will be implicitly designated as final methods.

 

 

  When using final to modify a class, you should choose carefully, unless this class will not be used for inheritance in the future or for safety reasons, try not to design the class as a final class.

  2. Modification method

  The following passage is taken from page 143 of the fourth edition of "Java Programming Thoughts":

  "There are two reasons for using the final method. The first reason is to lock the method in case any inherited class changes its meaning; the second reason is efficiency. In earlier versions of Java implementation, the final method was converted to Inline calls. However, if the method is too large, you may not see any performance improvements brought by inline calls. In recent versions of Java, there is no need to use the final method for these optimizations. "(Common rumors);

A common misconception is that declaring a method as final improves efficiency by allowing the compiler to directly insert the method wherever it is called (see inline expansion). Because the method is loaded at runtime, compilers are unable to do this. Only the runtime environment and JIT compiler know exactly which classes have been loaded, and so only they are able to make decisions about when to inline, whether or not the method is final.

  Therefore, only set the method to final if you want to explicitly prohibit the method from being overridden in the subclass.

  Note: The private method of the class is implicitly designated as the final method.

  3. Modified variables

  Decorating variables is the place where final is used the most, and it is also the focus of this article. First understand the basic syntax of final variables:

  For a final variable, if it is a variable of basic data type, its value cannot be changed once it is initialized; if it is a variable of reference type, it cannot be pointed to another object after its initialization.

  for example:

  

 

  In the above code, the re-assignment of variables i and obj is wrong.

2. In-depth understanding of the final keyword

  After understanding the basic usage of the final keyword, in this section we take a look at where the final keyword is easily confused.

1. What is the difference between final and ordinary variables of a class?

  When using final to act on a member variable of a class, the member variable (note that it is a member variable of the class, local variables only need to be guaranteed to be initialized and assigned before use) must be initialized and assigned in the definition or constructor, and the final variable Once it is initialized and assigned, it can no longer be assigned.

  So what is the difference between final and ordinary variables? Here is an example:

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));
    }
}
true
false
View Code

  You can think about the output of this question first. Why is the first comparison result true, and the second comparison result is fasle. This is the difference between final variables and ordinary variables. When final variables are basic data types and String types, if the exact value of it is known during compilation, the compiler will use it as a constant during compilation. 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 similar to macro replacement in C. Therefore, in the above code, because the variable b is final modified, it will be used as a compiler constant, so where the b is used, the variable b will be directly replaced with its value. However, the access to the variable d needs to be performed through the link at runtime. Presumably, the difference should be understood by everyone, but it should be noted that the compiler will perform such optimization only when the final variable value 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 content of the object pointed to by the reference variable modified by final variable?

  As mentioned above, once the reference variable modified by final can not point to other objects once it is initialized and assigned, does the content of the object pointed to by the reference variable change? 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 successfully compiled and has an output result, the output result is 1. This shows that after the reference variable is final modified, although it can no longer point to other objects, the content of the object it points to is variable.

3.final and static

  In many cases, it is easy to confuse the static and final keywords. Static acts on member variables to indicate that only one copy is saved, and the role of final is 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 the same, but the value of i is different. From here you can know the difference between final and static variables.

4. Why are external local variables used in anonymous inner classes only final variables?

  Please refer to the explanation in "Detailed Explanation of Java Internal Classes" in the previous blog post on this issue, and I won't repeat them here.

5. Questions about final parameters

  Regarding what is circulated on the Internet, when you do not need to change the object variable as a parameter in the method, explicitly use final to declare, which will prevent you from unintentionally modifying and affecting the variables outside the calling method. I personally understand this statement. Is inappropriate.

  Because no matter whether the parameter is a variable of a basic data type or a variable of a reference type, the final statement will not achieve the effect described above.

  Look at this example to make it clear:

 

 

  The above code seems to make people feel that after the final modification, the value of the variable i cannot be changed in the method. As everyone knows, the variable i in the method changeValue and the main method is not a variable at all, because java parameter transmission uses value transmission. For basic type variables, it is equivalent to directly copying the variables. So even if there is no final modification, changing the value of the variable i inside the method will not affect the i outside the method.

  Look at the following code:

public class Test {
    public static void main(String[] args)  {
        MyClass myClass = new MyClass();
        StringBuffer buffer = new StringBuffer("hello");
        myClass.changeValue(buffer);
        System.out.println(buffer.toString());
    }
}
 
class MyClass {
     
    void changeValue(final StringBuffer buffer) {
        buffer.append("world");
    }
}

  Run this code and you will find the output is helloworld. Obviously, decorating with final does not prevent changing the contents of the object pointed to by buffer in changeValue. Some people say that if the final is removed, what if the buffer points to other objects in changeValue. Friends who have this kind of thinking can write the code by themselves and try what the result is. If the final is removed, and then the buffer points to other objects in changeValue, it will not affect the buffer in the main method. The reason is that java Value passing is used. For reference variables, the reference value is passed, which means that letting the actual parameter and the formal parameter point to the same object at the same time, so let the formal parameter point to another object has no effect on the actual parameter.

  Therefore, I personally do not agree with the statement about the final parameters circulating on the Internet.

Guess you like

Origin www.cnblogs.com/Chary/p/12683107.html