2009-06-25 15 views
91

Ho un oggetto Java 'ChildObj' che si estende dal 'ParentObj'. Ora, se è possibile recuperare tutti i nomi e i valori degli attributi di ChildObj, inclusi anche gli attributi ereditati, utilizzando il meccanismo di riflessione Java?Recupero i nomi degli attributi/valori ereditati utilizzando Java Reflection

Class.getFields mi fornisce l'array di attributi pubblici e Class.getDeclaredFields mi fornisce l'array di tutti i campi, ma nessuno di essi include l'elenco di campi ereditati.

Esiste un modo per recuperare gli attributi ereditati anche?

risposta

132

no, è necessario scrivere da soli. Si tratta di un semplice metodo ricorsivo invitato 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

sì. pensato a questo. ma volevo controllare se esiste un altro modo per farlo. Grazie. :) – Veera

+0

ha funzionato. Grazie. – Veera

+6

Passare un argomento mutabile e restituirlo probabilmente non è un grande progetto. fields.addAll (type.getDeclaredFields()); sarebbe più convenzionale di un ciclo for enhanced con add. –

5

È necessario chiamare:

Class.getSuperclass().getDeclaredFields() 

recursing la gerarchia di ereditarietà, se necessario.

1

Si può provare:

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

Questa è la mia soluzione preferita, tuttavia la chiamerei "getAllFields" perché restituisce anche i campi della classe data. – Pino

+0

Sono d'accordo con Pino – Marquez

+3

Anche se mi piace molto la ricorsività (è divertente!), Preferisco la leggibilità di questo metodo e i parametri più intuitivi (non è richiesta una nuova raccolta da passare), non più se (implicito nella clausola for) e nessuna iterazione sui campi stessi. –

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

versione della soluzione di cui sopra

3

Le soluzioni ricorsive sono OK "DidYouMeanThatTomHa ..." Lavorare, l'unico piccolo problema è che restituiscono un superset di membri dichiarati ed ereditati. Nota che il metodo getDeclaredFields() restituisce anche metodi privati. Quindi, dato che navighi nella gerarchia della superclasse, includerai tutti i campi privati ​​dichiarati nelle superclassi e quelli che non vengono ereditati.

Un semplice filtro con un Modifier.isPublic || predicato Modifier.isProtected farebbe:

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

Se invece si voleva fare affidamento su una libreria per raggiungere questo obiettivo, Apache Commons Lang versione 3.2+ fornisce 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

Boom! Adoro non reinventare la ruota. Saluti per questo. –

0

Shorter e con meno oggetto istanziato? ^^

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 non riesce a trovare il simbolo. –

+1

Questa classe proviene da Apache Commons Lang. –

+0

Apache ha già una funzione FieldUtils.getAllFields per gestire questa richiesta di domande. –

4

Utilizzare Riflessioni libreria:

public Set<Field> getAllFields(Class<?> aClass) { 
    return org.reflections.ReflectionUtils.getAllFields(aClass); 
} 
Problemi correlati