2015-06-24 24 views
6

Ho faticato a trovare un titolo appropriato per questa domanda perché il fenomeno che ho osservato è molto strano. Quindi evito di spiegare il mio problema alla lettera e invece ti mostro un codice (che spero) auto-descrittivo. Si consideri il seguente classe parametrica:Perché Eclipse Compiler perde il parametro di tipo fisso?

public class GenericOptional<T> { 

    public GenericOptional(T someValue) {} 

    public T getValue() { return null; } 

    public Optional<String> getOptionalString() { return Optional.empty(); } 
} 

Quello che mi piace sottolineare è che il tipo di ritorno del metodo Optional<String>getOptionalString() non dipende dal tipo di parametroT.

Ora uno sguardo al seguente codice, che viene compilato all'interno Eclipse Luna 4.4.2 utilizzando Java 8u45:

public static void main(String[] args) { 
    Object obj = new GenericOptional<>(Boolean.TRUE); 
    GenericOptional go = (GenericOptional) obj; 
    Optional os = go.getOptionalString(); 
} 

La variabile locale os ha il tipo Optional senza la tipo- parametroString! Il compilatore Eclipse ha perso le informazioni sul parametro di tipo fisso. Qualcuno sa perché?

ora un'occhiata a un secondo esempio di codice:

public static void main(String[] args) { 
    Object obj = new GenericOptional<>(Boolean.TRUE); 
    GenericOptional<?> go = (GenericOptional) obj; 
    Optional<String> os = go.getOptionalString(); 
} 

dichiarando la variabile locale go come GenericOptional<?> il tipo di ritorno del metodo getOptionalString() ora è Optional<String> come previsto.

Qualcuno può spiegare questo comportamento?

risposta

4

Siete di fronte al comportamento di raw types. Quando si utilizza un tipo non elaborato, Generics viene effettivamente disattivato completamente, indipendentemente dal fatto che esista una connessione tra la firma generica del membro e il parametro type della classe.

Il ragionamento dietro questo è che i tipi di sono una funzionalità per retrocompatibilità solo con il codice di pre-Generics. Quindi o hai generici o non lo fai.

Se il metodo generico non dipende dal parametro di tipo effettivo della classe, il problema è facile da risolvere:

GenericOptional<?> go = (GenericOptional<?>) obj; 
Optional<String> os = go.getOptionalString(); 

Utilizzando <?> implica “Non so il parametro di tipo effettivo e io don Non importa, ma sto usando il controllo di tipo generico ".

+0

Grazie per la risposta. Kocko ha dato la stessa risposta e non so come darti la corretta/migliore approvazione. Quindi, poiché hai risposto per primo alla domanda, anche se non hai fornito codice di esempio per supportare la tua spiegazione, ti darò l'approvazione "più utile". Se pensi che la risposta di Kocko sia più importante per le persone che vogliono sapere come funziona, lasciami fare e trasferirò l'approvazione "più utile" a Kocko. – Harmlezz

4

Non si tratta di Eclipse o altro, ma di tipi non elaborati.

Rivediamo questo frammento:

public static void main(String[] args) { 
    Object obj = new GenericOptional<>(Boolean.TRUE); 
    GenericOptional go = (GenericOptional) obj; 
    Optional os = go.getOptionalString(); 
} 

Qui, si sta creando un'istanza grezzo di GenericOptional, il che significa che le informazioni sul tipo-parametro verrà completamente disattivato. Così, un'istanza di un grezzoGenericOptional significa che l'istanza esporrà i metodi come segue:

public class GenericOptional { 

    public GenericOptional(Object someValue) {} 

    public Object getValue() { return null; } 

    public Optional getOptionalString() { return Optional.empty(); } 
} 

Tuttavia, se ora in rassegna il secondo frammento di

public static void main(String[] args) { 
    Object obj = new GenericOptional<>(Boolean.TRUE); 
    GenericOptional<?> go = (GenericOptional) obj; 
    Optional<String> os = go.getOptionalString(); 
} 

possiamo vedere che si sta facendo un'istanza generica di GenericOptional. Anche esso è di tipo-parametro è <?>, il compilatore non turn-off preoccuparsi di tipo-parametri, quindi l'istanza esporrà il metodo getOptionalString() parametrizzato, in questo modo:

public Optional<String> getOptionalString() { return Optional.empty(); } 
+0

Grazie Kocko per la bella spiegazione. Si prega di vedere il commento che ho aggiunto alla risposta di Holger perché tendevo a dargli l'approvazione "più utile". Spero che tu stia bene con questa decisione. – Harmlezz

Problemi correlati