Java 从匿名类的角度看被局部变量遮挡的字段

Java 从匿名类的角度看被局部变量遮挡的字段,java,shadowing,Java,Shadowing,我正在尝试运行以下代码: class A { int x = 123; public void f(int x) { new Runnable() { public void run() { System.out.println(x); } }.run(); } static { A a = new A(); a.f(33); } } 但这给了我一个错误: $ javac A.java &&am

我正在尝试运行以下代码:

class A {
  int x = 123;
  public void f(int x) {
    new Runnable() {
      public void run() {
        System.out.println(x);
      }
    }.run();
  }
  static {
    A a = new A();
    a.f(33);
  }
}
但这给了我一个错误:

$ javac A.java && java A
A.java:6: local variable x is accessed from within inner class; needs to be declared final
        System.out.println(x);
                           ^
1 error
x
参数不是
final
,因此它不应从匿名类访问,但代码无法编译。看起来,
println
行试图使用
x
参数而不是
x
字段。为什么?如何告诉它我想要
x
字段?

您可以使用

A.this.x
因为匿名
Runnable
类是
A
类的内部类

阴影的概念决定了中的
x

System.out.println(x);
是指本地方法参数变量
x
,但这不是
final
,因此您不能在匿名类中访问它,至少在Java 7及以下版本中不能。您可以使用Java8,这可能会让人困惑


不要在同一个编译单元中为变量使用相同的名称。

是的,就是这样。比我快。1+@JasonC我肯定某处有一个。问问题的人通常不知道涉及的概念的名称,所以很难找到。@SotiriosDelimanolis是的,我在你回答时找到了一个,在“java内部阴影”搜索结果列表的下面一点。不太明显,除非你的搜索力很强。什么是编译单元?有关于Java 8更改的链接吗?@Dog编译单元是一个被编译的文件。所以只有一个
.java
文件。至于Java 8,请参阅关于访问封闭类的成员的教程。我现在没有到JLS的链接。请不要自找麻烦:|。如果你真的愿意,我会找到的。@Makoto这不是那个问题的重复。这个问题涉及到访问非最终变量,而不是跟踪。