首页 文章

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

提问于
浏览
12

当使用Kotlin extension function 时,我'd like to access Java' s private field .

假设我有一个 JavaABC . ABC 只有一个私有字段 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'

那种限制的任何方式都是 getting around

3 回答

  • 7

    首先,您需要获取Field并在Kotlin中启用它可以是 accessible ,例如:

    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;
        }
    }
    
  • 2

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

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

    编译成如下:

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

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

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

  • 15

    正如 nhaarman 建议我使用 reflection 来访问相关字段 . 具体来说,我创建了一个在所提到的类内部使用反射的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
    }
    

相关问题