[java] 자바 리플렉션-setAccessible (true)의 영향

클래스의 필드 값을 동적으로 설정하기 위해 몇 가지 주석을 사용하고 있습니다. 공개, 보호 또는 비공개 여부에 관계없이이 작업을 수행하고 싶기 때문에 메서드 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));
    }

}


답변