我正在玩反射,我遇到了这个问题。通过::class
语法使用绑定类引用时,我得到一个协变 KClass 类型:
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
正如我从文档中了解到的那样,这将返回对象的确切类型,以防它是 的子类型的实例T
,因此是方差修饰符。但是,这会阻止检索T
类中声明的属性并获取它们的值(这是我想要做的)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
我发现一个解决方案是javaClass.kotlin
在对象引用上使用扩展函数来获取不变类型:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
这样,我既可以在运行时获得确切的类型,也可以使用该类型。
有趣的是,如果我使用超类型而不是泛型,使用后一种方法我仍然可以访问正确的类型,而无需变化:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == Derived::class)
}
}
fun main(args: Array<String>) {
val derived = Derived()
foo(derived) // prints 'true'
}
如果我猜对了,::class
就等于调用 java getClass
,它返回一个带有通配符的变体类型,javaClass
而是一个getClass
带有特定类型的强制转换。尽管如此,我还是不明白为什么我需要一个协变 KClass,因为它限制我只生成类型,因为还有其他方法可以在运行时访问确切的类并自由使用它,我想知道更多immediate::class
应该按设计返回一个不变的类型。