Um auf private Felder zugreifen zu können, müssen Sie sie aus den deklarierten Feldern der Klasse abrufen und anschließend zugänglich machen:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
BEARBEITEN : Wie von Aperkins kommentiert , kann sowohl der Zugriff auf das Feld als auch das Festlegen des Zugriffs als auch das Abrufen des Werts Exception
s auslösen , obwohl die einzigen geprüften Ausnahmen, die Sie beachten müssen , oben kommentiert sind.
Das NoSuchFieldException
wird ausgelöst, wenn Sie nach einem Feld mit einem Namen fragen, der keinem deklarierten Feld entspricht.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Das IllegalAccessException
würde ausgelöst, wenn das Feld nicht zugänglich wäre (zum Beispiel, wenn es privat ist und nicht zugänglich gemacht wurde, indem die f.setAccessible(true)
Zeile verpasst wurde .
Die RuntimeException
s, die ausgelöst werden können, sind entweder SecurityException
s (wenn die JVMs SecurityManager
es Ihnen nicht erlauben, die Zugänglichkeit eines Felds zu ändern) oder IllegalArgumentException
s, wenn Sie versuchen, auf das Feld eines Objekts zuzugreifen, das nicht vom Klassentyp des Felds ist:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
getDeclaredField()
findet keine Felder, wenn sie in übergeordneten Klassen definiert sind - Sie müssen auch die übergeordnete Klassenhierarchie durchlaufen undgetDeclaredField()
jedes aufrufen , bis Sie eine Übereinstimmung finden (nach der Sie aufrufen könnensetAccessible(true)
) oder erreichenObject
.private
. Dies schließt einen versehentlichen Zugriff aus.Versuchen Sie es mit
FieldUtils
apache commons-lang3:quelle
Reflexion ist nicht die einzige Möglichkeit, Ihr Problem zu lösen (dh auf die private Funktionalität / das Verhalten einer Klasse / Komponente zuzugreifen).
Eine alternative Lösung besteht darin, die Klasse aus der JAR-Datei zu extrahieren, sie mit (z. B.) Jode oder Jad zu dekompilieren , das Feld zu ändern (oder einen Accessor hinzuzufügen) und sie mit der ursprünglichen JAR-Datei neu zu kompilieren. Stellen Sie dann die neue .class vor die
.jar
in den Klassenpfad oder fügen Sie sie erneut in die ein.jar
. (Mit dem Dienstprogramm jar können Sie eine vorhandene .jar-Datei extrahieren und erneut einfügen.)Wie unten erwähnt, löst dies das umfassendere Problem des Zugriffs auf / der Änderung des privaten Status, anstatt einfach auf ein Feld zuzugreifen / diesen zu ändern.
Dies setzt
.jar
natürlich voraus, dass das nicht unterschrieben wird.quelle
Eine andere Option, die noch nicht erwähnt wurde: Verwenden Sie Groovy . Mit Groovy können Sie als Nebeneffekt beim Entwurf der Sprache auf private Instanzvariablen zugreifen. Unabhängig davon, ob Sie einen Getter für das Feld haben oder nicht, können Sie ihn einfach verwenden
quelle
Mit der Reflection in Java können Sie auf alle
private/public
Felder und Methoden einer Klasse für eine andere zugreifen. Gemäß der Oracle- Dokumentation in dem Abschnitt Nachteile, die sie empfohlen haben:"Da durch Reflexion Code Operationen ausführen kann, die in nicht reflektierendem Code illegal wären, z. B. der Zugriff auf private Felder und Methoden, kann die Verwendung von Reflexion zu unerwarteten Nebenwirkungen führen, die den Code funktionsunfähig machen und die Portabilität zerstören können. Reflektierender Code bricht Abstraktionen und kann daher das Verhalten bei Upgrades der Plattform ändern "
Im Folgenden finden Sie folgende Code-Schnappschüsse, um grundlegende Konzepte der Reflexion zu demonstrieren
Reflection1.java
Reflection2.java
Hoffe es wird helfen.
quelle
Wie in oxbow_lakes erwähnt, können Sie mithilfe von Reflection die Zugriffsbeschränkungen umgehen (vorausgesetzt, Ihr SecurityManager lässt dies zu).
Das heißt, wenn diese Klasse so schlecht gestaltet ist, dass Sie auf solche Hackerei zurückgreifen, sollten Sie vielleicht nach einer Alternative suchen. Sicher, dieser kleine Hack spart Ihnen jetzt vielleicht ein paar Stunden, aber wie viel kostet es Sie später?
quelle
Verwenden Sie das Soot Java Optimization Framework, um den Bytecode direkt zu ändern. http://www.sable.mcgill.ca/soot/
Soot ist vollständig in Java geschrieben und funktioniert mit neuen Java-Versionen.
quelle
Sie müssen Folgendes tun:
quelle
Wenn Sie Spring verwenden, bietet ReflectionTestUtils einige nützliche Tools, die hier mit minimalem Aufwand helfen. Es wird als "zur Verwendung in Unit- und Integrationstestszenarien" beschrieben . Es gibt auch eine ähnliche Klasse mit dem Namen ReflectionUtils aber wie beschrieben wird : „Nur für den internen Gebrauch bestimmt“ - siehe diese Antwort für eine Interpretation dessen , was das bedeutet.
So adressieren Sie das veröffentlichte Beispiel:
quelle
ReflectionTestUtils
so beibehalten, wie ich es meiner Erfahrung nach nur in einer Testsituation tun musste.)Nur ein zusätzlicher Hinweis zur Reflexion: Ich habe in einigen Sonderfällen festgestellt, dass bei mehreren Klassen mit demselben Namen in verschiedenen Paketen die in der oberen Antwort verwendete Reflexion möglicherweise nicht die richtige Klasse aus dem Objekt auswählt. Wenn Sie also wissen, was die package.class des Objekts ist, ist es besser, wie folgt auf seine privaten Feldwerte zuzugreifen:
(Dies ist die Beispielklasse, die für mich nicht funktioniert hat)
quelle
Sie können Manifolds @JailBreak für die direkte, typsichere Java-Reflexion verwenden:
@JailBreak
Schaltet diefoo
lokale Variable im Compiler für den direkten Zugriff auf alle Mitglieder inFoo
der Hierarchie frei.Ebenso können Sie die Erweiterungsmethode jailbreak () für die einmalige Verwendung verwenden:
Über die
jailbreak()
Methode können Sie auf jedes Mitglied inFoo
der Hierarchie zugreifen .In beiden Fällen löst der Compiler den Feldzugriff für Sie typsicher wie ein öffentliches Feld auf, während Manifold unter der Haube einen effizienten Reflektionscode für Sie generiert.
Erfahren Sie mehr über Manifold .
quelle
Mit dem Tool XrayInterface ist das ganz einfach . Definieren Sie einfach die fehlenden Getter / Setter, z
und röntgen Sie Ihr schlecht gestaltetes Projekt:
Intern beruht dies auf Reflexion.
quelle
Versuchen Sie, das Problem für den Fall zu umgehen, dessen Kalass Sie Daten festlegen / abrufen möchten, ist eine Ihrer eigenen Klassen.
Erstellen Sie einfach ein
public setter(Field f, Object value)
undpublic Object getter(Field f)
dafür. Innerhalb dieser Mitgliedsfunktionen können Sie sogar selbst eine Sicherheitsüberprüfung durchführen. ZB für den Setter:Natürlich, jetzt müssen Sie das herausfinden,
java.lang.reflect.Field
fürsString
vor dem Einstellen von Feldwert.Ich verwende diese Technik in einem generischen ResultSet-to-and-from-Model-Mapper.
quelle