[java] Java 리플렉션에서 getFields와 getDeclaredFields의 차이점은 무엇입니까?

Java 리플렉션을 사용할 때 getFields메소드와 메소드 의 차이점에 대해 약간 혼란 스럽습니다 getDeclaredFields.

나는 getDeclaredFields클래스의 모든 필드에 액세스 할 수 있고 getFields공개 필드 만 반환 한다는 것을 읽었습니다 . 이 경우 항상 왜 항상 사용하지 getDeclaredFields않습니까?

누군가 이것에 대해 자세히 설명하고 두 방법의 차이점과 언제 어떻게 다른 것을 사용하고 싶습니까?



답변

getFields ()

모든 public필드는 전체 클래스 계층 구조입니다.

getDeclaredFields ()

현재 클래스가 상속 할 수있는 기본 클래스가 아닌 액세스 가능성에 관계없이 현재 클래스에 대해서만 모든 필드.

모든 필드를 계층 구조로 가져 오기 위해 다음 함수를 작성했습니다.

public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass,
                                   @Nullable Class<?> exclusiveParent) {

   List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
   Class<?> parentClass = startClass.getSuperclass();

   if (parentClass != null &&
          (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
     List<Field> parentClassFields =
         (List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
     currentClassFields.addAll(parentClassFields);
   }

   return currentClassFields;
}

exclusiveParent필드는 필드 검색을 방지하기 위해 제공됩니다 Object. 그것은있을 수 있습니다 null당신이 원하는 경우 Object필드를.

명확히하기 위해 Lists.newArrayList구아바 에서 온다.

최신 정보

참고로, 위 코드는 ReflectionUtils의 LibEx 프로젝트에서 GitHub에 게시되었습니다 .


답변

이미 언급했듯이, Class.getDeclaredField(String)필드 Class를 호출 한 필드 만 봅니다 .

계층 구조 Field에서 a를 검색 Class하려면 다음과 같은 간단한 기능을 사용할 수 있습니다.

/**
 * Returns the first {@link Field} in the hierarchy for the specified name
 */
public static Field getField(Class<?> clazz, String name) {
    Field field = null;
    while (clazz != null && field == null) {
        try {
            field = clazz.getDeclaredField(name);
        } catch (Exception e) {
        }
        clazz = clazz.getSuperclass();
    }
    return field;
}

private예를 들어 수퍼 클래스에서 필드 를 찾는 데 유용합니다 . 또한 값을 수정하려면 다음과 같이 사용할 수 있습니다.

/**
 * Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
 */
public static void setField(Object object, String fieldName, Object value) throws Exception {
    Field field = getField(object.getClass(), fieldName);
    field.setAccessible(true);
    field.set(object, value);
}


답변

public Field[] getFields() throws SecurityException

이 Class 객체가 나타내는 클래스 또는 인터페이스 의 액세스 가능한 모든 공개 필드 를 반영하는 Field 객체를 포함하는 배열을 리턴 합니다. 반환 된 배열의 요소는 정렬되지 않으며 특정 순서가 아닙니다. 이 메소드는 클래스 또는 인터페이스에 액세스 가능한 공용 필드가 없거나 배열 클래스, 기본 유형 또는 void를 나타내는 경우 길이가 0 인 배열을 리턴합니다.

특히,이 Class 객체가 클래스를 나타내는 경우,이 메소드는 이 클래스와 모든 슈퍼 클래스의 공개 필드를 돌려줍니다 . 이 Class 객체가 인터페이스를 나타내는 경우,이 메소드는이 인터페이스와 모든 슈퍼 인터페이스의 필드를 돌려줍니다.

이 클래스는 배열 클래스의 암시 적 길이 필드를 반영하지 않습니다. 사용자 코드는 Array 클래스의 메소드를 사용하여 배열을 조작해야합니다.

public Field[] getDeclaredFields() throws SecurityException

이 Class 객체가 나타내는 클래스 또는 인터페이스가 선언 한 모든 필드를 반영하는 Field 객체의 배열을 리턴 합니다. 여기 에는 공개, 보호, 기본 (패키지) 액세스 및 개인 필드가 포함되지만 상속 된 필드는 제외 됩니다. 반환 된 배열의 요소는 정렬되지 않으며 특정 순서가 아닙니다. 이 메소드는 클래스 또는 인터페이스가 필드를 선언하지 않거나이 Class 객체가 기본 유형, 배열 클래스 또는 void를 나타내는 경우 길이가 0 인 배열을 리턴합니다.

모든 부모 클래스의 모든 필드가 필요한 경우 어떻게해야합니까? 일부 코드가 필요합니다 (예 : https://stackoverflow.com/a/35103361/755804) .

public static List<Field> getAllModelFields(Class aClass) {
    List<Field> fields = new ArrayList<>();
    do {
        Collections.addAll(fields, aClass.getDeclaredFields());
        aClass = aClass.getSuperclass();
    } while (aClass != null);
    return fields;
}


답변


답변