Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using The Default Method Of Grandparent Interface

I'm totally lost on why that won't work:

interface Test {

    default void doMagic() {
        System.out.println("Abracadabra");
    }
}

class TestImpl implements Test {

}

class SpecialTestImpl extends TestImpl {

    public void doMagic() {
        Test.super.doMagic(); // Error: No enclosing instance of the type Test is accessible in scope
    }
}

Is this some weird Eclipse error message (it's not able to cope with Lamdas either, so maybe Mars isn't entirely Java 8 ready, yet)?

I can fix it by letting SpecialTestImpl implement Test directly (which yields a warning, because it's unnecessary) or overriding the method in TestImpl (which yields a warning for the same reasons).

So why wouldn't I be able to call the super method?

My guess was because if I was able to call Test.super.doMagic() directly, implementing the method in TestImpl would break the API for SpecialTestImpl even though it shouldn't. But that is also true if I let SpecialTestImpl implement Test and call the default method that way.

like image 685
Steffi S. Avatar asked Sep 16 '15 10:09

Steffi S.


2 Answers

It's not an Eclipse bug, it's expected behavior. Just use super.doMagic();, it works fine. You cannot call the Test.super.doMagic() as later the doMagic() can be reimplemented in TestImpl superclass. In this case the TestImpl implementation must completely shadow the Test implementation making it inaccessible.

like image 101
Tagir Valeev Avatar answered Sep 30 '22 17:09

Tagir Valeev


This is by design; you can call your direct super-methods, but not your grandparents.

Think about this by analogue to classes:

class A { 
    void m() { }
}

class B extends A { ... }

class C extends B { 
    void m() { 
        super.m(); // OK
    }
}

Imagine if it was OK for C to explicitly call the implementation in A, bypassing that of B. This would be totally broken! B could not enforce its representational invariants. That's what overriding means -- if B overrides a method from A, that overridden method is only accessible from B.

The restrictions for default super-calls attempt to track this goal (though multiple inheritance makes this far trickier.) You can call your immediate supers; you can't make an end-run around your supers by trying to directly call your grandparents. That would similarly undermine what override means here.

like image 32
Brian Goetz Avatar answered Sep 30 '22 17:09

Brian Goetz