Отражение Java-влияние setAccessible(true)



Я использую некоторые аннотации для динамического задания значений полей в классах. Поскольку я хочу сделать это независимо от того, является ли это публичным, защищенным или частным, я вызываю setAccessible(true) на поле объекта каждый раз перед вызовом set() метод. Мой вопрос в том, какое влияние оказывает setAccessible() вызов есть на самом поле?



более конкретно, скажем, что это частное поле и этот набор кодов вызывает setAccessible(true). Если какое-то другое место в коде было тогда получить то же самое поле через отражение, будет ли поле уже доступно? Или делает getDeclaredFields() и getDeclaredField() методы возвращают новые экземпляры объекта поля каждый раз?



Я думаю, другой способ постановки вопроса, если я позвоню setAccessible(true), насколько важно установить его обратно в исходное значение после того, как я закончу?

678   4  

4 ответов:

С setAccessible() вы меняете поведение AccessibleObject, т. е. Field экземпляр, но не фактическое поле класса. Вот это документация (выдержка):

значение true указывает, что отраженный объект должен подавлять проверки для управления доступом к языку Java, когда он используется

и запускаемый пример:

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

}

The getDeclaredField метод должен возвращать новый объект каждый раз, именно потому, что этот объект имеет изменчивую accessible флаг. Поэтому нет необходимости сбрасывать флаг. Вы можете найти полную информацию в этот блог.

как показали другие плакаты,setAccessible применимо только к этому экземпляру вашего java.lang.reflect.Field, поэтому доступность ее обратно в исходное состояние не требуется.

однако...

если вы хотите, чтобы ваши звонки field.setAccessible(true) чтобы быть постоянным, вам нужно использовать базовые методы в java.lang.Class и java.lang.reflect.Field. Публичные методы сталкиваются отправить вам копии на Field экземпляр, так что "забывает" после каждого раза вы делаете что-то вроде 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();
        }
    }
}
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));
    }

}

Comments

    Ничего не найдено.