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.
AGenericClass
senza 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.