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

时间:2017-07-16 17:49:53

标签: kotlin kotlin-extension kotlin-interop

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

假设我有一个 Java ABCABC只有一个私有字段mPrivateField。我想在Kotlin中编写一个扩展函数,无论出于何种原因使用该字段。

public class ABC {
    private int mPrivateField;

}

Kotlin 功能将是:

private fun ABC.testExtFunc() {
    val canIAccess = this.mPrivateField;
}

我得到的错误是:

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

绕过这种限制的任何方式?

5 个答案:

答案 0 :(得分:16)

首先,您需要获取Field并在Kotlin中启用可访问,例如:

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

field.isAccessible = true

然后,您可以从声明类的实例中将Int的字段值读取为val it: ABC = TODO() val value = field.getInt(it) ,例如:

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

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

modified:   submodule1 (new commits, modified content)
modified:   submodule2 (modified content)
modified:   submodule3 (modified content)

答案 1 :(得分:7)

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

fun String.foo() {
  println(this)
}

编译为:

public static void foo(String $receiver) {
  System.out.println($receiver);
}

现在可以清楚地看到您无法访问$receiver的私人成员,因为他们非常私密。

如果确实想要访问该成员,您可以使用反射进行访问,但是您将失去所有保证。

答案 2 :(得分:3)

正如 nhaarman 建议我使用反射来访问相关字段。具体来说,我创建了一个getter,它在所提到的类内部使用了反射(即ABC

2017年7月

开始,无法访问Kotlin扩展功能中的私人字段
fun ABC.testExtFunc() {
    val canIAccess = this.getmPrivateField()
}

fun ABC.getmPrivateField() : Int {
    val field = this.javaClass.declaredFields
            .toList().filter { it.name == "mPrivateField" }.first()
    field.isAccessible = true
    val value = field.get(this)
    return value as Int
}

答案 3 :(得分:1)

使用以下扩展功能获取私有变量

Stack

设置私有变量值获取变量

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

获取变量用途:

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)
    }
}

设置并获取变量用途:

val bool = <your_class_object>.getPrivateProperty("your_variable") as String

答案 4 :(得分:0)

用通用类型扩展 holi-java 的答案:

  1. 创建扩展名
fun<T: Any> T.accessField(fieldName: String): Any? {
    return this?.javaClass?.getDeclaredField(fieldName).let { field ->
        field?.isAccessible = true
        return@let field?.get(this)
    }
}

  1. 访问私有字段
val field = <your_object_instance_with_private_field>
                .accessField("<field_name>")
                    as <object_type_of_field_name>

示例:

class MyClass {

    private lateinit var mObject: MyObject

}

val privateField = MyClass()
                .accessField("mObject")
                    as MyObject