3

我正在对 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]

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

现在,我想使用 Kotlin 反射 API(当然,它包含可空性信息)来实现同样的结果。

当然,List<String>::class不能工作,因为它会产生一个KClass. 我正在寻找一个KType.

但是,当我尝试这个时:

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

当 I 时println(kGeneric<List<String?>>()),它会打印出来[ERROR : Unknown type parameter 0],这非常......好吧,虎头蛇尾;)

在 Kotlin 中,我怎样才能得到一个KType反射List<String>

4

1 回答 1

10

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

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

    val nonNullStringType = String::class.starProjectedType
    

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

    val nonNullListOfSmth = List::class.starProjectedType
    
  • 对于更复杂的情况,请使用该createType功能。它接受类、类型参数以及类型是否应该为空。类型参数是一个KTypeProjection简单的类型 + 方差(输入/输出/无)的列表。例如,以下代码创建一个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都在 package 中定义kotlin.reflect.full

我们计划引入KType简单地从内联函数的具体类型参数获取实例的可能性,这在某些需要的类型是静态已知的情况下会有所帮助,但是目前尚不完全清楚这是否可能在没有重大开销的情况下实现。因此,在实现之前,请使用上面解释的声明。

于 2017-05-26T14:19:02.210 回答