2015-01-26 17 views
10

Scusa se questo è stato già spiegato, ma non ho trovato thread simili ovunque nel web.Nessun errore del compilatore relativo ai cast incompatibili

Oggi ho aperto una classe di progetto in IDE e ho visto un errore (sottolineatura rossa), anche se il progetto è stato compilato correttamente.

Quindi, il codice è:

public interface DatasourceImplementation<T extends Entity> { 
    .... 
} 

public interface Datasource<T extends Entity> { 
    .... 
} 


public interface DsContext { 
    @Nullable 
    <T extends Datasource> T get(String name); 
} 

Ed ora noi chiamiamo questo metodo come questo:

DatasourceImplementation dsImpl = getDsContext().get("dsName"); 

Idea13 mi dà errore (tipi incompatibili) - Penso che sia giusto.

Idea14 non mostra errori qui.

JDK lo compila senza errori - questo è triste.

Devo dire che nella nostra classe di implementazione del progetto l'interfaccia A implementa sempre l'interfaccia B (forse spiega perché Idea14 dice che è OK), ma a mio parere non può giustificare questo comportamento - perché generalmente posso creare classe che implementa A e non implementa B. Voglio la tipizzazione statica nel mio codice, non voglio vedere le eccezioni del cast di classi di runtime.

Quindi, chi ha torto qui?

Aggiornamento. Aggiungere uno screenshot con le classi reali (non sono sicuro che spiegherà qualcosa di più, è proprio lo stesso che ho descritto)

enter image description here

+2

Questo è davvero interessante, potremmo vedere un programma semplificato completo? –

+0

@RichardTingle Ho aggiunto uno screenshot di queste 4 classi semplificate - è sufficiente? – AdamSkywalker

+0

Inserisci il codice come testo. Primo pensiero: si sta utilizzando il tipo non elaborato Datasource nel tipo di ritorno generico del metodo 'get()'. –

risposta

3

JDK è corretto. La dichiarazione promette di restituire QUALSIASI origine dati, se non corrisponde ci sarà solo un errore di runtime. Il compilatore potrebbe mostrare alcuni avvertimenti gravi, ma dovrebbe compilarlo. Lo sviluppatore originale del tuo snippet probabilmente intendeva evitare un cast esplicito in ogni chiamata.

diversi modi su come risolvere il problema in base al intento:

  1. DataSource<?> get(String name): chiamante dovrà lanciare a DatasourceImplementation.
  2. <T extends Datasource> T get(Class<T> dsType, String name). La funzione chiamata può controllare o selezionare il tipo restituito in fase di esecuzione, ad es. se si desidera restituire Impl1 o Impl2.
  3. <T extends Entity>' Datasource<T> get(String name): Probabilmente era previsto. Funziona finché DatasourceImplementation non ha bisogno di conoscere il tipo di entità concreto. Se ha bisogno di saperlo, allora <T extends Entity>' Datasource<T> get(Class<T> entityType, String name) sarebbe meglio.
+1

Capisco cosa dici, ma sembra che usare (dove X è intefaccia) ti consenta di evitare qualsiasi cast di classe tra X e qualsiasi interfaccia Y. Questo è strano, non credi? – AdamSkywalker

+0

' T f() {return (T) new Integer (1); } ': Il compilatore mostrerà solo l'avviso all'interno di f(), ma non quando chiama f(). Un tale metodo con il tipo di ritorno non dipendente da alcun parametro di input è in effetti una brutta scappatoia. Vedere http://stackoverflow.com/a/509324/404501 per un'applicazione brutta. –

+0

OK, ho scritto alcuni test che hanno approvato, che l'uso di ti permette di fare qualsiasi cast tu voglia, dal momento che sono possibili. Sembra che Idea13 sia sbagliato (rispondendo alla mia domanda). Dovrebbe semplicemente contrassegnare il codice come non sicuro. – AdamSkywalker

0

a prima vista il tuo codice/domanda sembra essere un po 'strano.

Si dispone di due interfacce indipendenti l'una dall'altra e entrambe con un tipo generico.

  1. DatasourceImplementation < T estende Entity > e
  2. Origine dati < T estende Entity >

tuttavia che avete < T estende Entità > non significa che queste Bose T sono uguali. In effetti, può essere implementazioni completamente diverse (entrambe estendentesi dall'entità) in cui nessuna può essere trasmessa all'altro tipo.

Inoltre avete la vostra interfaccia

public interface DsContext { 
    @Nullable 
    <T extends Datasource> T get(String name); 
} 

in cui si dice che il get-metodo deve restituire qualcosa che implementa origine dati. Tuttavia questa T è completamente indipendente da entrambe le altre. In effetti, il compilatore dovrebbe lamentarsi di utilizzare l'origine dati come tipo non elaborato.

Intendevi invece <T extends Entity> Datasource<T> get(String name); ?

Tuttavia, poiché non esiste alcuna relazione da un'origine dati a un'attribuzione Datasource, questi sono due tipi indipendenti l'uno dall'altro, come se fosse uno java.lang.String a java.lang.Number. Provare ad assegnare un numero a un riferimento dichiarato di tipo String o viceversa comporterebbe anche un errore del compilatore. Quindi il compilatore che riporta un errore sembra perfettamente a posto.

I frammenti di codice hanno perso qualcosa di importante (ereditarietà)? Inoltre il compilatore in tutti i casi è stato effettivamente eseguito?

Sebastian

Problemi correlati