Type Erasure
In this page:
Generic Type Information Is Erased
Once compiled, the JVM no longer distinguishes between a List<String> and a List<Int> -- both are simply represented as a plain List at runtime, which is what 'type erasure' means.
Example: Generic Type Information Is Erased
fun main() {
val strings: List<Any> = listOf("a", "b")
val numbers: List<Any> = listOf(1, 2)
println("Same runtime class: ${strings::class == numbers::class}")
}
Login to try C/C++/Java/PHP code in the editor
Why You Cannot Check is List<String>
Because the element type is erased, Kotlin does not allow checking is List<String> directly -- only whether something is a List at all, using a star projection like is List<*>.
Example: Why You Cannot Check is List<String>
fun describe(value: Any) {
if (value is List<*>) {
println("It is some kind of List with ${value.size} elements")
}
}
fun main() {
describe(listOf(1, 2, 3))
describe(listOf("a", "b"))
}
Login to try C/C++/Java/PHP code in the editor
Working Around Erasure with reified
Because plain generic functions cannot see the real type at runtime, the reified keyword on an inline function's type parameter is the standard workaround when a runtime type check is genuinely needed.
Example: Working Around Erasure with reified
inline fun <reified T> countOfType(items: List<Any>): Int = items.count { it is T }
fun main() {
val mixed = listOf(1, "a", 2, "b", 3)
println("Number of Strings: ${countOfType<String>(mixed)}")
}
Login to try C/C++/Java/PHP code in the editor
Arrays Are Not Erased
Unlike generic collections, arrays in Kotlin (backed by JVM arrays) retain their component type information at runtime, so is Array<String>-style checks behave differently from generic collections.
Example: Arrays Are Not Erased
fun main() {
val stringArray: Array<String> = arrayOf("a", "b")
println("Array component type: ${stringArray.javaClass.componentType}")
}
Login to try C/C++/Java/PHP code in the editor
- Trying to check
if (list is List<String>), which the compiler rejects since the element type is erased and cannot be checked at runtime. - Assuming two
List<Int>andList<String>are different runtime classes; at runtime they are both simply the sameListclass. - Forgetting that arrays are an exception -- unlike generic collections, arrays retain their element type information at runtime (reified natively by the JVM).
- At runtime, generic type parameters are erased -- a
List<String>and aList<Int>are both justListonce compiled. - You cannot check
is List<String>directly; only an unchecked cast or a star-projected check likeis List<*>is allowed. - Type erasure is a JVM-wide limitation, not specific to Kotlin, and it's why
reifiedtype parameters (withinline) exist as a workaround. - Arrays are an exception to erasure -- their component type is preserved by the JVM at runtime.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: