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

我正在对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> java.util.List<? extends java.lang.String> ,这是合乎逻辑的,考虑到Kotlin的List使用声明站点差异,并且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中得到一个反映List<String>KType

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

  • 要从KClass创建一个简单的非空类型,其中类不是泛型,或者可以用星型投影( * )替换其所有类型参数,请使用starProjectedType属性。 例如,下面的代码创建一个表示非空类型StringKType

     val nonNullStringType = String::class.starProjectedType 

    或者,下面的代码创建一个表示不可为空的类型List<*>KType

     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中定义。

我们打算引入一个简单的从一个内联函数的特定类型参数获取一个KType实例的可能性,这将有助于在某些情况下所需的类型是静态的,但是目前还不能完全清楚这是否可能,而没有大的开销。 因此,在实施之前,请使用上述说明。