使用 Kotlin 反射,如何设置 Kotlin 对象的成员属性?

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

我正在尝试使用反射来设置 Kotlin 对象的 val 属性。当我尝试下面的代码时,出现异常:

无法将静态最终 Foo 字段 Person.foo 设置为 Biz java.lang.IllegalAccessException:无法将静态最终 Foo 字段 Person.foo 设置为 Biz

interface Foo {
    fun hello(): String
}

class Bar: Foo {
    override fun hello(): String {
        return "Bar"
    }
}

class Biz: Foo {
    override fun hello(): String {
        return "Biz"
    }
}

object Person {
    val foo: Foo = Bar()
}

fun main() {
    val person = Person
    val property = person::class.memberProperties.first { it.name == "foo" }
    val javaField = property.javaField!!
    javaField.isAccessible = true
    javaField.set(person, Biz()) // exception happens here
    println(Person.foo.hello())
}

有没有办法让 Person.foo.hello() 通过 Kotlin 或 Java 反射 API 返回“Biz”而不是“Bar”?

谢谢!

kotlin reflection
2个回答
0
投票

不幸的是,

val
中的
object
的支持字段被编译为类文件中的
static final
字段。这些字段“非常”难以改变。请参阅 this post 了解在 Java 中执行此操作的方法。对于每个 JVM 版本,这变得越来越难,而且我还没有找到适用于 Java 22 的解决方案。 这里是来自链接问题的

这个答案

的 Kotlin 翻译。这在 Java 16 之前都有效。 fun main() { val person = Person val property = person::class.memberProperties.first { it.name == "foo" } val javaField = property.javaField!! javaField.setFieldAccessible() javaField.set(person, Biz()) // or javaField.set(null, Biz()), since the field is static println(Person.foo.hello()) } fun Field.setFieldAccessible() { setAccessible(true) val lookup = MethodHandles.privateLookupIn(Field::class.java, MethodHandles.lookup()) val modifiersHandle = lookup.findVarHandle(Field::class.java, "modifiers", Int::class.javaPrimitiveType) val mods: Int = modifiers if (Modifier.isFinal(mods)) { modifiersHandle.set(this, mods and Modifier.FINAL.inv()) } }



0
投票

fun main() { val unsafeField = Unsafe::class.java.getDeclaredField("theUnsafe") unsafeField.isAccessible = true val unsafe = unsafeField.get(null) as Unsafe val field = Person.javaClass.getDeclaredField("foo") // <-- FIELD WE WANT TO CHANGE val base = unsafe.staticFieldBase(field) val offset = unsafe.staticFieldOffset(field) unsafe.putObject(base, offset, Biz()) // <-- REPLACE println(Person.foo.hello()) }

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