Отражение Java-влияние setAccessible(true)
Я использую некоторые аннотации для динамического задания значений полей в классах. Поскольку я хочу сделать это независимо от того, является ли это публичным, защищенным или частным, я вызываю setAccessible(true) на поле объекта каждый раз перед вызовом set() метод. Мой вопрос в том, какое влияние оказывает setAccessible() вызов есть на самом поле?
более конкретно, скажем, что это частное поле и этот набор кодов вызывает setAccessible(true). Если какое-то другое место в коде было тогда получить то же самое поле через отражение, будет ли поле уже доступно? Или делает getDeclaredFields() и getDeclaredField() методы возвращают новые экземпляры объекта поля каждый раз?
Я думаю, другой способ постановки вопроса, если я позвоню setAccessible(true), насколько важно установить его обратно в исходное значение после того, как я закончу?
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