17

除非标记了这些局部变量,否则在方法内部定义的内部类无法访问方法的局部变量。final我查看了堆栈溢出和 java 代码牧场中的其他帖子,但似乎没有一个完全回答关于如何标记的问题variables 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访问它们。在哪里data section of memory?我相信所有的局部变量最终或不是都存储在堆栈中。当方法从堆栈中删除时,最终变量将随之删除。最终变量中的值是否与堆中的对象一起存储?

它不支持非最终字段,因为它们可以通过方法或类进行更改,并且不支持这是因为实际上有两个不同的字段/变量。

4

6 回答 6

13

将局部变量标记为final告诉编译器它的值一旦被分配就保证不会改变。这使得编译器可以安全地在内部类中创建合成字段,并在构造内部类实例时将局部变量的值复制到该合成字段中。从内部类代码内部对局部变量的所有读取实际上都编译为对合成字段的读取。

这个技巧不适用于非最终变量,因为它们可能会在内部类被实例化后发生变化,并且合成字段将与原始变量不同步。

重要的是要认识到所有内部类都是编译器的技巧 - 对于运行时 JVM,所有类(顶级、嵌套静态和内部)都被同等对待。

于 2012-10-23T08:08:33.993 回答
12

在内部类的实例化过程中,当方法和类都在作用域内时,内部类会复制作为常量的变量,这意味着方法可以超出作用域,因为内部类只使用变量的副本。 看看这篇文章

于 2012-10-23T08:14:45.283 回答
2

是的,最终的局部变量保存在堆栈中,并在方法从堆栈中删除的那一刻被销毁。正如@Ian 所建议的那样,当编译器看到变量的 final 关键字时,它会在堆上的内部类对象中创建值的副本。

于 2012-10-23T08:20:07.950 回答
0

这背后的故事是java的创造者没有足够的时间来全力支持闭包

有几种方法可以使语言支持闭包。例如,在方案中,函数中的自由参数绑定到与定义函数的词法范围相对应的环境。在诸如 SML 等强制不可变数据的语言中,可以通过将闭包所需的局部变量复制到堆中来实现闭包。

所以他们创建了内部类来拥有一个模仿 ML 风格的穷人版本的闭包。

于 2014-03-25T15:29:52.660 回答
0

方法局部内部类不能使用外部方法的局部变量,直到该局部变量未声明为最终变量。我们需要将局部变量声明为 final 的主要原因是局部变量存在于堆栈上,直到方法在堆栈上,但可能存在内部类的对象仍然存在于堆上的情况。

查看这篇文章: http ://www.geeksforgeeks.org/inner-class-java/

于 2015-04-08T12:31:04.467 回答
0

所以现在想一想。方法的局部变量存在于堆栈中,并且只在方法的生命周期内存在。我们已经知道,局部变量的作用域仅限于声明变量的方法。当方法结束时,栈帧被吹走,变量就是历史。但是即使在方法完成之后,在其中创建的内部类对象也可能在堆上仍然存在,例如,如果对它的引用被传递到其他代码中,然后存储在实例变量中。因为局部变量不保证只要方法局部内部类对象存在就一直存在,内部类对象不能使用它们。除非局部变量被标记为final

最终局部变量是否存储在堆而不是堆栈上?

说明:现在在 SO 中进行一些研究后,我发现所有局部变量(最终或非最终变量)都存储在堆栈中,并且在方法执行结束时超出范围。

但是关于 final 变量JVM将这些作为常量,因为它们在启动后不会改变。并且当内部类尝试访问它们时,编译器会将该变量(不是它自身的变量)的副本创建到堆中 并在内部类中创建一个合成字段,因此即使方法执行结束它也可以访问,因为内部类有它自己的副本。合成领域文件实际上在源代码中不存在,但编译器在一些内部类中创建这些字段以使这些字段可访问。在简单的单词隐藏字段中。

所以最终变量也存储在堆栈中,但是内部类存储在堆中的那个变量的副本。

于 2016-02-29T19:31:40.110 回答