2013-07-18 13 views
13

a List then Perché il codice (sotto) viene compilato? Sicuramente MyClass2 dovrebbe restituire un List<Integer>?Perché questa classe viene compilata anche se non implementa correttamente la sua interfaccia?

public class Main { 
    public static void main(final String[] args) { 
    MyClass myClass = new MyClass(); 
    List list = myClass.getList(); 
    System.out.println(list); 
    System.out.println(list.get(0).getClass()); 

    MyClass2 myClass2 = new MyClass2(); 
    List list2 = myClass2.getList(); 
    System.out.println(list2); 
    System.out.println(list2.get(0).getClass()); 
    } 

    public interface Int1 { 
    public List getList(); 
    } 

    public interface Int2 extends Int1 { 
    @Override 
    public List<Integer> getList(); 
    } 

    public static class MyClass implements Int2 { 
    @Override 
    public List<Integer> getList() { 
     return Arrays.asList(1, 2, 3); 
    } 
    } 

    public static class MyClass2 implements Int2 { 
    @Override 
    public List getList() { 
     return Arrays.asList("One", "Two", "Three"); 
    } 
    } 
} 

ho notato se si tenta di renderlo un List<String> poi si ottiene un errore "java: Main.MyClass2 non è astratta e non sovrascrive metodo astratto getList() in Main.Int2". Non capisco perché non capisci questo nell'esempio sopra.

Nota: la soluzione al problema nel mio progetto è rendere l'interfaccia stessa generica, ad esempio Int1<X> (ovviamente uso nomi migliori di questo, è solo un esempio).

+6

Generalmente si dovrebbero avere avvertenze nell'output del compilatore – fge

+0

Perché Java Generics fa schifo. – schlingel

risposta

5

La risposta è in JLS 7 5.5.1. Reference Type Casting:

Dato un tempo di compilazione tipo di riferimento S (sorgente) e un tempo di compilazione riferimento di tipo T (target), una conversione colata esiste da s a t se non si verificano errori in fase di compilazione a causa delle seguenti regole.

Se S è un tipo di classe:

If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs. 

Furthermore, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types 

(§4.5), e che le cancellature di X e Y sono uguali, una fase di compilazione si verifica errore.

Nel tuo caso List<Integer> e List<String> sono dimostrabilmente i tipi parametrici distinti ed entrambi hanno stessi cancellature: List.

7

Ho il sospetto, il compilatore dovrebbe essere si dà avvertimento per conversione incontrollato, piuttosto che la marcatura come errore del compilatore. Cerchiamo di capire il motivo per cui non ti avverte:

Hai seguendo due metodi per implementare per soddisfare il contratto dell'interfaccia di implementare:

public List getList(); 
public List<Integer> getList(); 

Ora, se nella tua classe, è sufficiente fornire l'implementazione del primo metodo , può gestire la richiesta per il metodo 2 nd. È possibile restituire un List<Integer> con il tipo restituito List. Questo perché un List<Integer> non è altro che un List in fase di runtime, a causa della cancellazione del tipo .

Tuttavia, se si assegna l'implementazione del metodo 2 n., il contratto non soddisfa il primo metodo. Il primo metodo dice che può restituire qualsiasi tipo di List, poiché ha utilizzato il tipo non elaborato nel tipo restituito. Quindi, può restituire List<Integer>, List<Object>, List<String>, qualsiasi cosa. Ma il metodo 2 nd può restituire solo List<Integer>.

compilatore fare questo tipo il controllo in fase di compilazione e vi darà avvertimento, che richiede la conversione List deselezionata per List<Integer>, perché la conversione avrà comunque successo in fase di esecuzione, a causa di digitare la cancellazione.


Questo è il caso simile come qui sotto:

List<String> listString = new ArrayList<String>(); 
List rawList = new ArrayList(); 

listString = rawList; // Warning: Unchecked conversion 
rawList = listString; 

consigliata lettura:

+0

Non capisco come "le due interfacce si contraggono per soddisfare". Un'interfaccia sovrascrive l'altra, quindi sicuramente 'Int2' che' MyClass2' deve soddisfare? Come può una richiesta per un 'Elenco' gestirne uno per un' Elenco '? So che sono gli stessi dopo la cancellazione del tipo, ma non sono la stessa prima della sua compilazione perché nel secondo controlla i tipi di ciò che si aggiunge ad esso/rimuoverlo ecc. –

+0

@PaulRichards.Sì, in realtà, tecnicamente stai implementando una sola interfaccia. Che estende la prima interfaccia. Quindi, puoi dire che devi soddisfare solo il contratto della singola interfaccia. Questo eredita il metodo da un'interfaccia diversa. –

+0

Come ho detto, un metodo con tipo di ritorno 'List' può restituire qualsiasi tipo di lista. Quindi, può anche restituire 'Elenco '. Quindi, questo è l'altro metodo. Dovrebbe restituire 'Lista ', che è curata da 'List'. –

4

La firma di public List<Integer> getList() corrisponde alla firma di public List getList() dopo la cancellazione del tipo. Per sovrascrivere i metodi è necessario che il metodo di sovrascrittura sia una sottosegnalazione del metodo sottoposto a override. Il compilatore deciderà qui che il metodo della sottoclasse sovrascrive l'interfaccia se sono identici dopo la cancellazione del tipo e non possiamo mai avere un conflitto.

4

Questo, letteralmente, non ha alcun effetto a causa della cancellazione del tipo:

public interface Int1 { 
    public List getList(); 
} 

public interface Int2 extends Int1 { 
    @Override 
    public List<Integer> getList(); 
} 

In fase di esecuzione, qualsiasi List<X> diventa List. Quindi non stai cercando nulla qui @Override. Il prototipo di runtime di .getList() è List getList(). Il fatto che parametrizzi il tuo in Int2 è completamente ignorato.

Il compilatore avvisa su questo:

java: Note: Main.java uses unchecked or unsafe operations. 
java: Note: Recompile with -Xlint:unchecked for details. 
0

in modo che appaia come il suo correlato al tipo di cancellazione e il suo il genere di cosa che genera un avviso, piuttosto che un errore di compilazione. Immagino sia come gli altri scenari di conversione incontrollati che ho visto prima. Grazie per le risposte ben studiate alle persone.

Problemi correlati