reified
Kotlin 中的 「泛型透视镜」 ,配合 inline
函数,让泛型在运行时保留类型信息,使开发者不再被类型擦除蒙蔽双眼。
一、样例
1、类型擦除的困境 (Java泛型本质)
kotlin
// 普通泛型函数
fun <T> checkType(obj: Any) {
if (obj is T) { // 编译错误:Cannot check for instance of erased type: T
println("类型匹配")
}
}
2、Kotlin解决方案:reified + inline
kotlin
inline fun <reified T> checkTypeReified(obj: Any) {
if (obj is T) { // 正常编译
println("${T::class.simpleName} 类型匹配")
} else {
println("预期类型: ${T::class.simpleName}, 实际类型: ${obj::class.simpleName}")
}
}
// 使用示例
checkTypeReified<String>(123) // 输出:预期类型: String, 实际类型: Int
reified
让泛型 T 在运行时保留类型信息 ,从而支持is T
这样的操作。
二、工作原理拆解
1、inline函数展开机制
kotlin
// 编译器会将内联函数展开为实际调用处的代码
val obj = 123
if (obj is String) { // T被替换为具体类型
println("String 类型匹配")
} else {
println("预期类型: String, 实际类型: ${obj::class.simpleName}")
}
2、reified类型保留原理
阶段 | 普通泛型 | reified泛型 |
---|---|---|
编译前代码 | <T> checkType(obj) |
<reified T> check() |
字节码层面 | 类型擦除为Object | 保留具体类型信息 |
运行时类型检查 | 无法执行obj is T |
可执行类型检查 |
三、经典应用场景
1、类型安全解析
kotlin
inline fun <reified T> Gson.fromJson(json: String): T {
return fromJson(json, T::class.java)
}
// 使用示例
val user = gson.fromJson<User>(jsonString) // 自动推导类型
2、依赖注入容器
kotlin
inline fun <reified T> koinGet(): T {
return get(T::class.java)
}
// 获取ViewModel无需传参
val vm: MainViewModel by viewModel() // 内部使用reified
3、反射工厂模式
kotlin
inline fun <reified T> createInstance(): T {
return T::class.java.getDeclaredConstructor().newInstance()
}
// 创建任意无参构造对象
val service = createInstance<HttpService>()
四、Java为何无法实现?
1、语言设计差异
- Java泛型通过类型擦除实现,运行时无类型信息
- 没有内联函数机制,无法进行代码展开
- 缺乏
reified
关键字支持类型保留
2、字节码层面限制
java
// Java泛型方法编译后
public <T> void checkType(Object obj) {
// T被擦除为Object
if (obj instanceof T) { // 编译错误
}
}
五、性能优化建议
1、谨慎使用场景
- 适合小型工具函数(<20行)
- 避免在循环中高频调用
2、替代方案对比
方案 | 优点 | 缺点 |
---|---|---|
reified + inline | 类型安全,代码简洁 | 增大字节码体积 |
手动传递Class对象 | 性能稳定 | 代码冗余 |
反射API | 灵活性高 | 性能损耗,类型不安全 |
六、高级组合技巧
1、多reified参数支持
kotlin
inline fun <reified T, reified R> Pair<*, *>.convertPair(): Pair<T, R> {
return first as T to second as R
}
// 使用示例
val p = Pair(1, "2").convertPair<Int, String>()
2、跨inline函数类型传递
kotlin
inline fun <reified T> logger(): Logger {
return LoggerFactory.getLogger(T::class.java)
}
// 获取类专属日志器
val log = logger<MainActivity>()
七、实现原理深度解析
1、编译器处理流程
- 识别
reified
标记的类型参数 - 生成携带类型信息的隐藏参数
- 在内联展开时替换具体类型
2、字节码层面验证
java
// 反编译后的Java代码
public static final void checkTypeReified(Object obj) {
Class tClass = T.class; // 实际类型直接替换
if (tClass.isInstance(obj)) {
System.out.println("类型匹配");
}
}
该机制使Kotlin在保持JVM兼容性的同时,突破了Java泛型的类型擦除限制,为开发者提供了更强大的类型操作能力。