[java] Java의 리플렉션을 통해 개인 상속 필드에 액세스

상속 된 구성원을 통해 class.getDeclaredFields();
개인 구성원에 액세스 하는 방법을 찾았 class.getFields()
지만 개인 상속 된 필드를 찾고 있습니다. 어떻게하면 되나요?



답변

이를 해결하는 방법을 보여줄 것입니다.

import java.lang.reflect.Field;

class Super {
    private int i = 5;
}

public class B extends Super {
    public static void main(String[] args) throws Exception {
        B b = new B();
        Field f = b.getClass().getSuperclass().getDeclaredField("i");
        f.setAccessible(true);
        System.out.println(f.get(b));
    }
}

(또는 Class.getDeclaredFields모든 필드의 배열)

산출:

5


답변

여기에서 가장 좋은 방법은 방문자 패턴을 사용하여 클래스의 모든 필드와 모든 수퍼 클래스를 찾아 콜백 작업을 실행하는 것입니다.


이행

Spring은이를 수행하는 멋진 Utility 클래스 ReflectionUtils를 가지고 있습니다. 콜백을 사용하여 모든 수퍼 클래스의 모든 필드를 반복하는 메서드를 정의합니다.ReflectionUtils.doWithFields()

선적 서류 비치:

대상 클래스의 모든 필드에서 지정된 콜백을 호출하여 선언 된 모든 필드를 가져 오기 위해 클래스 계층 구조로 이동합니다.

매개 변수 :
-clazz-분석 할 대상 클래스-fc-
각 필드에 대해 호출 할 콜백
-ff-콜백을 적용 할 필드를 결정하는 필터

샘플 코드 :

ReflectionUtils.doWithFields(RoleUnresolvedList.class,
    new FieldCallback(){

        @Override
        public void doWith(final Field field) throws IllegalArgumentException,
            IllegalAccessException{

            System.out.println("Found field " + field + " in type "
                + field.getDeclaringClass());

        }
    },
    new FieldFilter(){

        @Override
        public boolean matches(final Field field){
            final int modifiers = field.getModifiers();
            // no static fields please
            return !Modifier.isStatic(modifiers);
        }
    });

산출:

발견 된 필드 private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe in type 클래스 javax.management.relation.RoleUnresolvedList
Found field private transient boolean javax.management.relation.RoleUnresolvedList.tainted in type class javax.management.relation.RoleUnresolvedList
Found field private transient java.lang.Object [] 클래스 java.util.ArrayList 유형의 java.util.ArrayList.elementData
발견 된 필드 private int 클래스 java.util.ArrayList 유형의 java.util.ArrayList.size
발견 된 필드 보호 된 transient int java. 클래스 java.util.AbstractList 유형의 util.AbstractList.modCount


답변

이렇게하면됩니다.

private List<Field> getInheritedPrivateFields(Class<?> type) {
    List<Field> result = new ArrayList<Field>();

    Class<?> i = type;
    while (i != null && i != Object.class) {
        Collections.addAll(result, i.getDeclaredFields());
        i = i.getSuperclass();
    }

    return result;
}

EclEmma 와 같은 코드 커버리지 도구를 사용하는 경우주의해야합니다 . 각 클래스에 숨겨진 필드를 추가합니다. EclEmma의 경우,이 필드는 표시됩니다 합성 하고,이처럼 그들을 필터링 할 수 있습니다 :

private List<Field> getInheritedPrivateFields(Class<?> type) {
    List<Field> result = new ArrayList<Field>();

    Class<?> i = type;
    while (i != null && i != Object.class) {
        for (Field field : i.getDeclaredFields()) {
            if (!field.isSynthetic()) {
                result.add(field);
            }
        }
        i = i.getSuperclass();
    }

    return result;
}


답변

public static Field getField(Class<?> clazz, String fieldName) {
    Class<?> tmpClass = clazz;
    do {
        try {
            Field f = tmpClass.getDeclaredField(fieldName);
            return f;
        } catch (NoSuchFieldException e) {
            tmpClass = tmpClass.getSuperclass();
        }
    } while (tmpClass != null);

    throw new RuntimeException("Field '" + fieldName
            + "' not found on class " + clazz);
}

( 답변을 바탕으로 )


답변

사실 나는 복잡한 유형의 계층 구조를 사용하므로 솔루션이 완전하지 않습니다. 상속 된 모든 개인 필드를 가져 오려면 재귀 호출을해야합니다. 여기 내 해결책이 있습니다.

 /**
 * Return the set of fields declared at all level of class hierachy
 */
public Vector<Field> getAllFields(Class clazz) {
    return getAllFieldsRec(clazz, new Vector<Field>());
}

private Vector<Field> getAllFieldsRec(Class clazz, Vector<Field> vector) {
    Class superClazz = clazz.getSuperclass();
    if(superClazz != null){
        getAllFieldsRec(superClazz, vector);
    }
    vector.addAll(toVector(clazz.getDeclaredFields()));
    return vector;
}


답변

Model Citizen 에서 청사진에 대한 상속 된 필드에 대한 지원을 추가해야했습니다 . 클래스의 필드 + 상속 된 필드를 검색하기 위해 좀 더 간결한이 메서드를 파생했습니다.

private List<Field> getAllFields(Class clazz) {
    List<Field> fields = new ArrayList<Field>();

    fields.addAll(Arrays.asList(clazz.getDeclaredFields()));

    Class superClazz = clazz.getSuperclass();
    if(superClazz != null){
        fields.addAll(getAllFields(superClazz));
    }

    return fields;
}


답변

private static Field getField(Class<?> clazz, String fieldName) {
    Class<?> tmpClass = clazz;
    do {
        for ( Field field : tmpClass.getDeclaredFields() ) {
            String candidateName = field.getName();
            if ( ! candidateName.equals(fieldName) ) {
                continue;
            }
            field.setAccessible(true);
            return field;
        }
        tmpClass = tmpClass.getSuperclass();
    } while ( clazz != null );
    throw new RuntimeException("Field '" + fieldName +
        "' not found on class " + clazz);
}