Функция расширения 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 общего типа:
- Создать расширение
fun<T: Any> T.accessField(fieldName: String): Any? {
return javaClass.getDeclaredField(fieldName).let { field ->
field.isAccessible = true
[email protected]let field.get(this)
}
}
- Доступ к приватному полю
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