从anonymuos内部类访问外部类的最终局部变量

时间:2015-05-06 11:55:22

标签: java variables anonymous-class

Java anonymuos内部类允许无缝访问在外部对象的方法堆栈上声明的变量,只要它们声明final

但是,如果我在内部类中声明了具有相同名称的变量,该怎么办?有没有办法明确引用外部变量?

public class Outer {
    public static void main(String[] args) throws Throwable {
        new Outer().call();
    }

    private void call() throws Throwable {
        final String str = "I'm the outer String!";
        SwingUtilities.invokeAndWait(new Runnable() {

            @Override
            public void run() {
                String str = "I'm the inner String!";

                // This prints the inner String
                System.out.print(str);

                // So, can I have explicitly access to the outer String?
            }
        });
    }
}

BTW,这与this问题不同,因为它关注本地堆栈变量。

5 个答案:

答案 0 :(得分:2)

您可以在run函数中使用str外部变量,直到声明具有相同名称的新局部变量为止。 此时,您的新变量会影响另一个变量。

如果你想使用过去声明第二个str,则必须将它存储在其他对象中。

您的run方法在当前线程堆栈中获取私有堆栈帧。 新变量只是添加到该堆栈。执行run后,将删除堆栈帧。

您想要的是访问其范围之外的方法参数(在将新的str添加到堆栈之后)。

然而,外部str的堆栈帧只能访问java调试体系结构。 考虑这是一个安全问题。

答案 1 :(得分:1)

这很有趣。 Outer.this.str肯定不起作用,因为str是方法内的局部变量而不是类。

在我的测试中,我使用了Java 8 lambda表示法:

final String str = "I'm the outer String!";
SwingUtilities.invokeAndWait(() -> {
    String str = "I'm the inner String!"; // error: str is already defined in this scope

    // This prints the inner String
    System.out.print(str);

    // So, can I have explicitly access to the outer String?
    }
);

这里编译器实际输出一个错误,说明变量str已在此范围内定义。在你的例子中,虽然似乎没有办法访问外部变量。

你刚刚用匿名类中的变量隐藏了str(我认为这在Java中是不可能的......但我猜它只要它是真实的匿名课程。)

答案 2 :(得分:0)

如果通过这样做隐藏了内部类中的变量,则可以引用外部类中的变量:

System.out.println(Outer.this.str);

更新:我认为一旦隐藏了该方法中的变量,我就不会参考该变量。通过复制名称来避免影子变量的原因之一。另一个;它让人感到困惑。

答案 3 :(得分:0)

如果要访问类变量,可以调用

Outer.this.str

但它不是类变量,它是在call方法内声明的局部变量。 str方法内的run声明隐藏(遮蔽)外部str变量。

如果你想避免代码中难以捕获的错误,你应该避免使用变量这样的方法。

结论:您无法从run方法引用外部本地变量 str ,因为有一个变量相同的名称,在您的run方法内部声明,并且正在遮蔽外部本地 str 变量。

答案 4 :(得分:0)

如果您从Inner引用的字段是Outer.class中的字段,则它可以工作。如果它是localVariable,则将使用inner-Class的localVariable。

public class Outer {
    private String shadowed = "Outer";

    public static void main(String[] args) throws Throwable {
        new Outer().call();
    }

    private void call() throws Throwable {
        final String str = "I'm the outer String!";
        shadowed = "OuterString";

        SwingUtilities.invokeAndWait(new Runnable() {
            private String shadowed = "Outer";

            @Override
            public void run() {
                String inner = "I'm the inner String!";
                shadowed = "InnerString";

                // different reference identifier
                System.out.println(inner);
                System.out.println(str);

                // same reference identifier
                System.out.println(shadowed);
                System.out.println(Outer.this.shadowed);
            }
        });
    }
}