2016-05-12 73 views
6

Diciamo che ci sono i seguenti tipi:Java metodo 8 di default eredità

public interface Base { 

    default void sayHi(){ 
     System.out.println("hi from base"); 
    } 
} 

public interface Foo extends Base { 
    @Override 
    default void sayHi(){ 
     System.out.println("hi from foo"); 
    } 
} 

public interface Bar extends Base { 
} 

public class MyClass implements Foo, Bar { 
    public static void main(String[] args) { 
     MyClass c = new MyClass(); 
     c.sayHi(); 
    } 
} 

In questo scenario, se main viene eseguito, "hi da foo" viene stampato. Perché l'implementazione di Foo ha la precedenza? Non Bar eredita sayHi() da Base, poiché se MyClass dovesse implementare solo Bar, l'implementazione Base si chiamerebbe? Quindi avrebbe senso che il codice non si compilasse ancora. Inoltre, dal momento che Bar dovrebbe avere implementazione Base s' di sayHi(), perché non posso ignorare che in MyClass come:

@Override 
public void sayHi() { 
    Bar.super.sayHi(); 
} 

Il seguente errore si verifica quando si cerca di farlo:

male qualificatore di tipo Bar in metodo di default super-chiamata, sayHi() viene ignorato in Foo

+0

@Casey Che IDE stai utilizzando? Eclipse dà un altro errore. –

+0

@JornVernee Era di IntelliJ. Che cosa produce Eclipse? – Casey

+0

@Casey '' 'Il riferimento illegale al metodo super sayHi() dal tipo Base, non può ignorare l'override più specifico di tipo Foo''' –

risposta

9

Questo comportamento viene specificato utilizzando quasi il vostro esempio esatto in JLS 9.4.1, solo wi th alcuni nomi cambiati in giro:

interface Top { 
    default String name() { return "unnamed"; } 
} 
interface Left extends Top { 
    default String name() { return getClass().getName(); } 
} 
interface Right extends Top {} 

interface Bottom extends Left, Right {} 

destro eredita nome() da Top, ma il nome eredita inferiore() da sinistra, non è giusto. Questo perché name() di Left sovrascrive la dichiarazione di name() in Top.

Il JLS non sembra dare alcun motivo particolarmente concreto che io possa vedere; questo è il modo in cui i progettisti Java hanno deciso che l'ereditarietà avrebbe funzionato.

+0

Ha senso. Sembra un difetto di design. L'override di un metodo predefinito nasconde per sempre l'implementazione originale, che in una gerarchia complessa potrebbe essere critica. Sembra lasciare che la classe concreta decida quale implementazione usare sarebbe un'idea migliore. – aiguy

+3

@aiguy che ... è il punto di scavalcare. Questo è sempre stato vero per l'ereditarietà normale della classe, che sovrascrive completamente l'implementazione del supertipo. –

+0

beh, nell'ereditarietà normale della classe non si possono mai avere 2 implementazioni genitore. Il mio punto è che se in una gerarchia complessa qualcuno aggiunge un override dell'implementazione predefinita originale, potrebbe interrompere l'intera gerarchia se alcune delle classi concrete si basano sull'implementazione originale. – aiguy

9

Questo è di progettazione. Da JLS 15.12.3:

Se il modulo è TypeName. super [TypeArguments] Identifier, quindi:

  • Se TypeName indica un'interfaccia, lasciate T la dichiarazione di tipo immediatamente racchiude il metodo. Un errore di compilazione si verifica se esiste un metodo, distinta dalla dichiarazione compilazione, che sostituisce (§9.4.1) la dichiarazione di compilazione dal una superclasse diretta o superinterfaccia diretta di T.

Nel caso che una superinterfaccia sovrascrive un metodo dichiarato in un'interfaccia grandparent, questa regola impedisce all'interfaccia figlio di "saltare" l'override semplicemente aggiungendo il nonno alla sua lista di superinterfacce dirette. Il modo appropriato per accedere alla funzionalità di un nonno è attraverso la superinterfaccia diretta e solo se quell'interfaccia sceglie di esporre il comportamento desiderato. (In alternativa, lo sviluppatore è libero di definire la propria superinterfaccia aggiuntiva che espone il comportamento desiderato con un super metodo.)

+0

Tra questa e [l'altra risposta] (http://stackoverflow.com/a/37197609/5221149), la domanda ha ricevuto una risposta completa. Ora, quale risposta viene accettata? Hmmm .... – Andreas