Стирание типов на JVM
Вопрос
Что такое стирание типов, какие проблемы оно создаёт и как их решают в Kotlin?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Аргументы дженериков существуют только при компиляции
Нельзя `is List<String>`, `T::class`, создать `T()`
Конфликт сигнатур перегрузок, решается `@JvmName`
`reified` в inline-функциях
Явная передача `KClass` или `typeOf`
Что могут спросить следом
- Почему Gson требует TypeToken для
List<User>? - Работает ли reified из Java?
Разбор
На JVM дженерики реализованы стиранием: при компиляции аргументы типов проверяются, а в байткоде остаётся сырой тип, List<String> и List<Int> в рантайме неотличимы. Из-за этого нельзя написать x is List<String>, нельзя получить T::class внутри обычной функции и нельзя создать экземпляр T. Две перегрузки, отличающиеся только аргументом дженерика, конфликтуют в байткоде, это лечится @JvmName. В Kotlin главный инструмент обхода это inline fun <reified T>: функция встраивается в место вызова, где тип известен, поэтому работают T::class.java и is T. Так сделаны filterIsInstance, decodeFromString и by viewModels. Иначе тип передают явно через KClass<T> или typeOf<T>(), а библиотеки вроде Gson используют TypeToken, потому что им нужен полный тип с аргументами.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «Дженерики и вариантность»
- Проверка is List<String> и стирание типов
- Вариантность в объявлении и в месте использования
- Как обойти стирание типов
- Инвариантность, out и in
- Контравариантность in T
- Конфликт перегрузок из-за стирания
- Почему List<String> можно передать как List<Any>
- Дженерики Kotlin и Java