为什么我不能在同名的匿名类之外调用方法

时间:2008-10-31 00:45:22

标签: java methods javac anonymous-class

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

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) {
    }
}

3 个答案:

答案 0 :(得分:16)

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

jvm将评估如下:

this - >当前正在使用方法Runnable

执行run()的实例

NotApplicable.this - >当前正在使用方法NotApplicable

执行run(int)的实例

编译器将查找嵌套树以查找与方法的NAME匹配的第一个方法。 - 感谢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" );
    }
}

答案 1 :(得分:1)

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

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

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

答案 2 :(得分: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类型相匹配的内容,它只会在找到第一个引用时停止并看到类型不兼容。

注意:这不像无法这样做......只是为了保持自己的理智,已经决定不应该这样做