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


195

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

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

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


3
getField수퍼 클래스에서 상속 된 필드를 얻을 수 있지만 getDeclaredField불가능합니다. getDeclaredField함수를 호출하는 클래스로 자신을 제한하십시오.
user2336315

그러나 올바르지 만 @ user2336315 getField비공개 회원에 액세스 할 수 없습니다
Madbreaks

답변:


258

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에 게시되었습니다 .


8
대단한 대답이지만 수퍼 클래스의 개인 필드는 현재 클래스의 인스턴스 Field#get및 유사한 메소드 에서 사용할 수 없습니다 . 즉,이 방법은 하지 않는 전형적인 컴파일하지 않는 같은 방법으로 슈퍼 클래스의 개인 인터페이스에 현재 수준의 액세스를 할 수 있습니다.
FThompson 2016

4
@Vulcan 범위를 변경하기 위해 리플렉션을 사용하도록 코드를 작성 setAccessible하지 않고 보안 관리자가없는 경우
John B

약간의 니트는 "(범위에 상관없이)"가 아니라 "(접근성에 관계없이)"이어야합니다. 모든 필드는 동일한 범위, 즉 클래스의 본문을 갖습니다 .
yshavit

@yshavit 감사합니다. 업데이트되었습니다.
John B

1
그렇지 않습니다. 때문에 private필드에만 액세스 할 수 있습니다 통해 getDeclaredFields어떤 클래스 고유의 것입니다. 유형과 이름이 같은 각 필드는 별개의 Field인스턴스입니다.
John B

7

이미 언급했듯이, 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);
}

전혀 발견되지 않은 경우에도 여전히 오류가 발생하도록 약간 수정try try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }
Sven Dhaens

5

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;
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.