【问题标题】:How to get actual type arguments of a reified generic parameter in Kotlin?如何在 Kotlin 中获取具体泛型参数的实际类型参数?
【发布时间】:2016-07-15 04:18:09
【问题描述】:

使用reified type parameters,可以编写一个内联函数,在运行时通过反射来处理类型参数:

inline fun <reified T: Any> f() {
    val clazz = T::class
    // ...
}

但是当f被一个本身是泛型类的参数调用时,似乎没有办法通过T::class获取它的实际类型参数:

f<List<Integer>>() // T::class is just kotlin.collections.List

有没有办法通过反射获得具体泛型的实际类型参数?

【问题讨论】:

  • 用所需的接口替换Any,并使用接口:)

标签: generics reflection kotlin


【解决方案1】:

由于type erasure,无法通过泛型类的T::class 令牌获取实际的泛型参数。一个类的不同对象必须具有相同的类标记,这就是它不能包含实际泛型参数的原因。

但是有一种叫做 super type tokens 的技术可以在编译时知道类型的情况下给出实际的类型参数(由于内联,Kotlin 中的具体泛型也是如此)。


编辑:从 Kotlin 1.3.50 开始,不再需要遵循下面描述的技术来获取具体类型参数的类型信息。相反,您可以在具体类型参数上使用typeOf&lt;T&gt;()


诀窍在于编译器保留从泛型类派生的非泛型类的实际类型参数(它的所有实例都将具有相同的参数,很好的解释here)。它们可通过Class&lt;*&gt; 实例的clazz.genericSuperClass.actualTypeArguments 访问。

鉴于所有这些,您可以编写一个这样的 util 类:

abstract class TypeReference<T> : Comparable<TypeReference<T>> {
    val type: Type = 
        (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]

    override fun compareTo(other: TypeReference<T>) = 0
}

在使用相同方法的Jackson TypeReference 中进行了解释。 Jackson Kotlin 模块 uses it 在具体泛型上。

之后,在具有具体泛型的内联函数中,TypeReference 需要被子类化(object expression 会去),然后它的type 才能被使用。

例子:

inline fun <reified T: Any> printGenerics() {
    val type = object : TypeReference<T>() {}.type
    if (type is ParameterizedType)
        type.actualTypeArguments.forEach { println(it.typeName) }
}

printGenerics&lt;HashMap&lt;Int, List&lt;String&gt;&gt;&gt;()

java.lang.Integer
java.util.List<? extends java.lang.String>

【讨论】:

  • 这只适用于 Kotlin/JVM,有没有办法让它在 Kotlin/common 中适用于多平台项目?
  • 我觉得我看到了 stdlib(或者可能是反射库)直接支持类型标记的 YouTrack 问题,但我现在找不到。
  • @mkobit 这个我相信:youtrack.jetbrains.com/issue/KT-28230
【解决方案2】:

如果您已经在项目中使用 gson 库(例如 json 解析)。它为此提供了一个类。 com.google.gson.reflect.TypeToken()。 所以你可以使用类似的东西,

 f(object : TypeToken<List<Integer>>() {}.type)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 2013-09-13
    • 2018-07-26
    相关资源
    最近更新 更多