2

最后的代码产生编译错误:

NotApplicable.java:7: run() in  cannot be applied to (int)
                run(42);
                ^
1 error

问题是为什么?为什么javac认为我在调用run(),却没有找到run(int bar)?它正确地调用了 foo(int bar)。为什么我必须使用 NotApplicable.this.run(42);?它是一个错误吗?

public class NotApplicable {

    public NotApplicable() {
        new Runnable() {
            public void run() {
                foo(42);
                run(42);
                // uncomment below to fix
                //NotApplicable.this.run(42);
            }
        };
    }

    private void run(int bar) {
    }

    public void foo(int bar) {
    }
}
4

3 回答 3

16

对代码示例行为的解释是,它this被定义为您当前“最”在其中的类。在这种情况下,您在子类 runnable 的匿名内部类中“最多”,并且没有匹配的方法run(int)。为了扩大您的搜索范围,您可以通过声明来指定this要使用的内容NotApplicable.this.run(42)

jvm 将评估如下:

this-> 当前正在执行的Runnablewith 方法实例run()

NotApplicable.this-> 当前正在执行的NotApplicablewith 方法实例run(int)

编译器将在嵌套树中查找与方法名称匹配的第一个方法。–感谢 DJClayworth 的澄清

匿名内部类不是外部类的子类。由于这种关系,内部类和外部类都应该能够拥有具有完全相同签名的方法,并且最内部的代码块应该能够识别它想要运行的方法。

public class Outer{

    public Outer() {
        new Runnable() {
            public void printit() {
                System.out.println( "Anonymous Inner" );
            }
            public void run() {
                printit(); // prints "Anonymous Inner"
                this.printit(); //prints "Anonymous Inner"

                // would not be possible to execute next line without this behavior
                Outer.this.printit(); //prints "Outer" 
            }
        };
    }

    public void printit() {
        System.out.println( "Outer" );
    }
}
于 2008-10-31T01:54:31.793 回答
1

据我回忆,选择在嵌套类之间运行的方法的规则与选择继承树中的方法的规则大致相同。这意味着我们在这里得到的不是超载,而是隐藏。这些之间的区别对于理解继承中的方法至关重要。

如果您的 Runnable 被声明为子类,则 run() 方法会将 run(int) 方法隐藏在父类中。对 run(...) 的任何调用都会尝试在 Runnable 上执行该调用,但如果它无法匹配签名,则会失败。由于 foo 未在子级中声明,因此调用父级中的 foo。

同样的原理也发生在这里。查找对“方法隐藏”的引用,它应该很清楚。

于 2008-10-31T15:27:22.770 回答
0

这是因为在您进入范围run时正在重新声明。new Runnable() {}所有以前运行的绑定都变得不可访问。就好像你正在这样做:

import java.util.*;

public class tmp
{
  private int x = 20;
  public static class Inner
  {
      private List x = new ArrayList();
      public void func()
      {
          System.out.println(x + 10);
      }
  }

  public static void main(String[] args)
  {
    (new Inner()).func();
  }
}

编译器不会一直寻找与x作用域堆栈的类型匹配的东西,它只会在找到第一个引用并看到类型不兼容时停止。

注意:并不是说它不能这样做……只是为了保持你自己的理智,决定不应该这样做。

于 2008-10-31T00:51:04.743 回答