为什么超级方法不可见/已解决?

时间:2014-12-06 22:18:45

标签: java visibility javac overloading

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;无限地递归,并且只能通过抛出异常来结束

4 个答案:

答案 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的匿名子类。

laterthe 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)调用它,因为名称空间必须完全限定范围决议。