在 Kotlin 中使用不同类型的引用通过反射访问属性时出现问题

问题描述 投票:0回答:1

我尝试在复杂的场景(使用泛型等)中通过反射读取属性的值。但我总是因为这个错误而失败:

Type mismatch: inferred type is ReflectionTest.Person but Nothing was expected

所以我能够将其缩小到以下问题:

class ReflectionTest {
    
    data class Person(val firstname: String, val lastname: String)

    @Test
    fun b() {
        val person = Person("Donald", "Duck")

        val a = Person::class       
        val b = person::class     

        val personAfirstname = a.memberProperties.find { it.name == "firstname" }?.get(person) // this works fine
        val personBfirstname = b.memberProperties.find { it.name == "firstname" }?.get(person) // compiler error: Type mismatch: inferred type is ReflectionTest.Person but Nothing was expected
    }
}

有人可以解释一下,为什么编译器在最后一行需要

Nothing
以及如何解决这个问题?

在我的调查过程中,我遇到了 Error Kotlin:类型不匹配:推断类型是 T?但什么也没预料到。但即便如此,我也无法解决问题。

kotlin reflection
1个回答
0
投票

虽然

Person::class
的类型是
KClass<Person>
,但
person::class
的类型是
KClass<out Person>

TypeName::class
不同,它只能评估一件事 - 代表
KClass
TypeName
-
expression::class
可以评估不同的
KClass
实例,具体取决于
expression
的运行时类型。例如:

fun foo(x: Any) {
    println(x::class)
}

fun main() {
    foo(Any()) // prints Any
    foo(1) // prints Int
    foo("bar") // prints String
}

x::class
的类型不能是
KClass<Any>
(又名
Any::class
)。
x
在运行时可能是其他类的实例。它必须是
KClass<out Any>
,因为它可能会计算为
Int::class
(类型为
KClass<Int>
)或
String::class
(类型为
KClass<String>
)等。

在您的情况下,

Person
是一个数据类,因此无法继承它,因此
person
实际上不能是除了
Person
之外的任何对象的实例。 Kotlin 不够聪明,知道这一点,所以
person::class
的类型是
KClass<out Person>
,就像任何其他
expression::class
表达式一样。

因此,就 Kotlin 而言,

person::class
可能是
Person
的子类,因此在获取属性值时不能传递
Person
。毕竟,如果
find
找到仅在
Person
的子类中可用的属性怎么办? (当然,我们人类知道这不会发生。)

expression::class
类似于 Java 的
Object.getClass
方法。另请参阅 Why does getClass return a Class? 有关为什么
getClass
返回
Class<? extends T>
(类似于
KClass<out T>
)的讨论。

© www.soinside.com 2019 - 2024. All rights reserved.