kotlin - 如何使用反射更改 kotlin 私有(private)验证?

标签 kotlin reflection kotlin-reflect

我可以使用反射访问私有(private) 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"
}

但是如果我想改变info ,我怎么能用反射来做呢?

最佳答案

回答

简而言之,在这种情况下,您必须使用 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 的原因

不可能使用 Kotlin 反射 API,因为不会为只读 ( val ) 属性生成 setter 代码。所以要改变它,我们需要使用更底层的Java反射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"
  // ...

info MainClass 中的字段Kotlin 类导致编译器为常规 MainClass 发出 JVM 代码带有 final String info 的 Java 类 field 。因此,要更改它,我们可以使用 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)
}

但是如果你用 private val 试试这个你会得到以下异常
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)

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

关于kotlin - 如何使用反射更改 kotlin 私有(private)验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58360868/

相关文章:

android - 如何在 Exoplayer 视频中显示缩略图?

java - 在 Android 上使用 SQLDelight JVM 驱动程序

android - 如何在jetpack compose中的特定位置绘制图像

Scala反射派生包名

reflection - memberProperty returnType 父类(super class)的类型检查失败

android - 如何从构造函数获取参数?

Java匿名子类和常规(非匿名)子类的区别

c# - 根据属性名称数组创建对象的子集

kotlin - Kotlin反射(reflection):如何知道Kotlin类是否已使用 “internal”能见度修饰符标记

android - Kotlin 默认构造函数中的两种附加类型?