TWiStErRob
TWiStErRob

Reputation: 46480

Why is the super method not visible/resolved?

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 also gives a warning:

Method 'method()' recurses infinitely, and can only end by throwing an exception

Upvotes: 4

Views: 987

Answers (4)

user207421
user207421

Reputation: 311023

An overload in a child class hides the method being overloaded in the parent class. In this case, Problematic.method() overloads and hides Parent.method(int).

Upvotes: 1

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280138

From the Java Language Specification,

If the form is MethodName, that is, just an Identifier, then:

If the Identifier appears in the scope of a visible method declaration with that name (§6.3, §6.4.1), then:

  • If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.

  • This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy. See §6.5.7.1 for an example.

  • Otherwise, the visible method declaration may be in scope due to one or more single-static-import or static-import-on-demand declarations. There is no class or interface to search, as the method to be invoked is determined later (§15.12.2.1).

You're invoking the method inside the anonymous inner class which is a subtype of Problematic. This makes Child its enclosing type. In your case, T is the anonymous inner class, since that is the innermost type. Because of this, the class to search for the method is T, ie. the anonymous subclass of Problematic.

In later steps of the resolution of method invocation expressions, it is decided that the method Problematic#method() takes no arguments since it declares no parameters. It is therefore not applicable and a compiler error is raised.

Upvotes: 4

user177800
user177800

Reputation:

Explicit is always better than implicit!

method(0) is actually this.method(0) which is actually Child$1.this.method(0) and Child$1.this.method(int) does not exist in the declaration of Problematic.

This is explained in the error messages from the compiler and from the IDE.

The compiler tells you that this is exactly what it is doing, it is resolving to the most local scope and finding something and that something isn't correct and it stops looking.

You are doing this:

@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
}

Which actually implicitly means the following:

@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) is invalid code and if you called this.method() it would just recurse infinitely and throw a StackOverflow error.

This is explained in the error messages from the compiler and from the IDE.

This is how the scope resolution works, there is no mystery why, read the scope resolution rules and you will see it looks for this.XXX first then broadens the scope.

If your goal is to call method(int) on Child you already know how to do that, you have to call it with Child.this.method(int), it has to be fully qualified because of the namespace scoping resolution.

Upvotes: 0

loshad vtapkah
loshad vtapkah

Reputation: 459

See https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html:

Shadowing

If a declaration of a type (such as a member variable or a parameter name) in a particular scope (such as an inner class or a method definition) has the same name as another declaration in the enclosing scope, then the declaration shadows the declaration of the enclosing scope.

Upvotes: 2

Related Questions