Android泛型报错:无法将T用作具体化类型参数的原因咨询
泛型reified参数报错问题解答
问题描述
本人泛型使用经验尚浅,现咨询以下问题:为何无法告知getResult函数,bundle.getParcelableCompat<T>(BUNDLE_KEY)的返回值类型为继承自Parcelable的T?运行代码时出现错误提示:
Cannot use 'T' as reified type parameter. Use a class instead.
我认为已传递实现需求所需的全部信息,请问遗漏了什么?附相关代码:
class MyClass<T : Parcelable>( private val key: String, private val clazz: Class<T> ) { private inline fun <reified T : Parcelable> Bundle.getParcelableCompat(name: String): T? = if (Build.VERSION.SDK_INT >= 33) { this.getParcelable(name, T::class.java) } else { this.getParcelable(name) } fun getResult(fragment: Fragment, result: (T) -> Unit) = with(fragment) { setFragmentResultListener(requestKey) { request, bundle -> if (request == requestKey) { val parcelableCompat: T? = bundle.getParcelableCompat<T>(BUNDLE_KEY) parcelableCompat?.let(result) } } } }
问题根源
核心问题出在:类的泛型T没法直接当reified类型参数传给内联函数。
reified要求编译器在编译阶段就能明确知道具体类型,但类的泛型T是运行时才确定具体类型的,编译期拿不到它的类型信息,所以编译器才会报错让你用Class实例代替。
解决办法
你其实已经在类的构造方法里传了clazz: Class<T>这个参数,完全可以用它来改造getParcelableCompat函数,去掉reified限制就行:
修改后的完整代码
class MyClass<T : Parcelable>( private val key: String, private val clazz: Class<T> ) { private fun Bundle.getParcelableCompat(name: String): T? = if (Build.VERSION.SDK_INT >= 33) { this.getParcelable(name, clazz) } else { @Suppress("DEPRECATION") this.getParcelable(name) as T? } fun getResult(fragment: Fragment, result: (T) -> Unit) = with(fragment) { setFragmentResultListener(key) { request, bundle -> if (request == key) { val parcelableCompat: T? = bundle.getParcelableCompat(BUNDLE_KEY) parcelableCompat?.let(result) } } } }
关键改动点
- 删掉
getParcelableCompat的reified泛型声明,直接用类的泛型T做返回类型 - API 33+的分支里,直接用构造方法传入的
clazz代替原来的T::class.java - 低版本分支加
@Suppress("DEPRECATION")消除弃用警告,同时做安全类型转换
这样既用上了你已经传递的Class<T>信息,又绕开了reified参数的限制,还保持了多版本兼容性。
内容的提问来源于stack exchange,提问作者deadfish
相关产品推荐
相关产品推荐

