Java 将变量标记为final如何允许内部类访问它们?
在方法中定义的内部类无法访问方法的局部变量,除非这些局部变量被标记为Java 将变量标记为final如何允许内部类访问它们?,java,Java,在方法中定义的内部类无法访问方法的局部变量,除非这些局部变量被标记为final。我看过stack overflow和java code ranch中的其他文章,但它们似乎都没有准确回答标记变量final如何允许内部类访问的问题方法中的局部变量 class MyOuter { private String x = "Outer"; void fly(final int speed) { final int e = 1; class FlyingEq
final
。我看过stack overflow和java code ranch中的其他文章,但它们似乎都没有准确回答标记变量final如何允许内部类访问的问题方法中的局部变量
class MyOuter {
private String x = "Outer";
void fly(final int speed) {
final int e = 1;
class FlyingEquation {
public void seeOuter()
{
System.out.println("Outer x is " + x);
}
public void display()
{
System.out.println(e);// line 1
System.out.println(speed);// line 2
}
}
FlyingEquation f=new FlyingEquation();
f.seeOuter();
f.display();
}
public static void main(String args[])
{
MyOuter mo=new MyOuter();
mo.fly(5);
}
}
我对这一点的解释如下:
局部变量存储在堆栈上,一旦方法调用完成,堆栈就会弹出,局部变量不可访问,而最终局部变量存储在内存的数据部分可能允许JVM
甚至在调用结束后访问它们方法调用。内存的数据部分在哪里?我相信所有的局部变量final或not都存储在堆栈上。当方法从堆栈中移除时,最终变量将随之移除。最后一个变量中的值是否与堆中的对象一起存储
它不支持非最终字段,因为它们可以通过方法或类进行更改,这是不受支持的,因为实际上有两个不同的字段/变量。将局部变量标记为final
会告诉编译器,它的值保证在赋值后不会更改。这使得编译器可以安全地在内部类内创建一个合成字段,并在构造内部类实例时将局部变量的值复制到此合成字段中。所有从内部类代码中读取的局部变量实际上都编译为对合成字段的读取
这个技巧对非最终变量不起作用,因为它们在内部类实例化后可能会改变,合成字段将与原始变量不同步
重要的是要认识到,所有内部类都是编译器的把戏——对于运行时JVM来说,所有类(顶级、嵌套静态和内部)都是一样的。在内部类的实例化过程中,当方法和类都在范围内时,内部类将复制常量变量,这意味着该方法可能超出范围,因为内部类仅使用变量的副本。
.是的,最终的局部变量保存在堆栈上,并在方法从堆栈中删除时销毁。正如@Ian所建议的,当编译器看到变量的最后一个关键字时,它会在堆上的内部类对象中创建一个值的副本。这背后的故事是java的创建者没有足够的时间完全支持
有几种方法可以关闭语言支持。例如,在scheme中,函数中的自由参数被绑定到与定义函数的词法范围相对应的环境。在强制使用SML等不可变数据的语言中,可以通过将闭包所需的局部变量复制到堆来实现闭包
因此,他们创建了内部类来拥有穷人版本的闭包,它模仿了ML的风格。方法局部内部类不能使用外部方法的局部变量,除非该局部变量未声明为最终变量。
我们需要将局部变量声明为final的主要原因是,局部变量一直存在于堆栈上,直到方法在堆栈上,但可能存在这样的情况:内部类的对象仍然存在于堆上
签出本文:现在考虑一下。该方法的局部变量位于堆栈上,并且只在该方法的生命周期内存在。我们已经知道,局部变量的作用域仅限于声明该变量的方法。当方法结束时,堆栈帧被吹走,变量为历史。但是,即使在该方法完成之后,在该方法中创建的内部类对象在堆上可能仍然是活动的,例如,如果将对它的引用传递到其他代码中,然后存储在实例变量中。因为只要方法本地内部类对象是,就不能保证局部变量是活动的,所以内部类对象不能使用它们。除非局部变量标记为final
最终的局部变量是否存储在堆而不是堆栈上
?
解释:现在,在进行了一些研究之后,我发现所有局部变量(final或not)都存储在堆栈中,然后退出
方法执行结束时的范围。
但关于final
变量JVM
将它们作为常量,因为它们在
启动。当内部类试图访问它们时,编译器将创建
将该变量(不是该变量本身)复制到堆中
并在内部类中创建一个合成字段
方法执行结束,因为内部类
有自己的副本合成字段是实际上不存在的字段
存在于源代码中,但编译器在某些情况下创建这些字段
内部类以使这些字段可访问。用简单的词隐藏
字段。
所以最后一个变量也存储在堆栈中,但它是内部类存储在堆中的变量的副本。
这可能会有帮助