面试题答案
一键面试类型擦除在Kotlin泛型类和泛型函数中的表现
- 泛型类
- 在Kotlin中,编译时泛型类型参数会被擦除,只保留其边界类型(如果有)。例如,对于泛型类
class Box<T>(val value: T)
,编译后字节码中T
会被擦除。如果没有为T
指定上界,它会被擦除为Any?
。假设定义Box<String>
和Box<Int>
,编译后在字节码层面,它们本质上是同一个类,只是使用的方式在Java和Kotlin语法层面有区别。 - 示例代码:
class Box<T>(val value: T) fun main() { val stringBox = Box("Hello") val intBox = Box(10) // 这里stringBox和intBox编译后在字节码层面,Box类的结构是一样的,只是存储的值类型不同 }
- 在Kotlin中,编译时泛型类型参数会被擦除,只保留其边界类型(如果有)。例如,对于泛型类
- 泛型函数
- 泛型函数中的类型参数同样在编译时被擦除。例如
fun <T> printValue(value: T)
,编译后T
会被擦除。如果没有指定上界,也会被擦除为Any?
。函数调用时,不同实际类型参数的调用,在字节码层面本质上也是同一个函数的不同调用方式。 - 示例代码:
fun <T> printValue(value: T) { println(value) } fun main() { printValue("World") printValue(20) // 这里两个printValue调用,编译后在字节码层面,函数主体是一样的,只是传入的参数类型不同 }
- 泛型函数中的类型参数同样在编译时被擦除。例如
类型擦除可能带来的问题及解决办法
- 问题:在运行时无法获取确切的泛型类型信息。例如,不能在运行时直接检查一个
Box<String>
实例的泛型类型是String
。- 示例代码:
class Box<T>(val value: T) fun main() { val stringBox = Box("Test") // 以下代码不能直接获取stringBox的泛型类型是String // println(stringBox::class.typeParameters[0].type) // 这种写法会报错 }
- 解决办法:
- 使用
reified
关键字(仅适用于内联函数):- 内联函数中的
reified
类型参数可以在运行时获取类型信息。例如:
inline fun <reified T> printType() { println(T::class.simpleName) } fun main() { printType<String>() printType<Int>() }
- 内联函数中的
- 使用类型令牌(Type Token):通过传递一个表示类型的对象来获取类型信息。例如:
class Box<T>(val value: T, val typeToken: KClass<T>) { fun printType() { println(typeToken.simpleName) } } fun main() { val stringBox = Box("Hello", String::class) stringBox.printType() }
- 使用