2016-03-17 22 views
6

Dato AGenericClass dichiarato come di seguito:Come differiscono queste tre variabili parametrizzate?

public class AGenericClass<T> { 
    T subject; 
    public void setSubject(T subject) { 
    this.subject = subject; 
    } 
} 

Quali sono le differenze tra variabili un, b, e c?

AGenericClass<String> a = new AGenericClass<>(); 
AGenericClass<?> b = new AGenericClass<String>(); 
AGenericClass c = new AGenericClass<String>(); 

a.setSubject("L"); // OK. 

b.setSubject("M"); // Error: setSubject(capture<?>) cannot be 
        // applied to (java.lang.String) 

c.setSubject("N"); // Warning: Unchecked call to 'setSubject(T)' 
        // as a member of raw type 'AGenericClass' 

unb e c tutti sono dichiarati senza lamentarsi dall'IDE, ma tutti si comportano in modo diverso quando setSubject si chiama.

risposta

3

Le differenze tra i tre hanno in gran parte a che fare con i controlli che si ottengono in fase di compilazione. Dato che i generici erano pensati per proteggere l'utente da un cast non sicuro in fase di runtime, le differenze critiche e principali tra di loro sono radicate lì.


AGenericClass<String> dichiara un'istanza di una classe generica specificamente di tipo String. Qualsiasi operazione eseguita con questo generico che richiede un parametro generico avrà quel parametro associato a String e applicherà la verifica del tipo e la sicurezza del tipo al momento della compilazione.

Vale a dire, se si dispone di AGenericClass<String> a = new AGenericClass<>(); e si tenta di chiamare a.setSubject(3), Java non consentirà la compilazione dell'applicazione poiché i tipi non corrispondono.

AGenericClass<?> dichiara un'istanza di una classe generica con tipi sconosciuti.Formalmente, ? è un jolly in cui potrebbe essere qualsiasi tipo, che è bene se si desidera recuperare gli elementi da esso, ma non bene se si desidera aggiungere gli elementi da esso.

Il motivo? AGenericClass<?> è in realtà AGenericClass<? extends Object> e questo è importante a causa dello in and out principle. Generalmente (sebbene questa non sia una garanzia rigorosa), qualsiasi cosa generica con extends implica un'operazione di sola lettura.

Come ho detto prima, è bene leggere da, dal momento che la garanzia di una classe che è al massimo un Object, ma non è possibile scrivere ad esso in quanto non si sa, né può si garantisce , che tipo di oggetto stai aggiungendo ad esso da qualsiasi chiamata.

AGenericClasssenza il tipo di dichiarazioni è un tipo non elaborato. You can read more about them here, ma sappiamo che esistono per motivi di compatibilità legacy. Se il tuo codice utilizza i tipi non elaborati, il tuo perde i controlli del tempo di compilazione e il tuo codice potrebbe finire per generare un ClassCastException durante il runtime, operazione molto più difficile da eseguire il debug, diagnosticare e risolvere.

1
AGenericClass<String> a = new AGenericClass<>(); 

Indica che questo è un AGenericClass di String tipo e accetterà stringa nel parametro al posto del tipo di parametro T. Quindi non si lamenta quando hai chiamato a.setSubject("L");.

AGenericClass<?> b = new AGenericClass<String>(); 

? indica che è unbounded jolly, significa un tipo

non è specificato o sconosciuto

Con questo, tutto ciò che è garanzia è ottenere un rendimento di tipo sarebbe Object, se si avere un metodo come public T getSubject(). È possibile assegnare a una variabile di tipo Object o passarla come parametro in cui è previsto il tipo Object. Non sarà in grado di eseguire operazioni impostate. extends e super sono due parole chiave che è possibile utilizzare insieme a ? per impostare il limite inferiore/superiore che è possibile esplorare ulteriormente.

AGenericClass c = new AGenericClass<String>(); 

Il Warning: Unchecked call to 'setSubject(T)'.. indica che il messaggio è stato fatto come tipo grezzo, quindi non si lamentano anche se si chiama setSubject(new Integer(1)) cioè, non esegue alcun controllo per la sicurezza tipo. Ma in seguito, quando si tenta di ottenere questo oggetto e di trasmetterlo a String, si incontra lo ClassCastException poiché si è ignorato l'avviso del compilatore e non si ottiene il beneficio di sicurezza del tipo fornito dai generici.

2
AGenericClass<String> a = new AGenericClass<>(); 

Così chiamato istanza generica "Diamond". Quando si imposta <> vuoto sul costruttore di tipo generico, il compilatore proverà a determinare il tipo dal contesto. Nel compilatore caso di esempio verrà utilizzato <String> perché a dichiarato con <String>.


AGenericClass<?> b = new AGenericClass<String>(); 

Questa denominato "Unbounded Wildcards". b verrà creato come generico di tipo sconosciuto. Quando si sta tentando di utilizzare setSubject(), il compilatore non può controllare il tipo di argomento. Questo è il motivo per cui ottieni l'eccezione. Per risolvere questo problema, puoi creare un metodo di supporto con tipo generico definito.


AGenericClass c = new AGenericClass<String>(); 

In questo caso c dichiarata come "Raw type". c verrà creato come generico con il parametro <Object>. Perché è possibile assegnare String a Object, il metodo setSubject() funzionerà con un String. In realtà, funzionerà con qualsiasi tipo, ereditato da Object e potenzialmente potrebbe essere la causa dell'errore. E il compilatore ti avvisa a riguardo.

Problemi correlati