Frage Java-Reflektion - Auswirkung von setAccessible (true)


Ich verwende einige Anmerkungen, um Werte von Feldern in Klassen dynamisch festzulegen. Da ich dies unabhängig davon tun möchte, ob es öffentlich, geschützt oder privat ist, bin ich eine Berufung setAccessible(true) auf dem Field-Objekt jedes Mal vor dem Aufruf der set() Methode. Meine Frage ist, welche Art von Einfluss hat die setAccessible() Call auf dem Feld selbst haben?

Genauer gesagt, sagen wir, es ist ein privates Feld und diese Reihe von Codeaufrufen setAccessible(true). Wenn an einer anderen Stelle im Code das gleiche Feld durch Reflexion gefunden werden sollte, wäre das Feld dann bereits zugänglich? Oder macht das getDeclaredFields() und getDeclaredField() Methoden geben jedes Mal neue Instanzen eines Field-Objekts zurück?

Ich denke, eine andere Art, die Frage zu stellen, ist, wenn ich anrufe setAccessible(true)Wie wichtig ist es, den ursprünglichen Wert wiederherzustellen, nachdem ich fertig bin?


75
2018-05-17 15:33


Ursprung


Antworten:


Mit setAccessible() Sie ändern das Verhalten der AccessibleObject, d Field Instanz, aber nicht das eigentliche Feld der Klasse. Hier ist die Dokumentation (Auszug):

Ein Wert von true Gibt an, dass das reflektierte Objekt die Überprüfung der Java-Zugriffssteuerung unterdrücken soll, wenn es verwendet wird

Und ein ausführbares Beispiel:

public class FieldAccessible {
    public static class MyClass {
        private String theField;
    }

    public static void main(String[] args) throws Exception {
        MyClass myClass = new MyClass();
        Field field1 = myClass.getClass().getDeclaredField("theField");
        field1.setAccessible(true);
        System.out.println(field1.get(myClass));
        Field field2 = myClass.getClass().getDeclaredField("theField");
        System.out.println(field2.get(myClass));
    }

}

56
2018-05-17 15:43



Das getDeclaredField Methode muss jedes Mal ein neues Objekt zurückgeben, genau weil dieses Objekt veränderbar ist accessible Flagge. Es ist also nicht nötig, das Flag zurückzusetzen. Sie können die vollständigen Details in finden dieser Blogbeitrag.


27
2018-05-17 15:41



import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PrivateVariableAcc {

    public static void main(String[] args) throws Exception {
        PrivateVarTest myClass = new PrivateVarTest();
        Field field1 = myClass.getClass().getDeclaredField("a");
        field1.setAccessible(true);
        System.out.println("This is access the private field-"
            + field1.get(myClass));
        Method mm = myClass.getClass().getDeclaredMethod("getA");
        mm.setAccessible(true);
        System.out.println("This is calling the private method-"
            + mm.invoke(myClass, null));
    }

}

0
2017-11-23 09:45



Wie andere Poster angedeutet haben, setAccessible gilt nur für diese Instanz Ihres java.lang.reflect.FieldDaher ist es nicht erforderlich, die Barrierefreiheit in den ursprünglichen Zustand zurückzusetzen.

Jedoch...

Wenn Sie Ihre Anrufe wünschen field.setAccessible(true) Um persistent zu sein, müssen Sie die zugrunde liegenden Methoden verwenden java.lang.Class und java.lang.reflect.Field. Die Public-Facing-Methoden senden Sie Kopien des Field Beispiel, so ist es "vergisst" nach jeder Zeit machst du etwas wie class.getField(name)

import java.lang.reflect.*;
import sun.reflect.FieldAccessor;

public class Reflect {
    private static Method privateGetDeclaredFields;
    private static Method getFieldAccessor;

    public static Field[] fields(Class<?> clazz) throws Exception {
        return (Field[]) privateGetDeclaredFields.invoke(clazz, false);
    }

    public static <T> T get(Object instance, Field field) throws Exception {
        return ((FieldAccessor) getFieldAccessor.invoke(field, instance)).get(instance);
    }

    public static void set(Object instance, Field field, Object value) throws Exception {
        ((FieldAccessor) getFieldAccessor.invoke(field, instance)).set(instance, value);
    }

    static {
        try {
            // These are used to access the direct Field instances instead of the copies you normally get through #getDeclaredFields.
            privateGetDeclaredFields = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
            privateGetDeclaredFields.setAccessible(true);
            getFieldAccessor = Field.class.getDeclaredMethod("getFieldAccessor", Object.class);
            getFieldAccessor.setAccessible(true);
        } catch (Exception e) {
            // Should only occur if the internals change.
            e.printStackTrace();
        }
    }
}

0
2018-03-12 00:42