Kotlin 的反思:未知类型参数

Kotlin's reflection : Unknown type parameter

我正在运行对Kotlin的反射进行一些实验

我正在尝试获取通用 class 及其参数的反射对象。

在 Java 中,那将是 ParameterizedType

使用 Java 的反射 API 得到这样的东西的方法有点复杂:创建一个泛型 class 的匿名子 class,然后获取它的超类型第一个参数。

这是一个例子:

@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 中得到一个反映 List<String>KType

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

  • KClass 创建一个简单的不可空类型,其中 class 不是通用的,或者您可以用星形投影替换它的所有类型参数 ( *),使用starProjectedType 属性。例如,下面创建一个 KType 表示一个不可为 null 的类型 String:

    val nonNullStringType = String::class.starProjectedType
    

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

    val nonNullListOfSmth = List::class.starProjectedType
    
  • 对于更复杂的情况,请使用 createType 函数。它接受 class、类型参数以及类型是否可以为空。类型参数是 KTypeProjection 的列表,它只是一个类型 + 变体 (in/out/none)。例如,以下代码创建一个 KType 实例,表示 List<String>:

    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 引入了简单地从内联函数的具体化类型参数中获取 KType 实例的可能性,这在某些情况下需要的类型是静态已知的,但目前它是如果没有大量开销,这是否可能还不完全清楚。因此,在实施之前,请使用上面解释的声明。