Comment lire la valeur d'un champ privé à partir d'une autre classe en Java?
J'ai un mal conçus classe dans une 3e partie JAR
et j'ai besoin d'accéder à l'un de ses privé champs. Par exemple,
pourquoi aurais-je besoin de choisir le domaine privé est-il nécessaire?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
Comment puis-je utiliser la réflexion pour obtenir la valeur de stuffIWant
?
Vous devez vous connecter pour publier un commentaire.
Pour accéder aux champs privés, vous avez besoin pour obtenir à partir de la classe de déclaré champs, puis de les rendre accessibles:
MODIFIER: comme il a été commenté par aperkins, tant l'accès au champ, réglage de l'accessibilité et de la récupération de la valeur de tous les jeter
Exception
s, bien que le seul vérifié exceptions vous besoin d'être conscient de sont commentés ci-dessus.La
NoSuchFieldException
pourrait être levée si vous avez demandé un champ par un nom qui ne correspond pas à une déclaration de terrain.La
IllegalAccessException
pourrait être levée si le champ n'était pas accessible (par exemple, s'il est privé et n'a pas été rendu accessible via manquer lef.setAccessible(true)
ligne.La
RuntimeException
s qui pourraient être projetés sont soitSecurityException
s (si la JVMSecurityManager
ne vous permettra pas de modifier un champ d'accessibilité), ouIllegalArgumentException
s, si vous essayez d'accéder au champ sur un objet n'est pas de la classe du type:a.setAccessible(true); String var = a.getName(); a.get(var)
me donneCan not set final to java.lang.String
getDeclaredField()
ne trouve pas de champs si ils sont définis dans les classes parent -- vous devez également effectuer une itération par le biais de la classe parent de la hiérarchie, l'appel degetDeclaredField()
sur chacun d'eux, jusqu'à ce que vous trouver un match (après quoi vous pouvez appelersetAccessible(true)
), ou que vous arrivez àObject
.private
champs. Il s'oppose à l'accès accidentel.x
) à partir du module de la classe exécutant le code de réflexion (y
), puisx
devez ouvrir (opens
) ày
pourf.setAccessible(true)
pour réussir.Essayer
FieldUtils
de apache commons-lang3:Réflexion n'est pas la seule façon de résoudre votre problème (qui est de l'accès privé de la fonctionnalité et/ou du comportement d'une classe/composant)
Une solution alternative consiste à extraire de la classe à partir de l' .jar, décompiler à l'aide de (dis) Jode ou Jad, modifiez le champ (ou ajouter un accesseur), et de recompiler contre l'original .jar. Ensuite, mettre le nouveau .la classe à l'avance de la
.jar
dans le classpath, ou réinsérez-la dans le.jar
. (le pot utilitaire vous permet d'extraire et de le réinsérer à un existant .jar)Comme indiqué ci-dessous, cela résout le problème plus large de l'accès, de modification privé de l'état plutôt que le simple accès/modification d'un champ.
Cela nécessite la
.jar
de ne pas être signé, bien sûr..jar
à.zip
et de l'ouvrir avec l'Explorateur Windows.stuffIWant
de cette façon, si cela ne répond pas à la question posée.Une autre option qui n'a pas encore été mentionnés: l'utilisation Groovy. Groovy vous permet d'accéder à des variables d'instance privé comme un effet secondaire de la conception de la langue. Si vous avez ou non un getter pour le domaine, vous pouvez simplement utiliser
À l'aide de la Réflexion en Java vous pouvez accéder à tous les
private/public
les champs et les méthodes d'une classe à l'autre .Mais comme par le Oracle la documentation dans la section inconvénients ils ont recommandé que :"Depuis de réflexion permet code pour effectuer des opérations qui seraient illégales au non-réfléchissant code, telles que l'accès aux champs privés et des méthodes, l'utilisation de la réflexion, peut entraîner des effets secondaires inattendus, ce qui peut rendre le code de dysfonctionnements et peut détruire la portabilité. Réfléchissant code des pauses abstractions et, par conséquent, peuvent changer de comportement avec les mises à niveau de la plate-forme"
voici code suivant snapts pour démontrer des concepts de base de Réflexion
Reflection1.java
Reflection2.java
Espère que ça va aider.
Comme oxbow_lakes mentionne, vous pouvez utiliser la réflexion, afin de contourner les restrictions d'accès (en supposant que votre SecurityManager vous permettra d').
Cela dit, si cette classe est tellement mal conçu qu'il vous incite à recourir à de telles hackery, peut-être vous devriez chercher une alternative. Sûr que ce petit hack peut-être vous sauver quelques heures maintenant, mais combien cela va vous coûter en bas de la route?
Utiliser la Suie Java Optimisation cadre de modifier directement le bytecode.
http://www.sable.mcgill.ca/soot/
La suie est entièrement écrit en Java et fonctionne avec les nouvelles versions de Java.
Vous devez faire ce qui suit:
Juste une remarque supplémentaire sur la réflexion: j'ai pu observer dans certains cas particuliers, lorsque plusieurs classes avec le même nom existent dans les différents forfaits, que la réflexion tel qu'utilisé dans la réponse sommet, peut ne pas choisir la bonne classe de l'objet. Donc, si vous savez quelle est la package.class de l'objet, alors il est préférable pour accéder à son domaine privé valeurs comme suit:
(C'est l'exemple de la classe qui n'a pas de travail pour moi)
Si l'aide de Printemps, ReflectionTestUtils fournit quelques outils pratiques qui aide ici avec un minimum d'effort. Il est décrit comme étant "pour l'utilisation de l'unité et de l'intégration des scénarios d'essais". Il y a aussi une catégorie similaire nommé ReflectionUtils mais c'est décrite comme "Uniquement destinées à un usage interne" - voir cette réponse pour une interprétation de ce que cela signifie.
À l'adresse affichée exemple:
ReflectionTestUtils
que dans mon expérience, je n'ai jamais nécessaire de faire ce genre de chose dans une situation de test.)Vous pouvez utiliser Manifold @JailBreak direct, type-safe réflexion Java:
@JailBreak
déverrouille lefoo
variable locale dans le compilateur pour un accès direct à tous les membres deFoo
's de la hiérarchie.De même, vous pouvez utiliser le jailbreak() méthode d'extension pour un usage:
Par le biais de la
jailbreak()
méthode, vous pouvez accéder à n'importe quel membre enFoo
's de la hiérarchie.Dans les deux cas, le compilateur résout le domaine de l'accès pour vous de type sécuritaire, comme si un champ public, tandis que le Collecteur génère efficace code de réflexion pour vous sous le capot.
Découvrir plus sur Collecteur.