Java 为什么可以';我在同名的匿名类之外调用一个方法

Java 为什么可以';我在同名的匿名类之外调用一个方法,java,methods,javac,anonymous-class,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(intbar)。为什么我必须使用notapplicative.this.run(42);?是虫子吗 public class NotAppli

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

NotApplicable.java:7: run() in  cannot be applied to (int)
                run(42);
                ^
1 error
问题是为什么?为什么javac认为我在调用run(),而没有找到run(int-bar)?它正确地称为foo(intbar)。为什么我必须使用notapplicative.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) {
    }
}

这是因为当您输入
new Runnable(){}
范围时,正在重新声明
run
。以前要运行的所有绑定都将无法访问。就好像你在这样做:

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
类型匹配的内容,它只会在找到第一个引用并发现类型不兼容时停止


注意:这并不是说它不能做到这一点。。。只是为了保持自己的理智,我们决定不这样做。

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

jvm将进行如下评估:

->使用方法
run()

不适用。此
->当前正在使用方法
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" );
    }
}

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

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


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

但是两个运行函数的签名不相同。这是超载。没有覆盖。显然,它正在覆盖它。如果不是,那么它将正确地重载它。这个答案是正确的,除了关于“即使两个方法都没有命名为‘run’,也会显示此行为”的部分。编译器将在嵌套树中查找与方法名称匹配的第一个方法。