Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用反射更改kotlin私有val?_Kotlin_Reflection_Kotlin Reflect - Fatal编程技术网

如何使用反射更改kotlin私有val?

如何使用反射更改kotlin私有val?,kotlin,reflection,kotlin-reflect,Kotlin,Reflection,Kotlin Reflect,我可以使用反射访问私有val值,如下所示 fun main() { val mainClass = MainClass() val f = MainClass::class.memberProperties.find { it.name == "info" } f?.let { it.isAccessible = true val w = it.get(mainClass) as String println(w)

我可以使用反射访问私有val值,如下所示

fun main() {
    val mainClass = MainClass()
    val f = MainClass::class.memberProperties.find { it.name == "info" }
    f?.let {
        it.isAccessible = true
        val w = it.get(mainClass) as String
        println(w)
    }
}


class MainClass {
    private val info: String = "Hello"
}
但是,如果我想更改
信息
,如何使用反射呢

答复 简而言之,在这种情况下,您必须使用Java反射API,下面是如何做到这一点:

fun main() {
    val mainClass = MainClass()
    val f = MainClass::class.java.getDeclaredField("info")
    f.isAccessible = true
    f.set(mainClass, "set from reflection")
    mainClass.printInfo() // Prints "set from reflection"
}

class MainClass {
    private val info: String = "Hello"
    fun printInfo() = println(info)
}
使用Java反射API的原因 由于没有为只读(
val
)属性生成setter代码,因此无法使用Kotlin反射API。所以要改变它,我们需要使用Java反射API,这是一种更低级的API。首先,我们使用工具->Kotlin->显示Kotlin字节码,查看生成的字节码是什么样子。然后我们看到:

// ================MainClass.class =================
// class version 50.0 (50)
// access flags 0x31
public final class MainClass {
  // access flags 0x12
  private final Ljava/lang/String; info = "Hello"
  // ...
i、 e
MainClass
Kotlin类中的
info
字段会导致编译器为带有
final String info
字段的常规
MainClass
Java类发出JVM代码。因此,为了改变它,我们可以使用Java反射API,如上面的代码所示

Kotlin反射API尝试 如果该字段为
private var
,则可以使用Kotlin反射API,如下所示:

f?.let {
    val mutableProp = it as KMutableProperty<*>
    it.isAccessible = true
    mutableProp.setter.call(mainClass, "set from Kotlin reflection")
    val w = it.get(mainClass) as String
    println(w)
}

由于没有为
val
字段生成setter代码,因此
info
属性的Kotlin反射API类型为
KProperty
,而不是
KMutableProperty

,我将尝试为您找到答案,但我不能保证我会成功。。同时,想知道你为什么要这样做是很有趣的?您可能知道,在运行时绕过编译时检查通常是个坏主意。只是想看看有没有办法。谢谢。这很有帮助。看看是否有其他人可以提供val解决方案。如果没有,那么这将是我的勾选答案。@Elye也许现在是时候将这个答案标记为已接受了?;)
Exception in thread "main" java.lang.ClassCastException: class kotlin.reflect.jvm.internal.KProperty1Impl cannot be cast to class kotlin.reflect.KMutableProperty (kotlin.reflect.jvm.internal.KProperty1Impl and kotlin.reflect.KMutableProperty are in unnamed module of loader 'app')
    at MainKt.main(main.kt:107)
    at MainKt.main(main.kt)