首页 文章

Kotlin的反思:未知的类型参数

提问于
浏览
1

我正在对Kotlin的反思进行一些实验 .

我试图通过其参数获得泛型类的反射对象 .

在Java中,那将是 ParameterizedType .

使用Java的反射API获取此类内容的方法有点复杂:创建泛型类的匿名子类,然后获取其超类型的第一个参数 .

这是一个例子:

@Suppress("unused") @PublishedApi
internal abstract class TypeReference<T> {}

inline fun <reified T> jGeneric() =
    ((object : TypeReference<T>() {}).javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]

当我 println(jGeneric<List<String?>>()) 时,它打印 java.util.List<? extends java.lang.String> ,这是合乎逻辑的,考虑到Kotlin的 List 使用声明站点 out 方差,并且Java类型没有可空性的概念 .

现在,我希望获得相同类型的结果,但使用Kotlin反射API(当然,它包含可空性信息) .

当然, List<String>::class 无法工作,因为它产生 KClass . 我正在寻找 KType .

但是,当我尝试这个:

inline fun <reified T> kGeneric() =
    (object : TypeReference<T>() {})::class.supertypes[0].arguments[0].type

当我 println(kGeneric<List<String?>>()) 时,会打印 [ERROR : Unknown type parameter 0] ,这很......很好,虎头蛇尾;)

我怎么能在Kotlin得到 KType 反映 List<String>

1 回答

  • 5

    要在Kotlin 1.1中创建 KType 实例,您有两个选择:

    • 要从 KClass 创建一个简单的非可空类型,其中该类不是通用的,或者您可以使用星形投影( * )替换其所有类型参数,请使用 starProjectedType 属性 . 例如,以下创建 KType 表示不可为空的类型 String
    val nonNullStringType = String::class.starProjectedType
    

    或者,以下创建 KType 表示不可为空的类型 List<*>

    val nonNullListOfSmth = List::class.starProjectedType
    
    • 对于更复杂的情况,请使用 createType 函数 . 它接受类,类型参数以及类型是否应该为空 . 类型参数是 KTypeProjection 的列表,它只是一个类型方差(in / out / none) . 例如,以下代码创建表示 List<String>KType 实例:
    val nonNullStringType = String::class.starProjectedType
    val projection = KTypeProjection.invariant(nonNullStringType)
    val listOfStrings = listClass.createType(listOf(projection))
    

    或者,以下创建类型 List<String>?

    val listOfStrings = listClass.createType(listOf(projection), nullable = true)
    

    starProjectedTypecreateType 都在包 kotlin.reflect.full 中定义 .

    We're planning引入了简单地从内联函数的reified类型参数获取 KType 实例的可能性,这有助于在某些情况下静态地知道所需类型,但是目前它可能没有大的开销 . 因此,在实施之前,请使用上面说明的声明 .

相关问题