Jaka jest różnica między getFields a getDeclaredFields w odbiciu Java


195

Jestem trochę zdezorientowany co do różnicy między getFieldsmetodą agetDeclaredFields metodą przy użyciu odbicie Java.

Przeczytałem, że getDeclaredFieldsdaje ci dostęp do wszystkich pól klasy i getFieldszwraca tylko pola publiczne. Jeśli tak jest, dlaczego po prostu nie zawsze używałbyś getDeclaredFields?

Czy ktoś może rozwinąć tę kwestię i wyjaśnić różnicę między tymi dwiema metodami oraz kiedy / dlaczego miałbyś chcieć używać jednej z nich?


3
getFieldmoże uzyskać pole dziedziczone z nadklasy, ale getDeclaredFieldnie może. getDeclaredFieldogranicz się do klasy, na której wywołujesz funkcję.
user2336315,

@ user2336315 jest poprawny, jednak getFieldnie może uzyskać dostępu do członków prywatnych
Madbreaks

Odpowiedzi:


258

getFields ()

Wszystkie publicpola w górę całej hierarchii klas.

getDeclaredFields ()

Wszystkie pola, niezależnie od ich dostępności, ale tylko dla bieżącej klasy, nie żadnych klas podstawowych, z których może dziedziczyć bieżąca klasa.

Aby przenieść wszystkie pola w górę hierarchii, napisałem następującą funkcję:

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

Ta exclusiveParentklasa ma zapobiegać pobieraniu pól z Object. Może tak być, nulljeśli chcesz Objectpola.

Aby wyjaśnić, Lists.newArrayListpochodzi z Guawy.

Aktualizacja

Do Twojej wiadomości, powyższy kod został opublikowany na GitHub w moim projekcie LibEx w ReflectionUtils .


8
Świetna odpowiedź, ale należy zauważyć, że prywatne pola w nadklasach nie mogą być używane przez instancje bieżącej klasy dla Field#geti podobnych metod. Innymi słowy, to podejście nie pozwala bieżącej klasie na dostęp do prywatnego interfejsu jego nadklasy, podobnie jak typowa kompilacja.
FThompson,

4
@Vulcan Prawda, chyba że kod został napisany w celu użycia zakresu refleksji w celu zmiany zakresu za pośrednictwem setAccessiblei nie ma menedżera zabezpieczeń
John B

Nieznaczna nitka, powinna być „(bez względu na dostępność)„ nie ”(bez względu na zakres)”. Wszystkie pola mają ten sam zakres, a mianowicie ciało klasy .
yshavit

@yshavit Thanks. Zaktualizowano
John B,

1
Nie zrobiłby tego. Ponieważ privatepola są dostępne tylko za pośrednictwem, getDeclaredFieldsktóre są specyficzne dla klasy. Każde pole (nawet o tym samym typie i nazwie) byłoby odrębnym Fieldwystąpieniem.
John B,

7

Jak już wspomniano, Class.getDeclaredField(String)patrzy tylko na pola zClass w którym je wywołujesz.

Jeśli chcesz wyszukać Fieldw Classhierarchii, możesz użyć tej prostej funkcji:

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

Jest to przydatne na przykład do znalezienia privatepola z nadklasy. Ponadto, jeśli chcesz zmodyfikować jego wartość, możesz użyć jej w następujący sposób:

/**
 * 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);
}

niewielka modyfikacja, aby nadal try try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }
zgłaszać

5

public Field[] getFields() throws SecurityException

Zwraca tablicę zawierającą obiekty Field odzwierciedlające wszystkie dostępne pola publiczne klasy lub interfejs reprezentowany przez ten obiekt Class. Zwracane elementy tablicy nie są sortowane i nie mają określonej kolejności. Ta metoda zwraca tablicę o długości 0, jeśli klasa lub interfejs nie ma dostępnych pól publicznych lub jeśli reprezentuje klasę tablicy, typ pierwotny lub void.

W szczególności, jeśli ten obiekt klasy reprezentuje klasę, ta metoda zwraca pola publiczne tej klasy i wszystkich jej nadklas. Jeśli ten obiekt klasy reprezentuje interfejs, ta metoda zwraca pola tego interfejsu i wszystkich jego super interfejsów.

Ta metoda nie uwzględnia pola niejawnej długości dla klasy tablicy. Kod użytkownika powinien używać metod klasy Array do manipulowania tablicami.


public Field[] getDeclaredFields() throws SecurityException

Zwraca tablicę obiektów Field odzwierciedlających wszystkie pola zadeklarowane przez klasę lub interfejs reprezentowany przez ten obiekt Class. Obejmuje to pola publiczne, chronione, domyślne (pakietowe) i prywatne , ale wyklucza pola dziedziczone . Zwracane elementy tablicy nie są sortowane i nie mają określonej kolejności. Ta metoda zwraca tablicę o długości 0, jeśli klasa lub interfejs nie deklaruje żadnych pól lub jeśli ten obiekt klasy reprezentuje typ pierwotny, klasę tablic lub void.


A jeśli potrzebuję wszystkich pól ze wszystkich klas nadrzędnych? Potrzebny jest pewien kod, np. Z 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;
}

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.