我有以下代码:
public class BookLib {
void f() {
final int x = 5; // Line 1
class MyCLass {
void print() {
System.out.println(x);
}
}
}
}
我不明白为什么在这种情况下应该使用最终变量(第1行)?
答案 0 :(得分:20)
你在这里创建了一个内部类。由于此类对象的生命周期可能远远大于方法调用的运行时(即对象在返回方法后很久仍然存在),它需要“保留”局部变量的状态可以访问。
这种保留是通过在内部类中创建(不可见的,合成的)副本并使用对该副本的引用自动替换对局部变量的所有引用来完成的。在创建内部类对象后修改局部变量时,此可能会导致奇怪的效果。
为了避免这种情况,需要以这种方式访问的所有局部变量都是final
:这样可以确保局部变量只有一个可能的值,并且没有观察到任何不一致。
此特定规则可在§8.1.3 Inner Classes and Enclosing Instances的the JLS中找到:
使用但未在内部类中声明的任何局部变量,形式方法参数或异常处理程序参数必须声明为final。任何在内部类中使用但未声明的局部变量必须在内部类的主体之前明确赋值(§16)。
答案 1 :(得分:3)
在这里创建一个内部类。为了访问执行的上下文,对变量的引用应该保持不变,否则会出现错误行为。为了保证这一点,你应该声明你的变量final:因此无法改变它。
查看详细解释here。
答案 2 :(得分:1)
来自kathy sierra scjp Book
方法的局部变量存在于堆栈中,并且仅在方法的生命周期中存在。我们已经知道局部变量的范围仅限于声明变量的方法。当方法结束时,堆栈帧被吹走,变量是历史。但即使在方法完成之后,在其中创建的内部类对象仍可能在堆上存活,例如,如果对它的引用被传递到其他代码中,然后存储在实例变量中。因为只要方法本地内部类对象,局部变量不能保证存活,内部类对象不能使用它们。除非局部变量标记为final!
答案 3 :(得分:0)
所以你有一个局部最终变量和方法本地内部类。方法本地内部类不能使用在方法中声明的非最终变量(包括参数)。
进一步深入研究: 方法本地内部类只能在定义类的方法中实例化。局部变量在方法的生命周期中存在于堆栈中。随着方法结束,局部变量消失,但创建的内部类对象仍然存在。
这是终身/范围的问题。