Voglio provare a scomporre la risposta di @DerMike per spiegare:
Innanzitutto, la cancellazione del tipo non significa che JDK elimini le informazioni sul tipo in fase di esecuzione. È un metodo per consentire alla verifica del tipo in fase di compilazione e alla compatibilità del tipo di runtime di coesistere nella stessa lingua. Come implica questo blocco di codice, il JDK conserva le informazioni sul tipo cancellato - non è semplicemente associato a cast e cose controllati.
In secondo luogo, ciò fornisce informazioni di tipo generico a una classe generica esattamente a un livello superiore dell'erarchia dal tipo concreto che viene verificato - vale a dire una classe padre astratta con parametri di tipo generico può trovare i tipi di calcestruzzo corrispondenti ai suoi parametri di tipo per un'implementazione concreta di se stessa che eredita direttamente da esso. Se questa classe fosse non astratta e istanziata, o l'implementazione concreta fosse inferiore di due livelli, ciò non funzionerebbe (anche se un po 'di jimmy potrebbe farla applicare a qualsiasi numero predeterminato di livelli oltre uno, o fino alla classe più bassa con X parametri di tipo generico, eccetera).
Comunque, sulla spiegazione. Ecco di nuovo il codice, diviso in righe per facilità di riferimento:
Classe 1 # genericParameter0OfThisClass =
2 # (Classe)
3 # ((ParameterizedType)
4 # getClass ()
5 # .getGenericSuperclass ())
6 # .getActualTypeArguments () [0];
Lasciateci "essere" la classe astratta con tipi generici che contiene questo codice. Leggendolo all'incirca:
- La riga 4 ottiene l'istanza di classe della classe concreta corrente. Questo identifica il tipo concreto del nostro discendente immediato.
- La riga 5 ottiene il supertipo di quella classe come Tipo; Questi siamo noi. Dato che siamo un tipo parametrico, possiamo tranquillamente lanciarci su ParameterizedType (linea 3). La chiave è che quando Java determina questo oggetto Type, utilizza le informazioni di tipo presenti nel figlio per associare le informazioni di tipo ai nostri parametri di tipo nella nuova istanza ParameterizedType. Quindi ora possiamo accedere a tipi concreti per i nostri generici.
- La riga 6 ottiene l'array di tipi mappato nei nostri generici, nell'ordine dichiarato nel codice di classe. Per questo esempio estraiamo il primo parametro. Questo ritorna come Tipo.
- La riga 2 lancia il Tipo finale restituito a una Classe. Questo è sicuro perché sappiamo quali tipi sono in grado di prendere i nostri parametri di tipo generico e possiamo confermare che saranno tutti classi (non sono sicuro di come in Java si otterrebbe un parametro generico che non ha un'istanza di classe associato ad esso, in realtà).
... e basta. Quindi riponiamo in noi le informazioni sul tipo dalla nostra implementazione concreta e le usiamo per accedere a un handle di classe. potremmo raddoppiare getGenericSuperclass () e passare a due livelli, oppure eliminare getGenericSuperclass () e ottenere valori per noi stessi come un tipo concreto (avvertenza: non ho testato questi scenari, non mi sono ancora inventato).
Diventa difficile se i tuoi figli concreti sono un numero arbitrario di luppoli di distanza, o se sei concreto e non definitivo, e particolarmente difficile se ti aspetti che i tuoi figli (variabilmente profondi) abbiano i loro generici. Ma di solito è possibile progettare attorno a queste considerazioni, quindi questo ti dà la maggior parte del modo.
Spero che questo abbia aiutato qualcuno! Riconosco che questo post è antico. Probabilmente prenderò questa spiegazione e la terrò per altre domande.