2015-04-08 18 views
24

Załóżmy, że istnieją dwa interfejsy: Interface1 i Interface2, gdzie Interface2 rozszerza się o .Domyślne metody i interfejsy rozszerzające inne interfejsy

interface Interface1 { 

    default void method() { 
     System.out.println("1"); 
    } 

    // Other methods 
} 

interface Interface2 extends Interface1 { 

    @Override 
    default void method() { 
     System.out.println("2"); 
    } 

    // Other methods 
} 

Załóżmy, że chcemy utworzyć klasę, która implementuje Interface2 ale chcę method() być wersja w Interface1. Jeśli piszę

class MyClass implements Interface1, Interface2 { 

    public void method() { 
     Interface1.super.method(); 
    } 
} 

pojawia się błąd kompilacji:

bad type qualifier in default super call: redundant interface Interface1 is extended by Interface2

To jest możliwe, aby obejść ten problem, tworząc trzeci interfejs:

interface Interface3 extends Interface1 { 

    default void method() { 
     Interface1.super.method(); 
    } 
} 

wówczas:

class MyClass implements Interface1, Interface2, Interface3 { 

    public void method() { 
     Interface3.super.method(); 
    } 
} 

To kompiluje się dobrze, a jeśli ja w Stantiate nowego MyClass i wywołaj method(), wyjście jest zgodnie z oczekiwaniami 1.

Moje pytanie brzmi, biorąc pod uwagę, że tak łatwo jest obejść ograniczenie, że można napisać tylko InterfaceName.super.method() dla najbardziej konkretnego interfejsu w łańcuchu, jaki jest powód ograniczenia? W jaki sposób zapobiega się problemom, uniemożliwiając pisanie Interface1.super.method() w pierwszej kolejności?

+2

Jeśli 'Interface2 rozciąga Interface1', w których scenariusz chcesz klasą je realizować zarówno * *? – Maroun

+0

@MarounMaroun Masz rację, nie ma sensu pisać ich obu. Po prostu na IntelliJ dostałem mniej pomocny komunikat o błędzie, jeśli napisałem tylko "Interface2". –

+0

metody w 'interfejsach' mają ciało, zgaduję, że muszę zrewidować moje podstawy. Sądzę, że mają być abstrakcyjne. –

Odpowiedz

16

To jest dokładnie opisane przez JLS w 15.12.3."Czas kompilacji Krok 3: czy wybrana metoda jest odpowiednia?".

If the form is TypeName . super . [TypeArguments] Identifier, then:

  • […]
  • If TypeName denotes an interface, let T be the type declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (§9.4.1) the compile-time declaration from a direct superclass or direct superinterface of T .

JLS wyjaśnia, dlaczego zasada jest na swoim miejscu:

In the case that a superinterface overrides a method declared in a grandparent interface, this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface, and only if that interface chooses to expose the desired behavior.

Tak to mniej lub bardziej konkretnie istnieje powstrzymać od robienia tego, co próbujesz zrobić.

Ale JLS wydaje się również, aby potwierdzić swoje rozwiązania:

(Alternately, the developer is free to define his own additional superinterface that exposes the desired behavior with a super method invocation.)

+0

To naprawdę interesujące. Są w porządku z workaraound (co wydaje się dla mnie hackowaniem), ale jedynym powodem, dla którego odrzucili oryginał, jest to, że nie uważają go za "odpowiedni". –

+1

Tak, wydaje się to trochę dziwne. Być może @BrianGoetz (hi Brian) ma kilka uwag na temat racjonalnego uzasadnienia. – Radiodef

+1

Tak, uważam to również za dziwne. Rozumiem, jeśli na przykład javadoc automatycznie wykrył, która implementacja podklasy decyduje się na użycie i wygeneruje odpowiednią dokumentację. Ale wątpię, aby tak było, ponieważ, AFAIK, javadoc nie dba o całą masę metod. –