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)
starProjectedType
和 createType
都在包 kotlin.reflect.full
中定义。
We're planning 引入了简单地从内联函数的具体化类型参数中获取 KType
实例的可能性,这在某些情况下需要的类型是静态已知的,但目前它是如果没有大量开销,这是否可能还不完全清楚。因此,在实施之前,请使用上面解释的声明。
我正在运行对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)
starProjectedType
和 createType
都在包 kotlin.reflect.full
中定义。
We're planning 引入了简单地从内联函数的具体化类型参数中获取 KType
实例的可能性,这在某些情况下需要的类型是静态已知的,但目前它是如果没有大量开销,这是否可能还不完全清楚。因此,在实施之前,请使用上面解释的声明。