You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin反射中不同类引用访问属性报错:期望Nothing却传入Person

反射读取属性报类型不匹配的原因及解决方法

原因分析

  • Person::class获取的是类的静态KClass实例,类型为KClass<Person>,无协变修饰符,对应的memberProperties返回Collection<KProperty1<Person, *>>,调用get(person)时参数类型完全匹配。
  • person::class获取的是实例的运行时KClass,由于Kotlin的类型安全机制,其类型为KClass<out Person>(协变类型)——编译器无法确定person是否是Person子类的实例,因此用out标记该类型只能用于读取。
  • KProperty1的定义为interface KProperty1<in T, out V>,其中第一个类型参数T是逆变的(in修饰)。当T为out Person时,逆变参数的合法输入类型被限制为Nothing(协变类型无法作为逆变参数的输入,编译器找不到符合要求的类型,只能退化为Nothing),这就导致调用get(person)时出现“期望Nothing,但传入了Person”的类型不匹配错误。

解决方案

方法1:强转KClass类型

将协变的KClass<out Person>强转为KClass<Person>,消除类型限制:

@Suppress("UNCHECKED_CAST")
val b = person::class as KClass<Person>
val personBfirstname = b.memberProperties.find { it.name == "firstname" }?.get(person)

添加@Suppress("UNCHECKED_CAST")可消除未检查转换警告,若确定person的实际类型就是Person而非子类,该方式安全可靠。

方法2:通过Java类转换为KClass

利用实例的Java类再转回Kotlin KClass,直接得到KClass<Person>:

val b = person.javaClass.kotlin
val personBfirstname = b.memberProperties.find { it.name == "firstname" }?.get(person)

此方式无需强转,适合明确实例类型的场景。

方法3:强转属性类型

若不想修改b的类型,可对找到的属性进行强转:

val personBfirstname = (b.memberProperties.find { it.name == "firstname" } as KProperty1<Person, *>?)?.get(person)

内容的提问来源于stack exchange,提问作者Mat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:52:44