Je voudrais accéder à Java champ privé lors de l'utilisation de Kotlin fonction d'extension.
Supposons que j'ai une classe JavaABC
. ABC
n'a qu'un seul champ privé mPrivateField
. Je voudrais écrire une fonction d'extension dans Kotlin qui utilise ce champ pour une raison quelconque.
public class ABC {
private int mPrivateField;
}
la fonction Kotlin serait:
private fun ABC.testExtFunc() {
val canIAccess = this.mPrivateField;
}
l'erreur que je reçois est:
Cannot access 'mPrivateField': It is private in 'ABC'
Une façon de se déplacer cette limitation?
Tout d'abord, vous devez obtenir un Field et l'activer peut être accessible dans Kotlin, par exemple:
val field = ABC::class.Java.getDeclaredField("mPrivateField")
field.isAccessible = true
Ensuite, vous pouvez lire la valeur du champ comme Int
par Field # getInt à partir de l'instance de la classe déclarante, par exemple:
val it: ABC = TODO()
val value = field.getInt(it)
Enfin, votre méthode d'extension est la suivante:
private inline fun ABC.testExtFunc():Int {
return javaClass.getDeclaredField("mPrivateField").let {
it.isAccessible = true
val value = it.getInt(this)
//todo
return@let value;
}
}
Ce n'est pas possible par conception. Les fonctions d'extension se résolvent essentiellement en fonctions statiques avec le récepteur comme premier paramètre. Ainsi, une fonction d'extension
fun String.foo() {
println(this)
}
compile quelque chose comme:
public static void foo(String $receiver) {
System.out.println($receiver);
}
Maintenant, il est clair que vous ne pouvez pas accéder au membre privé de $receiver
, puisqu'ils sont, eh bien, privés.
Si vous vraiment voulez accéder à ce membre, vous pouvez le faire en utilisant la réflexion, mais vous perdrez toutes les garanties.
Tout comme nhaarman m'a suggéré d'utiliser réflexion pour accéder au champ en question. Plus précisément, j'ai créé un getter qui utilise la réflexion en interne sur la classe mentionnée (c'est-à-dire ABC
)
Malheureusement, l'accès aux champs privés dans la fonction d'extension Kotlin n'est pas possible à partir du juillet 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
}
Étendre la réponse de holi-Java avec un type générique:
fun<T: Any> T.accessField(fieldName: String): Any? {
return javaClass.getDeclaredField(fieldName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
val field = <your_object_instance_with_private_field>
.accessField("<field_name>")
as <object_type_of_field_name>
Exemple:
class MyClass {
private lateinit var mObject: MyObject
}
val privateField = MyClass()
.accessField("mObject")
as MyObject