Я хочу спробувати розбити відповідь від @DerMike, щоб пояснити:
По-перше, стирання типу не означає, що JDK усуває інформацію про тип під час виконання. Це метод, який дозволяє перевіряти тип компіляції та час сумісності типу співіснування на одній мові. Як випливає з цього блоку коду, JDK зберігає стерту інформацію про тип - вона просто не пов’язана з перевіреними кастрами та ін.
По-друге, це забезпечує загальну інформацію про тип для родового класу рівно на один рівень вгору по спадковості від конкретного типу, що перевіряється - тобто абстрактний батьківський клас із загальними параметрами типу може знайти конкретні типи, що відповідають його параметрам типу для конкретної реалізації себе що безпосередньо успадковує від цього. Якби цей клас був не абстрактним та інстанційним, або конкретна реалізація була знижена на два рівні, це не спрацювало (хоча трохи джимінгу може змусити його застосувати до будь-якої заздалегідь визначеної кількості рівнів понад один, або до найнижчого класу з параметрами загального типу X та ін.
У будь-якому випадку, на пояснення. Ось ще раз код, розділений на рядки для зручності посилання:
1 # Клас genericParameter0OfThisClass =
2 # (клас)
3 # ((ParameterizedType)
4 # getClass ()
5 # .getGenericSuperclass ())
6 # .getActualTypeArguments () [0];
Нехай «ми» - абстрактний клас із загальними типами, який містить цей код. Читаючи це приблизно зсередини:
- Рядок 4 отримує поточний екземпляр класу конкретного класу. Це визначає конкретний тип нашого безпосереднього нащадка.
- Рядок 5 отримує супертип типу класу як тип; це ми. Оскільки ми параметричного типу, ми можемо сміливо віднестись до ParameterizedType (рядок 3). Ключовим моментом є те, що коли Java визначає цей об'єкт Type, він використовує інформацію про тип, наявну у дочірніх даних, для асоціювання інформації типу з нашими параметрами типу в новому екземплярі ParameterizedType. Тож тепер ми можемо отримати доступ до конкретних типів для наших дженериків.
- Рядок 6 отримує масив типів, відображених у нашому дженеріку, у порядку, який задекларований у коді класу. Для цього прикладу витягуємо перший параметр. Це повертається як тип.
- Рядок 2 відкидає остаточний тип, повернений до класу. Це безпечно, тому що ми знаємо, які типи можуть приймати наші параметри загального типу і можемо підтвердити, що всі вони будуть класами (я не впевнений, як у Java можна було б отримати загальний параметр, у якого немає екземпляра Class власне, пов'язане з цим).
... і це майже все. Тож ми відштовхуємо інформацію про тип із власної конкретної реалізації назад до себе і використовуємо її для доступу до класу ручки. ми могли б подвоїти getGenericSuperclass () і пройти два рівні, або усунути getGenericSuperclass () і отримати значення для себе як конкретний тип (застереження: я не перевіряв ці сценарії, вони ще не підійшли для мене).
Це стає хитромудрим, якщо ваші конкретні діти відбирають довільну кількість хмелів, або якщо ви конкретні, а не остаточні, а особливо хитрі, якщо ви очікуєте, що хтось із ваших (мінливо глибоких) дітей матиме власні дженерики. Але зазвичай ти можеш розбиратися з цих міркувань, тож це дає тобі більшу частину шляху.
Сподіваюся, це комусь допомогло! Я визнаю, цей пост є давнім. Я, мабуть, оснащую це пояснення і зберігатиму його для інших питань.