Imansible eseguire il cast di tipi non annidati non specifici con generici

Ho due classi con generici annidati. C’è un modo per sbarazzarsi di

Tipo mancata corrispondenza: imansible convertire da Msg<Value> a Msg<Value> errore? Nell’ultimo incarico

 public class Value { V val; public Value(V val) { this.val = val; } @Override public String toString() { return "" + val; } } public class Msg { T holder; public Msg( T holder) { this.holder = holder ; } public String toString() { return "" + holder; } public static void main(String[] args) { Msg<Value>strMsg = new Msg(new Value("abc")); // This is OK MsgobjMsg = strMsg; // Type mismatch: cannot convert from Msg<Value> to Msg<Value> Msg<Value>objMsg = strMsg; } } 

Utilizza il seguente:

 Msg> someMsg = strMsg; 

Il problema è che il ? in Msg> objMsg NON è in grado di acquisire la conversione. Non è “un Msg di Value di qualche tipo. È” un Msg di Value di QUALSIASI tipo “.

Questo spiega anche il motivo per cui insieme alla modifica della dichiarazione, ho anche rinominato la variabile in someMsg . Il Value non può essere qualsiasi Object . Deve appartenere ad un certo tipo ( String in questo esempio).


Un esempio più generico

Consideriamo un esempio più generico di un List> . Analogamente allo scenario originale, un List> NON può acquisire-convertire un List> .

  List> lolInt = null; List> lolAnything = lolInt; // DOES NOT COMPILE!!! // a list of "lists of anything" List> lolSomething = lolInt; // compiles fine! // a list of "lists of something" 

Ecco un altro modo per vederlo:

  • I generici di Java sono di tipo invariante
  • C’è una conversione da Integer a Number , ma una List< Integer > non è una List< Number >
    • Allo stesso modo, un List può essere convertito in cattura da un List , Ma un List< List non è un List< List >
  • Usando un carattere jolly limitato, un List List Number > can capture-convert a List< Integer >
    • Allo stesso modo, una List List List può acquisire-convertire un List< List >

Il fatto che alcuni ? può catturare e altri non possono anche spiegare il seguente frammento:

  List> lolAnything = new ArrayList>(); // compiles fine! List listSomething = new ArrayList(); // DOES NOT COMPILE!!! // cannot instantiate wildcard type with new! 

Domande correlate

  • I caratteri jolly multipli su metodi generici rendono il compilatore Java (e io!) Molto confuso
    • Esplorazione molto lunga e dettagliata di questo problema
  • List> generico Java List> List>
  • Un modo semplice per spiegare perché non riesco a fare List animals = new ArrayList() ?
  • Qual è la differenza tra e ?

Guarda anche

  • Esercitazione su Java Generics
    • Generici e sottotitoli | Caratteri jolly | Più divertimento con i caratteri jolly
  • Domande frequenti su Java Generics di Angelika Langer
    • Che cos'è un carattere jolly limitato?
    • Quali relazioni di sottotipo esistono tra le istanze di tipi generici?

Sebbene il tuo parametro di tipo generico contenga un carattere jolly, non è esso stesso un jolly. Quando si assegna a una variabile ( Msg ) con un T generico non jolly, l’object assegnato deve avere esattamente T come tipo generico (compresi tutti i parametri di tipo generico di T , jolly e non jolly). Nel tuo caso T è Value , che non è dello stesso tipo di Value .

Cosa puoi fare, perché Value è assegnabile al Value , Utilizza il tipo di carattere jolly:

 Msg> a = new Msg>(); 

La mia risposta è simile a un’altra, ma si spera sia più chiara.

 List> is a list of (lists of anything). List> is a list of (lists of strings). 

Quest’ultimo non può essere convertito nel primo perché così facendo si consentirebbe di aggiungere un elenco al proprio Elenco >, che sarebbe chiaramente rotto.

Si noti che le regole per questo non cambiano se si sostituisce List con un tipo che non ha .add. Java avrebbe bisogno di dichiarazione-sito covarianza e / o controvarianza per quello (come IEnumerable di C # o Scala’s List [+ A]). Java ha solo covarianza e contravarianza del sito d’uso (? Extends X,? Super X).

Non una risposta diretta, ma consiglio vivamente la lettura di: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf per capire meglio i generici.

ILMTitan ha una buona soluzione e se non vuoi rendere la class specifica a Value puoi anche usare il tipo di base anziché i generici a questo punto, perché stai distriggersndo una funzione di sicurezza, ma c’è un modo . Potresti anche essere in grado di passare un parametro per rendere questo metodo più generico, ma la chiave è “@SuppressWarnings”.

 @SuppressWarnings("unchecked") Msg> convert() { return (Msg>) this; }