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

发布于 2024-07-07 20:03:17 字数 683 浏览 8 评论 0原文

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

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

The code at the end produces a compile error:

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

The question is why? Why does javac think I am calling run(), and does not find run(int bar)? It correctly called foo(int bar). Why do I have to use NotApplicable.this.run(42);? Is it a bug?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情归归情 2024-07-14 20:03:17

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

jvm 将进行如下评估:

this -> 当前使用方法 run() 执行 Runnable 实例

NotApplicable.this -> 当前使用方法 run(int) 执行 NotApplicable 的实例

编译器将在嵌套树中查找第一个与该方法的 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" );
    }
}

The explanation for the behavior of your code sample is that this is defined to be the class that you are currently "most" inside of. In this case, you are "most" inside the anonymous inner class that subclasses runnable and there is no method which matches run(int). To broaden your search you specify which this you want to use by stating NotApplicable.this.run(42).

The jvm will evaluate as follows:

this -> currently executing instance of Runnable with method run()

NotApplicable.this -> currently executing instance of NotApplicable with method run(int)

The compiler will look up the nesting tree for the first method that matches the NAME of the method. –Thanks to DJClayworth for this clarification

The anonymous inner class is not a subclass of the outer class. Because of this relationship, both the inner class and the outer class should be able to have a method with exactly the same signature and the innermost code block should be able to identify which method it wants to run.

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" );
    }
}
岛徒 2024-07-14 20:03:17

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

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

同样的原理也发生在这里。 查找“方法隐藏”的参考文献,它应该很清楚。

As far as I recall the rules for selecting a method to run between nested classes are approximately the same as the rules for selecting a method in an inheritance tree. That means that what we are getting here is not overloading, it's hiding. The difference between these is crucial to understanding methods in inheritance.

If your Runnable was declared as a subclass, then the run() method would hide the run(int) method in the parent. Any call to run(...) would try to execute the one on Runnable, but would fail if it couldn't match signatures. Since foo is not declared in the child then the one on the parent is called.

The same principle is happening here. Look up references to "method hiding" and it should be clear.

甜尕妞 2024-07-14 20:03:17

这是因为当您进入 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 类型匹配的内容,它只会在找到第一个引用并看到时停止类型不兼容。

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

This is because run is being re-declared when you enter the new Runnable() {} scope. All previous bindings to run become inaccessible. It's as if you were doing this:

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();
  }
}

The compiler won't look for something that matches the type of x all the way up the scope stack, it'll just halt when it finds the first references and sees that the types are incompatible.

NOTE: It's not as if it couldn't do this... it's just that, to preserve your own sanity, it's been decided that it shouldn't.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文