Je veux essayer de décomposer la réponse de @DerMike pour expliquer:
Premièrement, l'effacement de type ne signifie pas que le JDK élimine les informations de type au moment de l'exécution. C'est une méthode pour permettre à la vérification de type à la compilation et à la compatibilité des types à l'exécution de coexister dans le même langage. Comme ce bloc de code l'implique, le JDK conserve les informations de type effacées - elles ne sont tout simplement pas associées aux transtypages vérifiés et autres.
Deuxièmement, cela fournit des informations de type générique à une classe générique exactement un niveau au-dessus de la hiérarchie à partir du type concret en cours de vérification - c'est-à-dire qu'une classe parent abstraite avec des paramètres de type générique peut trouver les types concrets correspondant à ses paramètres de type pour une implémentation concrète d'elle-même qui en hérite directement . Si cette classe était non abstraite et instanciée, ou si l'implémentation concrète était de deux niveaux plus bas, cela ne fonctionnerait pas (bien qu'un peu de jimmying puisse la faire appliquer à n'importe quel nombre prédéterminé de niveaux au-delà d'un, ou jusqu'à la classe la plus basse avec X paramètres de type générique, et cetera).
Quoi qu'il en soit, à l'explication. Voici à nouveau le code, séparé en lignes pour plus de facilité:
1 # Classe genericParameter0OfThisClass =
2 # (classe)
3 # ((ParameterizedType)
4 # getClass ()
5 # .getGenericSuperclass ())
6 # .getActualTypeArguments () [0];
Soit «nous» la classe abstraite avec des types génériques qui contient ce code. Lire ceci à peu près à l'envers:
- La ligne 4 obtient l'instance de classe de la classe concrète actuelle. Cela identifie le type concret de notre descendant immédiat.
- La ligne 5 obtient le supertype de cette classe comme Type; c'est nous. Puisque nous sommes un type paramétrique, nous pouvons nous convertir en toute sécurité en ParameterizedType (ligne 3). La clé est que lorsque Java détermine cet objet Type, il utilise les informations de type présentes dans l'enfant pour associer les informations de type à nos paramètres de type dans la nouvelle instance ParameterizedType. Alors maintenant, nous pouvons accéder à des types concrets pour nos génériques.
- La ligne 6 récupère le tableau des types mappés dans nos génériques, dans l'ordre déclaré dans le code de la classe. Pour cet exemple, nous retirons le premier paramètre. Cela revient en tant que type.
- La ligne 2 lance le type final retourné à une classe. C'est sûr parce que nous savons quels types nos paramètres de type générique sont capables de prendre et pouvons confirmer qu'ils seront tous des classes (je ne sais pas comment en Java on pourrait obtenir un paramètre générique qui n'a pas d'instance de classe associé, en fait).
...Et c'est à peu près tout. Nous renvoyons donc les informations de type de notre propre implémentation concrète en nous-mêmes, et les utilisons pour accéder à un handle de classe. nous pourrions doubler getGenericSuperclass () et passer à deux niveaux, ou éliminer getGenericSuperclass () et obtenir des valeurs pour nous-mêmes en tant que type concret (mise en garde: je n'ai pas testé ces scénarios, ils ne sont pas encore venus pour moi).
Cela devient délicat si vos enfants concrets sont à un nombre arbitraire de sauts, ou si vous êtes concret et non définitif, et surtout si vous vous attendez à ce que l'un de vos enfants (de profondeur variable) ait ses propres génériques. Mais vous pouvez généralement concevoir en fonction de ces considérations, ce qui vous permet de faire la plupart du temps.
J'espère que cela a aidé quelqu'un! Je reconnais que cet article est ancien. Je vais probablement couper cette explication et la garder pour d'autres questions.