Java中的内部块如何访问应该超出范围的局部变量? (JVM如何处理Java中的最终局部变量)

前端之家收集整理的这篇文章主要介绍了Java中的内部块如何访问应该超出范围的局部变量? (JVM如何处理Java中的最终局部变量)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在以下代码中:

public class Main
{
    Emp globalEmp;

    public void aMethod()
    {
        final int stackVar = 10;

        globalEmp = new Emp()
        {
            public void doSomeThing()
            {
                System.out.println("stackVar :" + stackVar);
            }
        };
    }

    public static void main(String[] args)
    {
        Main m = new Main();
        m.aMethod();
        m.globalEmp.doSomeThing();
    }
}

interface Emp{
    public void doSomeThing();
}

据我所知,将执行以下操作:

> Main m = new Main(); :将创建一个新的Main类实例,并将globalEmp设置为null.
> m.aMethod(); :调用aMethod,包括将其实例变量stackVar复制到堆栈中,然后创建Emp类的新实例并将其分配给globalEmp实例.
>当方法aMethod到达结束时,局部变量stackVar将从堆栈中推出.
> m.globalEmp.doSomeThing(); :将在globalEmp变量指向的先前创建的对象上调用函数doSomeThing.并且因为这个函数doSomeThing正在访问一个本地变量stackVar,它假定不会从缓存中弹出,它应该抛出一些错误说明.

那么,Java运行时如何真正起作用呢?

编辑:

>由于运行时将创建最终局部变量的浅表副本(下面的每个答案),为什么它也不允许访问非最终变量?
>你能否提供一些链接(在规格或官方地方)?

解决方法

通常,匿名内部类将为其生成一个构造函数,以获取在匿名内部类的类中引用的局部变量的值.生成代码转为:

globalEmp = new Emp() { ... };

成:

globalEmp = new Main$1(stackVar);

然后,该构造函数将值复制到生成的匿名类中的隐藏字段中.

换句话说,它会创建值的副本.之后,原始值来自的变量无关紧要.

在您实际显示的情况下,它不需要因为10是常量 – 但这是捕获变量的一般方式.

编辑:回应你的编辑…

变量必须是最终的,这样就不会出现混淆 – 如果你可以改变它们,一些开发人员可能希望在匿名类中可以看到任何变化,就像在其他闭包实现中一样.

至于围绕这个的官方文档,我在Java语言规范中看到的最接近的是section 8.1.3,尽管它没有讨论各种决策背后的动机.

猜你在找的JVM相关文章