Функция расширения Kotlin доступа к частному полю Java

Я хотел бы получить доступ к частному полю Java при использовании функции расширения Kotlin .

Предположим, что у меня есть класс Java ABC. 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'

Любой способ обойти это ограничение?

Ответ 1

Во- первых, вам нужно получить поле и включить его могут быть доступны в Котлин, например:

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

field.isAccessible = true

Затем вы можете прочитать значение поля как Int by Field # getInt из экземпляра объявленного класса, например:

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
        [email protected] value;
    }
}

Ответ 2

Это невозможно по дизайну. Функции расширения по существу разрешают статические функции с приемником в качестве первого параметра. Таким образом, функция расширения

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

компилируется примерно так:

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

Теперь ясно, что вы не можете получить доступ к частному члену $receiver, так как они, ну, частные.

Если вы действительно хотите получить доступ к этому члену, вы можете сделать это с помощью отражения, но вы потеряете все гарантии.

Ответ 3

Так же, как nhaarman предложил использовать отражение для доступа к соответствующему полю. В частности, я создал геттер, который использовал отражение внутри указанного класса (т.е. ABC)

К сожалению, доступ к закрытым полям в функции расширения Котлина невозможен с июля 2017 года.

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
}

Ответ 4

Расширение holi-java общего типа:

  1. Создать расширение
fun<T: Any> T.accessField(fieldName: String): Any? {
    return javaClass.getDeclaredField(fieldName).let { field ->
        field.isAccessible = true
        [email protected]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