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问题不同,因为它关注本地堆栈变量。
答案 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);
}
});
}
}