2009-06-25 12 views
91

Mam obiekt Java "ChildObj", który jest rozszerzony z "ParentObj". Teraz, jeśli możliwe jest pobranie wszystkich nazw atrybutów i wartości ChildObj, w tym także dziedziczonych atrybutów, za pomocą mechanizmu Java Reflection?Pobieranie nazw/wartości odziedziczonych atrybutów za pomocą Java Reflection

Class.getFields daje mi tablicę atrybutów publicznych, a Class.getDeclaredFields daje mi tablicę wszystkich pól, ale żadna z nich nie obejmuje listy dziedziczonych pól.

Czy istnieje sposób na odzyskanie dziedziczonych atrybutów?

Odpowiedz

132

Nie, musisz napisać to sam. Jest to prosta metoda rekurencyjna wezwał Class.getSuperClass():

public static List<Field> getAllFields(List<Field> fields, Class<?> type) { 
    fields.addAll(Arrays.asList(type.getDeclaredFields())); 

    if (type.getSuperclass() != null) { 
     getAllFields(fields, type.getSuperclass()); 
    } 

    return fields; 
} 

@Test 
public void getLinkedListFields() { 
    System.out.println(getAllFields(new LinkedList<Field>(), LinkedList.class)); 
} 
+1

tak. myślałem o tym. ale chciałem sprawdzić, czy jest jakikolwiek inny sposób na zrobienie tego. dzięki. :) – Veera

+0

zadziałało. dzięki. – Veera

+6

Podanie argumentu zmiennego i zwrócenie go prawdopodobnie nie jest świetnym projektem. fields.addAll (type.getDeclaredFields()); byłaby bardziej konwencjonalna niż ulepszona pętla for z dodaniem. –

5

Trzeba zadzwonić:

Class.getSuperclass().getDeclaredFields() 

recursing górę hierarchii dziedziczenia w razie potrzeby.

1

Można spróbować:

Class parentClass = getClass().getSuperclass(); 
    if (parentClass != null) { 
     parentClass.getDeclaredFields(); 
    } 
0
private static void addDeclaredAndInheritedFields(Class c, Collection<Field> fields) { 
    fields.addAll(Arrays.asList(c.getDeclaredFields())); 
    Class superClass = c.getSuperclass(); 
    if (superClass != null) { 
     addDeclaredAndInheritedFields(superClass, fields); 
    } 
} 
71
public static List<Field> getAllFields(Class<?> type) { 
     List<Field> fields = new ArrayList<Field>(); 
     for (Class<?> c = type; c != null; c = c.getSuperclass()) { 
      fields.addAll(Arrays.asList(c.getDeclaredFields())); 
     } 
     return fields; 
    } 
+9

To jest moje preferowane rozwiązanie, jednak nazwałbym je "getAllFields", ponieważ zwraca również pola danej klasy. – Pino

+0

Zgadzam się z Pino – Marquez

+3

Chociaż bardzo lubię rekursywność (to fajne!), Wolę czytelność tej metody i bardziej intuicyjne parametry (nie jest wymagane, aby nowa kolekcja była przekazywana), nie więcej, jeśli (niejawne w klauzuli for) i bez iteracji nad polami. –

2
private static void addDeclaredAndInheritedFields(Class<?> c, Collection<Field> fields) { 
    fields.addAll(Arrays.asList(c.getDeclaredFields())); 
    Class<?> superClass = c.getSuperclass(); 
    if (superClass != null) { 
     addDeclaredAndInheritedFields(superClass, fields); 
    }  
} 

wersję "DidYouMeanThatTomHa ..." rozwiązanie powyżej

3

rekurencyjnego rozwiązania są OK działa, tylko jest mały problem zwracają nadzbiór deklarowanych i odziedziczonych członków. Zauważ, że metoda getDeclaredFields() zwraca również metody prywatne. Biorąc pod uwagę, że nawigujesz całą hierarchią superklasy, uwzględnisz wszystkie prywatne pola zadeklarowane w nadklasach, które nie zostaną odziedziczone.

Prosty filtr z modyfikatorem.isPublic || Modifier.isProtected orzecznik zrobi:

import static java.lang.reflect.Modifier.isPublic; 
import static java.lang.reflect.Modifier.isProtected; 

(...) 

List<Field> inheritableFields = new ArrayList<Field>(); 
for (Field field : type.getDeclaredFields()) { 
    if (isProtected(field.getModifiers()) || isPublic(field.getModifiers())) { 
     inheritableFields.add(field); 
    } 
} 
25

Jeśli zamiast tego chciał polegać na bibliotekę do osiągnięcia tego celu, w wersji 3.2 lub nowszym Apache Commons Lang zapewnia FieldUtils.getAllFieldsList:

import java.lang.reflect.Field; 
import java.util.AbstractCollection; 
import java.util.AbstractList; 
import java.util.AbstractSequentialList; 
import java.util.Arrays; 
import java.util.LinkedList; 
import java.util.List; 

import org.apache.commons.lang3.reflect.FieldUtils; 
import org.junit.Assert; 
import org.junit.Test; 

public class FieldUtilsTest { 

    @Test 
    public void testGetAllFieldsList() { 

     // Get all fields in this class and all of its parents 
     final List<Field> allFields = FieldUtils.getAllFieldsList(LinkedList.class); 

     // Get the fields form each individual class in the type's hierarchy 
     final List<Field> allFieldsClass = Arrays.asList(LinkedList.class.getFields()); 
     final List<Field> allFieldsParent = Arrays.asList(AbstractSequentialList.class.getFields()); 
     final List<Field> allFieldsParentsParent = Arrays.asList(AbstractList.class.getFields()); 
     final List<Field> allFieldsParentsParentsParent = Arrays.asList(AbstractCollection.class.getFields()); 

     // Test that `getAllFieldsList` did truly get all of the fields of the the class and all its parents 
     Assert.assertTrue(allFields.containsAll(allFieldsClass)); 
     Assert.assertTrue(allFields.containsAll(allFieldsParent)); 
     Assert.assertTrue(allFields.containsAll(allFieldsParentsParent)); 
     Assert.assertTrue(allFields.containsAll(allFieldsParentsParentsParent)); 
    } 
} 
+3

Bum! Kocham nie wymyślać koła. Pozdrawiam za to. –

0

krótszy i mniej instancja obiektu? ^^

private static Field[] getAllFields(Class<?> type) { 
    if (type.getSuperclass() != null) { 
     return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields()); 
    } 
    return type.getDeclaredFields(); 
} 
+0

HI @Alexis LEGROS: ArrayUtils nie może znaleźć symbolu. –

+1

Ta klasa jest od Apache Commons Lang. –

+0

Apache ma już funkcję FieldUtils.getAllFields do obsługi tego żądania pytania. –

4

Stosować Refleksje Biblioteka:

public Set<Field> getAllFields(Class<?> aClass) { 
    return org.reflections.ReflectionUtils.getAllFields(aClass); 
} 
Powiązane problemy