Ответ вслух Middle Дженерики и вариантность обновлено

Стирание типов на JVM

Вопрос

Что такое стирание типов, какие проблемы оно создаёт и как их решают в Kotlin?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

На JVM дженерики реализованы стиранием: при компиляции аргументы типов проверяются, а в байткоде остаётся сырой тип, List<String и List<Int в рантайме неотличимы. Из-за этого нельзя написать x is List<String, нельзя получить T::class внутри обычной функции и нельзя создать экземпляр T.

Что должно прозвучать в ответе

  • Аргументы дженериков существуют только при компиляции

  • Нельзя `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 ошибок.