类型擦除与实化类型参数(reified)
1. 类型擦除的概念
在 Java 和 Kotlin 的泛型中,类型擦除(Type Erasure) 是指泛型类型信息在编译后会被擦除,运行时无法直接获取泛型的实际类型参数。例如:
fun <T> checkType(item: T) {
// 编译错误:无法直接获取 T 的实际类型
// println(T::class.java)
}
2. 类型擦除的限制
由于类型擦除,以下操作无法直接实现:
- 运行时检查泛型类型(如
item is T) - 获取泛型类的具体类型参数(如
T::class) - 基于类型参数创建实例(如
T())
3. 实化类型参数(reified)
Kotlin 通过 reified 关键字解决部分类型擦除问题,但仅适用于内联函数(inline)。实化类型参数允许在函数体内访问类型信息:
inline fun <reified T> checkType(item: Any) {
if (item is T) { // 可检查类型
println("Item is of type ${T::class.simpleName}")
}
}
// 使用示例
checkType<String>("Kotlin") // 输出: "Item is of type String"
关键特性:
- 必须与
inline函数结合使用(编译器会将具体类型替换到调用处) - 支持
T::class获取KClass对象 - 允许类型检查(
is T)和类型转换(as T)
4. 实际应用场景
案例1:简化 Gson 解析
inline fun <reified T> fromJson(json: String): T {
return Gson().fromJson(json, T::class.java)
}
// 直接获取具体类型
val user = fromJson<User>("""{"name": "Alice"}""")
案例2:依赖注入
inline fun <reified T> inject(): T {
return ServiceLocator.resolve(T::class)
}
val service = inject<AuthService>()
5. 注意事项
- 局限性:
reified只能用于内联函数,无法用于类或属性 - 性能:内联会导致代码膨胀,但通常影响可忽略
- Java 互操作:Java 代码无法调用带
reified参数的 Kotlin 函数
6. 替代方案
当无法使用 reified 时,可通过传递 KClass 参数实现类似功能:
fun <T : Any> parseJson(json: String, type: KClass<T>): T {
return Gson().fromJson(json, type.java)
}
提示:优先使用
reified简化代码,但在需要动态类型或非内联场景时选择传统方式。
