由于type erasure,无法通过泛型类的T::class 令牌获取实际的泛型参数。一个类的不同对象必须具有相同的类标记,这就是它不能包含实际泛型参数的原因。
但是有一种叫做 super type tokens 的技术可以在编译时知道类型的情况下给出实际的类型参数(由于内联,Kotlin 中的具体泛型也是如此)。
编辑:从 Kotlin 1.3.50 开始,不再需要遵循下面描述的技术来获取具体类型参数的类型信息。相反,您可以在具体类型参数上使用typeOf<T>()。
诀窍在于编译器保留从泛型类派生的非泛型类的实际类型参数(它的所有实例都将具有相同的参数,很好的解释here)。它们可通过Class<*> 实例的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<HashMap<Int, List<String>>>():
java.lang.Integer
java.util.List<? extends java.lang.String>