为什么我不能调用同名匿名类之外的方法
最后的代码会产生编译错误:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对代码示例行为的解释是
this
被定义为您当前“最”位于其中的类。 在这种情况下,您位于可运行子类的匿名内部类中的“最”部分,并且没有与run(int)
匹配的方法。 要扩大搜索范围,您可以通过声明NotApplicable.this.run(42)
来指定要使用的this
。jvm 将进行如下评估:
this
-> 当前使用方法run()
执行Runnable
实例NotApplicable.this
-> 当前使用方法run(int)
执行NotApplicable
的实例编译器将在嵌套树中查找第一个与该方法的 NAME 匹配的方法。 -感谢 DJClayworth 的澄清
匿名内部类不是外部类的子类。 由于这种关系,内部类和外部类都应该能够拥有具有完全相同签名的方法,并且最里面的代码块应该能够识别它想要运行哪个方法。
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 matchesrun(int)
. To broaden your search you specify whichthis
you want to use by statingNotApplicable.this.run(42)
.The jvm will evaluate as follows:
this
-> currently executing instance ofRunnable
with methodrun()
NotApplicable.this
-> currently executing instance ofNotApplicable
with methodrun(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.
据我记得,选择在嵌套类之间运行的方法的规则与选择继承树中的方法的规则大致相同。 这意味着我们在这里得到的不是超载,而是隐藏。 它们之间的区别对于理解继承中的方法至关重要。
如果您的 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.
这是因为当您进入
new Runnable() {}
作用域时,run
被重新声明。 所有之前要运行的绑定都变得无法访问。 就好像您正在这样做:编译器不会在作用域堆栈中一直寻找与
x
类型匹配的内容,它只会在找到第一个引用并看到时停止类型不兼容。注意:这并不是说它不能这样做......只是为了保持你自己的理智,我们决定不应该这样做。
This is because
run
is being re-declared when you enter thenew Runnable() {}
scope. All previous bindings to run become inaccessible. It's as if you were doing this: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.