如何获得Kotlin中实际泛型参数的实际类型参数?
使用指定的类型参数 ,可以编写一个内联函数,它可以在运行时通过反射来处理类型参数:
inline fun <reified T: Any> f() { val clazz = T::class // ... }
但是当用一个本身是一个泛型类的参数调用f
时,似乎没有办法通过T::class
获得它的实际类型参数:
f<List<Integer>>() // T::class is just kotlin.collections.List
有没有办法通过反射来获得实际的泛化类型的类型参数?
由于类型擦除 ,实际泛型参数不能通过泛型类的T::class
令牌获得。 类的不同对象必须具有相同的类标记,这就是为什么它不能包含实际的泛型参数。
但是有一个称为超级类型标记的技术,当编译时已知类型时,它可以给出实际类型的参数(因为内联而在Kotlin中实现泛化的泛型)。
诀窍是编译器保留了从泛型类派生的非泛型类的实际类型参数(它的所有实例都有相同的参数, 这里有很好的解释)。 它们可以通过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模块将其用于通用泛型。
之后,在具有泛化泛型的内联函数中, TypeReference
需要被子类化( 对象表达式将会去),然后可以使用它的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>