클래스의 필드 값을 동적으로 설정하기 위해 몇 가지 주석을 사용하고 있습니다. 공개, 보호 또는 비공개 여부에 관계없이이 작업을 수행하고 싶기 때문에 메서드 setAccessible(true)
를 호출하기 전에 매번 Field 개체를 호출하고 set()
있습니다. 제 질문은이 setAccessible()
호출이 현장 자체에 어떤 영향을 미치는가입니다.
좀 더 구체적으로 말하자면, 개인 필드이고이 코드 세트는 setAccessible(true)
. 코드의 다른 위치가 리플렉션을 통해 동일한 필드를 검색하는 경우 해당 필드에 이미 액세스 할 수 있습니까? 아니면 메서드 getDeclaredFields()
와 getDeclaredField()
메서드가 매번 Field 개체의 새 인스턴스를 반환합니까?
질문을 설명하는 또 다른 방법은 전화 setAccessible(true)
하면, 완료 후 원래 값으로 다시 설정하는 것이 얼마나 중요합니까?
답변
으로 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)); // no exception
Field field2 = myClass.getClass().getDeclaredField("theField");
System.out.println(field2.get(myClass)); // IllegalAccessException
}
}
답변
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();
}
}
}
업데이트 :이 구현은 Java 8 용이며 향후 버전은이를 중단하는 백엔드를 변경합니다. 이 전략을 계속 진행하려면 동일한 개념이 여전히 적용됩니다.
답변
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));
}
}