interface Problematic {
void method();
}
class Parent {
void method(int arg) { }
}
class Child extends Parent {
void test() {
new Problematic() {
@Override public void method() {
// javac error: method method in class <anonymous Problematic> cannot be applied to given types;
// required: no arguments, found: int
method(0);
Child.this.method(0); // works just fine
Child.super.method(0); // works just fine
}
};
}
}
IntelliJ IDEA也会发出警告:
方法&#39;方法()&#39;无限地递归,并且只能通过抛出异常来结束
答案 0 :(得分:4)
From the Java Language Specification,
如果表单是
MethodName
,即只是一个标识符,那么:如果标识符出现在可见方法声明的范围内 使用该名称(§6.3,§6.4.1),然后:
如果存在该方法为成员的封闭类型声明,则让
T
成为最里面的类型声明。班级或 搜索界面为T
。此搜索政策称为“梳理规则”。它在查找之前有效地在嵌套类的超类层次结构中查找方法 用于封闭类及其超类层次结构中的方法。看到 §6.5.7.1为例。
否则,由于一个或多个单静态导入或静态导入按需声明,可见方法声明可能在范围内。 没有要搜索的类或接口,作为要调用的方法 稍后确定(§15.12.2.1)。
您正在调用匿名内部类中的方法,该类是Problematic
的子类型。这使Child
成为封闭类型。在您的情况下,T
是匿名内部类,因为这是最内层类型。因此,搜索方法的类是T
,即。 Problematic
的匿名子类。
在later的the resolution of method invocation expressions步骤中,决定方法Problematic#method()
不带参数,因为它声明没有参数。因此它不适用,并且引发了编译器错误。
答案 1 :(得分:2)
请参阅https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html:
阴影
如果特定范围(例如内部类或方法定义)中的类型声明(例如成员变量或参数名称)与封闭范围中的另一个声明具有相同的名称,则声明隐藏封闭范围的声明。
答案 2 :(得分:1)
子类中的重载会隐藏父类中重载的方法。在这种情况下,Problematic.method()
会重载并隐藏Parent.method(int).
答案 3 :(得分:0)
method(0)
实际上是this.method(0)
,实际上Child$1.this.method(0)
并且Child$1.this.method(int)
的声明中不存在Problematic
。
这在编译器和IDE的错误消息中有解释。
编译器告诉你这正是它正在做的事情,它正在解析到最本地的范围并找到一些东西并且某些东西不正确而且它停止了。
@Override public void method() {
// javac error: method method in class <anonymous Problematic> cannot be applied to given types;
// required: no arguments, found: int
method(0);
Child.this.method(0); // works just fine
Child.super.method(0); // works just fine
}
@Override public void method() {
// javac error: method method in class <anonymous Problematic> cannot be applied to given types;
// required: no arguments, found: int
this.method(0); // this is implied in the above code
// and resolves to the Problematic declaration
Child.this.method(0); // will never be reached if the previous call is actually corrected.
Child.super.method(0); // will never be reached either
}
this.method(0)
是无效代码,如果您调用this.method()
,它只会无限递归并抛出StackOverflow
错误。
这在编译器和IDE的错误消息中有解释。
这是范围解析的工作原理,没有神秘的为什么,阅读范围解析规则,你会看到它首先查找this.XXX
,然后扩大范围。
如果您的目标是在method(int)
上致电Child
,您已经知道如何执行此操作,则必须使用Child.this.method(int)
调用它,因为名称空间必须完全限定范围决议。