编程Android开发者

解释Kotlin中常规、内联和重ified泛型参数之间的区别。何时以及为何使用重ified,它消除了标准泛型方法的哪些限制?

用 Hintsage AI 助手通过面试

答案

在Kotlin中,泛型(generic参数)默认是类型擦除(type erasure)的:在运行时没有类型信息。这使得反射、类型转换和读取类型注解变得复杂。对于大多数任务,这是可接受的——常规泛型的工作方式类似于Java。

内联函数使用reified参数可以 "强制" 编译器在调用处 "插入" 具体类型,因此函数可以在运行时对类型执行操作(例如,进行检查,通过反射创建新实例等)。但是,reified只能应用于inline函数中的参数。

比较示例:

// 普通泛型 fun <T> printType(t: T) { println(t.javaClass) // 对List<Int>等将引发ClassCastException } // 使用reified inline fun <reified T> printType(t: T) { println(T::class.simpleName) } fun main() { printType(123) // 输出: Int printType("hello") // 输出: String }

应用实践: 通常用于类型检查、类型转换、反射、创建实例,在其他情况下无法获取类型。

陷阱问题

"重ified类型的函数可以不是内联的吗?"

  • 不,reified仅在内联函数中工作。否则不可能在编译时插入类型。

不正确的使用示例:

fun <reified T> failFunction() {} // 编译错误:reified类型参数只能用于内联函数

正确的:

inline fun <reified T> goodFunction() {}

由于不了解主题细节造成的实际错误示例


故事

在项目中需要通过带有泛型参数的函数通用地解析JSON字符串到任何类型。通过fun <T> parse(json: String): T的标准实现由于类型擦除不正确工作——无法提取Class<T>来解析集合和泛型模型。通过使用带重ified类型的内联,问题消失了。


故事

一位开发者尝试使用普通构造函数T()创建类型T的实例,而不使用内联和重ified。在编译时出现错误,因为类型信息已被擦除。通过重写为inline fun <reified T: Any>成功用语言的标准工具解决了所有问题。


故事

尝试在普通函数(没有内联)中使用重ified时——IDE给出了令人困惑的编译错误。开发者花了很长时间寻找原因,直到研究了文档并修复了函数,添加了内联。