Ich möchte versuchen, die Antwort von @DerMike aufzuschlüsseln, um Folgendes zu erklären:
Erstens bedeutet das Löschen des Typs nicht, dass das JDK eliminiert Typinformationen zur Laufzeit. Es ist eine Methode, mit der die Typprüfung zur Kompilierungszeit und die Laufzeitkompatibilität in derselben Sprache koexistieren können. Wie dieser Codeblock impliziert, behält das JDK die gelöschten Typinformationen bei - es ist nur nicht mit überprüften Casts und Sachen verbunden.
Zweitens liefert dies generische Typinformationen für eine generische Klasse genau eine Ebene höher als die Hierarchie des zu überprüfenden konkreten Typs - dh eine abstrakte übergeordnete Klasse mit generischen Typparametern kann die konkreten Typen finden, die ihren Typparametern für eine konkrete Implementierung von sich selbst entsprechen das erbt direkt davon. Wenn diese Klasse nicht abstrakt und instanziiert wäre oder die konkrete Implementierung zwei Ebenen tiefer wäre, würde dies nicht funktionieren (obwohl ein wenig Jimmying dazu führen könnte, dass sie auf eine vorgegebene Anzahl von Ebenen über eine oder bis zur niedrigsten Klasse angewendet wird mit X generischen Typparametern usw.).
Wie auch immer, weiter zur Erklärung. Hier ist noch einmal der Code, der zur leichteren Bezugnahme in Zeilen unterteilt ist:
1 # Klasse genericParameter0OfThisClass =
2 # (Klasse)
3 # ((ParameterizedType)
4 # getClass ()
5 # .getGenericSuperclass ())
6 # .getActualTypeArguments () [0];
Sei 'wir' die abstrakte Klasse mit generischen Typen, die diesen Code enthält. Lesen Sie dies grob von innen nach außen:
- Zeile 4 ruft die aktuelle Klasseninstanz der konkreten Klasse ab. Dies identifiziert den konkreten Typ unseres unmittelbaren Nachkommen.
- Zeile 5 erhält den Supertyp dieser Klasse als Typ. Das sind wir. Da wir ein parametrischer Typ sind, können wir uns sicher in ParameterizedType (Zeile 3) umwandeln. Der Schlüssel ist, dass Java, wenn es dieses Type-Objekt bestimmt, die im Kind vorhandenen Typinformationen verwendet, um Typinformationen unseren Typparametern in der neuen ParameterizedType-Instanz zuzuordnen. Jetzt können wir auf konkrete Typen für unsere Generika zugreifen.
- Zeile 6 ruft das Array von Typen ab, die unseren Generika zugeordnet sind, in der Reihenfolge, wie sie im Klassencode deklariert ist. In diesem Beispiel ziehen wir den ersten Parameter heraus. Dies kommt als Typ zurück.
- Zeile 2 wirft den endgültigen Typ, der an eine Klasse zurückgegeben wurde. Dies ist sicher, da wir wissen, welche Typen unsere generischen Typparameter annehmen können, und bestätigen können, dass es sich bei allen um Klassen handelt (ich bin mir nicht sicher, wie man in Java einen generischen Parameter ohne Klasseninstanz abrufen würde damit verbunden).
... und das war's auch schon. Wir übertragen also Typinformationen aus unserer eigenen konkreten Implementierung zurück in uns selbst und verwenden sie, um auf ein Klassenhandle zuzugreifen. Wir könnten getGenericSuperclass () verdoppeln und zwei Ebenen durchlaufen oder getGenericSuperclass () eliminieren und Werte für uns als konkreten Typ erhalten (Einschränkung: Ich habe diese Szenarien nicht getestet, sie sind noch nicht für mich aufgetaucht).
Es wird schwierig, wenn Ihre konkreten Kinder eine beliebige Anzahl von Sprüngen entfernt sind oder wenn Sie konkret und nicht endgültig sind, und besonders schwierig, wenn Sie erwarten, dass eines Ihrer (unterschiedlich tiefen) Kinder seine eigenen Generika hat. Normalerweise können Sie diese Überlegungen jedoch berücksichtigen, sodass Sie den größten Teil des Weges zurücklegen können.
Hoffe das hat jemandem geholfen! Ich erkenne, dass dieser Beitrag uralt ist. Ich werde diese Erklärung wahrscheinlich abschneiden und für andere Fragen aufbewahren.