微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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,尽管它没有讨论各种决策背后的动机.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐