Recently, while looking at inner classes, I had a question: local inner classes and anonymous inner classes can only access final local variables. After reading several blog posts, I understood a lot.
First, let's look at an example of a local inner class:
Example
private int age = 12;
public void outPrint(final int x) {
class InClass {
public void InPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
Here there is an outer class OuterClass and an inner class InClass. The inner class accesses a local variable x in a method of the outer class. Here, x must be final, otherwise an error will be reported:
Cannot refer to a non-final variable x inside an inner class defined in a different method
Let's analyze this problem below:
The root cause is the lifecycle of variables in the scope;
The first thing to know is: the inner class and the outer class are at the same level, and the inner class will not be destroyed just because it is defined in a method when the method finishes executing.
This creates a problem: when the outer class's method ends, the local variable will be destroyed, but the inner class object may still exist (it will only die when no one references it anymore). Here a contradiction arises: the inner class object accesses a variable that does not exist. To solve this problem, a copy of the local variable is made as a member variable of the inner class, so that when the local variable dies, the inner class can still access it — what it actually accesses is a "copy" of the local variable. This seems to extend the lifecycle of the local variable. We can test this by decompiling the generated .class file:
In the command line window, first execute the commandjavac OutClass.javaTo compile, two files will be obtained: OutClass$1InClass.class, OutClass.class:

javap is a Java class file disassembler that can decompile and also view the bytecode generated by the Java compiler.
Here we can execute the command againjavap -privateOutClass$1InClassTo decompile,-privateIt means display all classes and members. After execution, the following result will be obtained:

It can be seen that the local variable in the method is indeed actually copied and used as a member variable of the inner class.
The problem arises again: when copying the local variable as a member variable of the inner class, the two variables must be guaranteed to be the same. That is, if we modify the member variable in the inner class, the local variable in the method must also change accordingly. How to solve this problem?
Set the local variable to final. After initializing it, you are not allowed to modify this variable anymore, which ensures the consistency between the inner class's member variable and the method's local variable. This is actually a compromise.
If the variable is final:
-
If it is a primitive type, its value cannot be changed, which ensures that the copy is the same as the original local variable's value;
-
If it is a reference type, its reference cannot be changed, which ensures that the copy and the original variable reference the same object.
This keeps the local variable consistent with the copy established within the inner class.
Original link: https://blog.csdn.net/sf_climber/article/details/78326984