
Frank Krüger
Ich habe eine schlecht gestaltete Klasse in einem Drittanbieter JAR
und ich muss auf eines davon zugreifen Privat Felder. Warum sollte ich zum Beispiel ein privates Feld auswählen müssen, wenn es notwendig ist?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
Wie kann ich Reflexion verwenden, um den Wert von zu erhalten? stuffIWant
?

oxbow_lakes
Um auf private Felder zugreifen zu können, müssen Sie diese von den Klassen abrufen erklärt Felder und dann zugänglich machen:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
BEARBEITEN: wie von kommentiert wurde Taschentüchersowohl beim Zugriff auf das Feld als auch beim Festlegen des Zugriffs und beim Abrufen des Werts kann ausgelöst werden Exception
s, obwohl die einzige geprüft Ausnahmen, die Sie beachten müssen, sind oben kommentiert.
Die NoSuchFieldException
ausgelöst, wenn Sie nach einem Feld mit einem Namen fragen, der keinem deklarierten Feld entspricht.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Die IllegalAccessException
ausgelöst, wenn auf das Feld nicht zugegriffen werden kann (z. B. wenn es privat ist und nicht zugänglich gemacht wurde, indem die f.setAccessible(true)
Linie.
Die RuntimeException
s, die geworfen werden können, sind entweder SecurityException
s (wenn die JVMs SecurityManager
erlaubt Ihnen nicht, die Zugänglichkeit eines Felds zu ändern), oder IllegalArgumentException
s, wenn Sie versuchen, auf das Feld eines Objekts zuzugreifen, das nicht den Klassentyp des Felds hat:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
Versuchen FieldUtils
von Apache commons-lang3:
FieldUtils.readField(object, fieldName, true);

Brian Agnew
Reflektion ist nicht die einzige Möglichkeit, Ihr Problem zu lösen (d. h. auf die private Funktionalität/das private Verhalten einer Klasse/Komponente zuzugreifen).
Eine alternative Lösung besteht darin, die Klasse aus der .jar-Datei zu extrahieren und sie mit (sagen wir) zu dekompilieren Jode oder Jad, ändern Sie das Feld (oder fügen Sie einen Accessor hinzu) und kompilieren Sie es erneut mit der ursprünglichen .jar-Datei. Setzen Sie dann die neue .class vor die .jar
in den Klassenpfad oder fügen Sie ihn erneut in die .jar
. (Mit dem Dienstprogramm jar können Sie eine vorhandene .jar-Datei extrahieren und wieder einfügen.)
Wie unten angemerkt, löst dies das umfassendere Problem des Zugreifens/Änderns des privaten Zustands, anstatt einfach auf ein Feld zuzugreifen/dass es geändert wird.
Dies erfordert die .jar
natürlich nicht unterschreiben.

Lukas
Eine weitere Option, die noch nicht erwähnt wurde: use Groovig. Groovy ermöglicht den Zugriff auf private Instanzvariablen als Nebeneffekt des Sprachdesigns. Unabhängig davon, ob Sie einen Getter für das Feld haben oder nicht, können Sie einfach verwenden
def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()

simmant
Verwendung der Reflexion in Java Sie können auf alle zugreifen private/public
Felder und Methoden von einer Klasse zur anderen. Aber gemäß der Orakel Dokumentation im Bereich Nachteile sie empfahlen das:
„Da Reflektion es Code ermöglicht, Operationen auszuführen, die in nicht-reflektierendem Code illegal wären, wie z. B. der Zugriff auf private Felder und Methoden, kann die Verwendung von Reflektion zu unerwarteten Nebenwirkungen führen, die Code dysfunktional machen und die Portabilität zerstören können. Reflektierender Code bricht Abstraktionen und kann daher das Verhalten bei Upgrades der Plattform ändern”
Hier sind die folgenden Code-Snapts, um die grundlegenden Konzepte von zu demonstrieren Betrachtung
Reflexion1.java
public class Reflection1{
private int i = 10;
public void methoda()
{
System.out.println("method1");
}
public void methodb()
{
System.out.println("method2");
}
public void methodc()
{
System.out.println("method3");
}
}
Reflexion2.java
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection2{
public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Method[] mthd = Reflection1.class.getMethods(); // for axis the methods
Field[] fld = Reflection1.class.getDeclaredFields(); // for axis the fields
// Loop for get all the methods in class
for(Method mthd1:mthd)
{
System.out.println("method :"+mthd1.getName());
System.out.println("parametes :"+mthd1.getReturnType());
}
// Loop for get all the Field in class
for(Field fld1:fld)
{
fld1.setAccessible(true);
System.out.println("field :"+fld1.getName());
System.out.println("type :"+fld1.getType());
System.out.println("value :"+fld1.getInt(new Reflaction1()));
}
}
}
Hoffe es wird helfen.

Laurence Gonsalve
Wie oxbow_lakes erwähnt, können Sie Reflektion verwenden, um die Zugriffsbeschränkungen zu umgehen (vorausgesetzt, Ihr SecurityManager lässt Sie zu).
Das heißt, wenn diese Klasse so schlecht gestaltet ist, dass Sie auf solche Hacker zurückgreifen, sollten Sie vielleicht nach einer Alternative suchen. Sicher, dieser kleine Hack spart Ihnen jetzt vielleicht ein paar Stunden, aber wie viel wird es Sie später kosten?

pcpratts
Verwenden Sie das Soot Java Optimization Framework, um den Bytecode direkt zu ändern.
http://www.sable.mcgill.ca/soot/
Soot ist komplett in Java geschrieben und funktioniert mit neuen Java-Versionen.
9640300cookie-checkWie liest man den Wert eines privaten Felds aus einer anderen Klasse in Java?yes