Kotlin扩展函数访问Java私有字段

kos*_*cki 20 kotlin kotlin-extension kotlin-interop

我想在使用Kotlin 扩展功能时访问Java的私有字段.

假设我有一个JavaABC.ABC只有一个私人领域mPrivateField.我想在Kotlin中编写一个扩展函数,无论出于何种原因使用该字段.

public class ABC {
    private int mPrivateField;

}
Run Code Online (Sandbox Code Playgroud)

科特林功能是:

private fun ABC.testExtFunc() {
    val canIAccess = this.mPrivateField;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

Cannot access 'mPrivateField': It is private in 'ABC'

有什么办法解决这个限制?

hol*_*ava 26

首先,您需要获取一个Field并使其可以在Kotlin中访问,例如:

val field = ABC::class.java.getDeclaredField("mPrivateField")

field.isAccessible = true
Run Code Online (Sandbox Code Playgroud)

然后,您可以从声明类的实例中Int通过Field#getInt读取字段值,例如:

val it: ABC = TODO()

val value = field.getInt(it)
Run Code Online (Sandbox Code Playgroud)

最后,您的扩展方法如下所示:

private inline fun ABC.testExtFunc():Int {
    return javaClass.getDeclaredField("mPrivateField").let {
        it.isAccessible = true
        val value = it.getInt(this)
        //todo
        return@let value;
    }
}
Run Code Online (Sandbox Code Playgroud)


akh*_*707 14

使用以下扩展函数获取私有变量

fun <T : Any> T.getPrivateProperty(variableName: String): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        return@let field.get(this)
    }
}
Run Code Online (Sandbox Code Playgroud)

设置私有变量值获取变量

fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        field.set(this, data)
        return@let field.get(this)
    }
}
Run Code Online (Sandbox Code Playgroud)

获取变量使用:

val bool = <your_class_object>.getPrivateProperty("your_variable") as String
Run Code Online (Sandbox Code Playgroud)

设置和获取变量使用:

val bool = <your_class_object>.setAndReturnPrivateProperty("your_variable", true) as Boolean
val str = <your_class_object>.setAndReturnPrivateProperty("your_variable", "Hello") as String
Run Code Online (Sandbox Code Playgroud)


nha*_*man 8

这在设计上是不可能的.扩展函数基本上解析为静态函数,接收器作为其第一个参数.因此,扩展功能

fun String.foo() {
  println(this)
}
Run Code Online (Sandbox Code Playgroud)

编译成如下:

public static void foo(String $receiver) {
  System.out.println($receiver);
}
Run Code Online (Sandbox Code Playgroud)

现在很明显看到你无法访问私人成员$receiver,因为他们是私有的.

如果你真的想要访问该成员,你可以使用反射,但你将失去所有保证.

  • Android平台中的轶事提交:[另一天,访问另一个私人字段](https://android.googlesource.com/platform/libcore/+/81abb6fb7332dfe62ff596ffb250d8aec61895df%5E!/).在这种情况下,谷歌不得不回滚***私人***成员的重命名,因为Facebook通过反思访问它. (8认同)
  • 好吧,这不会发生.没有人应该鼓励这样的反思. (3认同)