The reason why local variables accessed by Java local classes are decorated with final

1. Internal class

1️⃣ An inner class that is a member of its outer class is called a member inner class. Unless otherwise stated, "inner class" generally means a member inner class.
2️⃣ Local classes and anonymous classes are two special types of inner classes:

  1. The inner class declared in the method body is called a local inner class, also known as a local class. Local classes have class names.
  2. The unnamed inner class declared in the method body is called anonymous inner class, also known as anonymous class. An anonymous class has no class name.

2. Local variables

Local variables, also called internal variables, refer to variables defined inside a function or inside a compound statement. The scope of a local variable is the function in which it is defined or the compound statement in which it is defined. The lifetime of a local variable is calculated from the moment the function is called to the moment the function returns to the caller.

Therefore, the inner class can access a local variable, indicating that the inner class is not the inner class defined in the class, but the inner class defined in the method, which is called: local inner class 没有类名的局部内部类叫匿名内部类.

Scope of local variables: Local variables are defined in a method, and when the method is executed, the local variables disappear. [Local variables are allocated in the virtual machine stack of the JVM , and this part of memory space is automatically recovered as the program executes], that is: the scope of local variables is "in the scope of the method". However, when a (local) inner class accesses a local variable, the scope of the local variable is enlarged.

3. Examples

public class finalLocalVariable {
    
    
    public static void main(String[] args) {
    
    
        final String str = "HelloWorld!";//局部变量
        //局部内部类
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                for (int i = 0; i < 1000; i++)
                    System.out.println(str);
            }
        }).start();
        System.out.println("main thread finished");
    }
}

Line 3 defines a local variable str in main(), line 5 defines a local internal class Thread, and access str in the local internal class Thread. It stands to reason: when the program executes to line 17, main() ends, that is: the main thread ends. The lifetime of the local variable str should also end. However, the Thread thread is not over yet, and the value of the local str can also be printed in the Thread thread. This shows that: the scope of the local variable str has been expanded.

Therefore, if the local variable is not modified by final , the value of the local variable can be modified at will in the (local) inner class. At the same time, these modified values ​​​​can be seen outside the scope of the local variable, so inexplicable problems will occur. Therefore, Java stipulates that local variables accessed by (local) inner classes must be modified with final to prevent changing the value of local variables.

analyze:

  1. The life cycle is different: local variables are directly stored in the stack. When the method execution ends, the non-final local variables are destroyed, while the local inner class still has a reference to the local variable. When the local inner class wants to call the local variable, it will An error occurred with an illegal reference. To put it simply, the life cycle of non-final local variables is shorter than that of local inner classes. Is it possible to directly copy variables to local inner classes? In this way, it can be used in inner classes without worrying about life cycle issues? It is also not possible, because direct copying will cause the second problem, that is, the data is not synchronized.

  2. Data out of sync: The internal class does not directly use the passed parameters, but backs up the passed parameters to itself through its own constructor. On the surface, it looks like the same variable, and actually calls its own properties instead of external classes. The parameters of the method, if these parameters are modified in the internal class, will not affect the external variables, only the parameters backed up in the local internal class will be changed. However, it is found that the value has not been modified when it is called externally, which will cause the data to be out of sync. So use final to avoid the problem of data out of sync.

Why can a local variable with final modification be referenced by a local inner class?
If it is defined as final, the Java compiler will generate a copy of the external variable in the internal class, which not only ensures that the internal class references the external attribute, but also ensures the uniqueness of the value. That is, a copy of a variable is copied and provided to the local inner class. The life cycle of the copy is as long as that of the local inner class, and it cannot be modified to ensure data synchronization.

4. Reasons

  1. Because when the inner class is compiled, a separate .class file of the inner class will be generated, which is not in the same class file as the outer class. If the internal class changes the values ​​of these parameters, it is impossible to affect the original parameters, but this will lose the consistency of the parameters. Because they are the same thing from the developer's point of view, if the developer changes the value of the parameter in the internal class during programming, but finds that the value has not been changed when the external call is made, this makes people It is very difficult to understand and accept. In order to avoid this kind of problem, the compiler sets the parameters that can be used by the inner class as final to avoid the existence of such inexplicable errors.

  2. When the method is called and runs, the local variable has died. But the inner class object may still exist and will not die until it is not referenced. At this point, there will be a situation where the inner class wants to access a local variable that does not exist.

  3. The solution to this problem is to use final to modify the local variable. By "copying" the final local variable, the copy is directly used as a data member in the inner class of the method. At this time, what the inner class of the method accesses is actually a copy of the local variable. Taste! Moreover, since the variable modified by final cannot be modified after assignment, the consistency between the copy and the original variable is guaranteed.

  4. The reason why the function of the second reason can be realized is that Java adopts a copy local variable (copy local variable) method to realize it, that is to say, the local variable defined as final is copied and used, and the referenced one can also be used. , just cannot be reassigned. As a result, it creates the illusion of accessing local variables (accessing local variables), and at this time, because it cannot be reassigned, it generally does not cause unpredictable things to happen.

  5. Using the final modifier will not only keep the reference of the object unchanged, but the compiler will also continue to maintain the life cycle of the object in the callback method. This is the fundamental meaning of final variables and final parameters.

Guess you like

Origin blog.csdn.net/ChineseSoftware/article/details/125041404
Recommended