Java reflection-wpływ setAccessible(true)

Używam adnotacji do dynamicznego ustawiania wartości pól w klasach. Ponieważ chcę to zrobić niezależnie od tego, czy jest to publiczne, chronione, czy prywatne, jestem wywołaniem setAccessible(true) w obiekcie Field za każdym razem przed wywołaniem metody set(). Moje pytanie brzmi, jaki wpływ ma wywołanie setAccessible() na samo pole?

Mówiąc dokładniej, powiedzmy, że jest to pole prywatne i ten zestaw wywołań kodu setAccessible(true). Jeśli jakieś inne miejsce w kodzie było wtedy, aby pobrać to samo pole przez odbicie, czy pole będzie już dostępne? Czy metody getDeclaredFields() i getDeclaredField() zwracają za każdym razem nowe instancje obiektu Field?

Myślę, że innym sposobem na stwierdzenie pytania jest to, jeśli wywołam setAccessible(true), jak ważne jest, aby ustawić go z powrotem do pierwotnej wartości po zakończeniu?

Author: dnc253, 2012-05-17

4 answers

Za pomocą setAccessible() zmieniasz zachowanie AccessibleObject, tj. instancji Field, ale nie rzeczywistego pola klasy. Oto dokumentacja (fragment):

Wartość true wskazuje, że odbity obiekt powinien wstrzymać kontrole kontroli dostępu języka Java, gdy jest używany

I przykład:

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));
    }

}
 59
Author: Moritz Petersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 12:33:32

Metoda getDeclaredField musi zwracać za każdym razem nowy obiekt, dokładnie dlatego, że obiekt ten ma zmienną flagę accessible. Nie ma więc potrzeby resetowania flagi. Pełne szczegóły znajdziesz w ten wpis na blogu .

 27
Author: Jörn Horstmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-17 15:41:09

Jak wskazywały inne plakaty, setAccessible ma zastosowanie tylko do tej instancji twojego java.lang.reflect.Field, więc ustawienie dostępności z powrotem do jej pierwotnego stanu nie jest konieczne.

Jednakże...

Jeśli chcesz, aby Twoje wywołania field.setAccessible(true) były trwałe, musisz użyć podstawowych metod w java.lang.Class i java.lang.reflect.Field. Metody public facing wysyłają kopie instancji Field, więc "zapomina" po każdym zrobieniu czegoś w rodzaju class.getField(name) {9]}

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();
        }
    }
}
 1
Author: Col-E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-12 00:42:43
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
Author: RamChandra Bhakar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-06 12:53:25