Wie liest man den Wert eines privaten Felds aus einer anderen Klasse in Java?

Lesezeit: 8 Minuten

Wie liest man den Wert eines privaten Felds aus einer
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?

Wie liest man den Wert eines privaten Felds aus einer
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 Exceptions, 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 RuntimeExceptions, die geworfen werden können, sind entweder SecurityExceptions (wenn die JVMs SecurityManager erlaubt Ihnen nicht, die Zugänglichkeit eines Felds zu ändern), oder IllegalArgumentExceptions, 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

  • können Sie bitte die Ausnahmekommentare erläutern? der Code ausgeführt wird, aber Ausnahmen auslöst? oder der Code kann Ausnahmen auslösen?

    – Nir Levy

    28. Juli 2009 um 20:34 Uhr

  • @Nir – Nein – aller Wahrscheinlichkeit nach wird der Code problemlos ausgeführt (da der standardmäßige SecurityManager die Änderung der Zugänglichkeit von Feldern zulässt) – aber Sie müssen handhaben geprüfte Ausnahmen (entweder abfangen oder als solche deklarieren zurückgeworfen). Ich habe meine Antwort ein wenig modifiziert. Es könnte für Sie gut sein, einen kleinen Testfall zu schreiben, um herumzuspielen und zu sehen, was passiert

    – oxbow_lakes

    28. Juli 2009 um 20:42 Uhr

  • Entschuldigung, diese Antwort ist für mich verwirrend. Zeigen Sie vielleicht ein Beispiel für eine typische Ausnahmebehandlung. Es scheint, als würden die Ausnahmen auftreten, wenn die Klassen falsch miteinander verbunden sind. Das Codebeispiel erweckt den Anschein, als würden die Ausnahmen auf die entsprechenden llnes geworfen.

    – LaFayette

    29. Februar 2016 um 8:33 Uhr


  • getDeclaredField() findet keine Felder, wenn sie in übergeordneten Klassen definiert sind – Sie müssen auch die übergeordnete Klassenhierarchie nach oben durchlaufen und aufrufen getDeclaredField() auf jedem, bis Sie eine Übereinstimmung finden (danach können Sie anrufen setAccessible(true)), oder Sie erreichen Object.

    – Lukas Hutchison

    13. Februar 2017 um 8:47 Uhr

  • @legend Sie können einen Sicherheitsmanager installieren, um einen solchen Zugriff zu verbieten. Seit Java 9 soll ein solcher Zugriff nicht über Modulgrenzen hinweg funktionieren (es sei denn, ein Modul ist explizit geöffnet), allerdings gibt es eine Übergangsphase bezüglich der Durchsetzung der neuen Regeln. Abgesehen davon machte zusätzlicher Aufwand wie Reflexion immer einen Unterschied zu Nicht-private Felder. Es schließt einen versehentlichen Zugriff aus.

    – Holger

    25. September 2018 um 8:30 Uhr

Versuchen FieldUtils von Apache commons-lang3:

FieldUtils.readField(object, fieldName, true);

  • Ich bin davon überzeugt, dass Sie die meisten Probleme der Welt lösen könnten, indem Sie einige Methoden aus commons-lang3 aneinanderreihen.

    – Kamerun

    5. August 2015 um 18:46 Uhr

  • @yegor warum erlaubt Java das? Meinst du, warum Java den Zugriff auf private Mitglieder erlaubt?

    – Asif Mushtaq

    24. April 2016 um 10:52 Uhr

  • @yegor256 Ich kann auch immer noch auf private C#- und C++-Mitglieder zugreifen..!! Dann? Alle Sprachschöpfer sind schwach?

    – Asif Mushtaq

    28. April 2016 um 15:04 Uhr

  • @UnKnown Java nicht. Es gibt zwei verschiedene Dinge – Java-Sprache und Java als virtuelle Java-Maschine. Letzteres arbeitet mit Bytecode. Und es gibt Bibliotheken, um das zu manipulieren. Die Java-Sprache erlaubt Ihnen also nicht, private Felder außerhalb des Geltungsbereichs zu verwenden, oder erlaubt nicht, endgültige Referenzen zu mutieren. Aber mit dem Tool ist das möglich. Was sich zufällig in der Standardbibliothek befindet.

    – evgenii

    7. August 2016 um 10:22 Uhr

  • @UnKnown Einer der Gründe ist, dass Java keinen “Friend” -Zugriff hat, um den Zugriff auf das Feld nur über ein Infrastruktur-Framework wie DI, ORM oder XML/JSON-Serializer zu ermöglichen. Solche Frameworks benötigen Zugriff auf Objektfelder, um den internen Zustand eines Objekts korrekt zu serialisieren oder zu initialisieren, aber Sie benötigen möglicherweise dennoch eine ordnungsgemäße Kapselung zur Kompilierzeit für Ihre Geschäftslogik.

    – Ivan Gammel

    21. Dezember 2016 um 16:51 Uhr

Wie liest man den Wert eines privaten Felds aus einer
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.

  • Dieser Weg wird für ein einfaches Feld ziemlich schmerzhaft sein.

    – Valentin Rocher

    29. Juli 2009 um 8:30 Uhr

  • Ich bin nicht einverstanden. Es ermöglicht Ihnen nicht nur den Zugriff auf Ihr Feld, sondern auch die Klasse zu wechseln, falls sich herausstellt, dass der Zugriff auf das Feld nicht ausreicht.

    – Brian Agnew

    29. Juli 2009 um 8:33 Uhr

  • Dann musst du das nochmal machen. Was passiert, wenn das JAR ein Update erhält und Sie Reflektion für ein Feld verwenden, das nicht mehr vorhanden ist? Es ist genau das gleiche Problem. Du musst es nur managen.

    – Brian Agnew

    23. November 2012 um 8:17 Uhr


  • Ich bin erstaunt, wie sehr dies abgelehnt wird, da es a) als praktische Alternative hervorgehoben wird und b) Szenarien berücksichtigt, in denen das Ändern der Sichtbarkeit eines Felds nicht ausreicht

    – Brian Agnew

    27. Dezember 2012 um 9:16 Uhr


  • @BrianAgnew vielleicht ist es nur semantisch, aber wenn wir bei der Frage bleiben (Reflektion verwenden, um ein privates Feld zu lesen), ist die Nichtverwendung von Reflektion sofort ein Selbstwiderspruch. Aber ich stimme zu, dass Sie Zugriff auf das Feld gewähren … aber das Feld ist immer noch nicht mehr privat, also bleiben wir auch hier nicht bei der Frage “ein privates Feld lesen”. Aus einem anderen Blickwinkel funktioniert die .jar-Modifikation in einigen Fällen möglicherweise nicht (signiertes JAR), muss jedes Mal durchgeführt werden, wenn das JAR aktualisiert wird, erfordert eine sorgfältige Manipulation des Klassenpfads (die Sie möglicherweise nicht vollständig kontrollieren, wenn Sie in einem ausgeführt werden Anwendungscontainer) usw.

    – Remi Morin

    24. Februar 2014 um 20:58 Uhr

1646638631 298 Wie liest man den Wert eines privaten Felds aus einer
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()

1646638632 449 Wie liest man den Wert eines privaten Felds aus einer
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.

1646638632 71 Wie liest man den Wert eines privaten Felds aus einer
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?

1646638632 411 Wie liest man den Wert eines privaten Felds aus einer
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.

964030cookie-checkWie liest man den Wert eines privaten Felds aus einer anderen Klasse in Java?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy