wake-up-neo.com

Abrufen der geerbten Attributnamen/-werte mit Java Reflection

Ich habe ein Java-Objekt 'ChildObj', das von 'ParentObj' erweitert wird. Wenn nun alle Attributnamen und -werte von ChildObj einschließlich der geerbten Attribute mithilfe des Java-Reflektionsmechanismus abgerufen werden können?

Class.getFields gibt mir das Array von öffentlichen Attributen und Class.getDeclaredFields gibt mir das Array aller Felder, aber keines von ihnen enthält die geerbte Feldliste.

Gibt es eine Möglichkeit, die geerbten Attribute auch abzurufen?

107
Veera

nein, du musst es selbst schreiben. Es ist eine einfache rekursive Methode, die auf Class.getSuperClass () aufgerufen wird:

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));
}
155
dfa
    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;
    }
77
Esko Luontola

Wenn Sie sich stattdessen auf eine Bibliothek verlassen wollten, um dies auszuführen, bietet Apache Commons Lang Version 3.2+ 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));
    }
}
32
Chris

Sie müssen anrufen:

Class.getSuperclass().getDeclaredFields()

Rekursion der Vererbungshierarchie nach Bedarf.

6
Nick Holt

Verwenden Sie die Reflections-Bibliothek:

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

Die rekursiven Lösungen sind in Ordnung, das einzige kleine Problem ist, dass sie eine Obermenge von deklarierten und geerbten Mitgliedern zurückgeben. Beachten Sie, dass die getDeclaredFields () -Methode auch private Methoden zurückgibt. Vorausgesetzt, Sie navigieren durch die gesamte Superklassenhierarchie, schließen Sie alle in den Superklassen deklarierten privaten Felder ein, und diese werden nicht vererbt.

Ein einfacher Filter mit einem Modifier.isPublic || Modifier.isProtected-Prädikat würde Folgendes tun:

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);
    }
}
3
Marek Dec
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); 
    }       
}

Arbeitsversion der Lösung "DidYouMeanThatTomHa ..." oben

2
Theo Platt

Kürzer und mit weniger Objekten instanziiert? ^^

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

Du kannst es versuchen:

   Class parentClass = getClass().getSuperclass();
   if (parentClass != null) {
      parentClass.getDeclaredFields();
   }
1
Manuel Selva

Ich habe diesen Code kürzlich aus org.Apache.commons.lang3.reflect.FieldUtils gesehen. 

public static List<Field> getAllFieldsList(final Class<?> cls) {
        Validate.isTrue(cls != null, "The class must not be null");
        final List<Field> allFields = new ArrayList<>();
        Class<?> currentClass = cls;
        while (currentClass != null) {
            final Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            currentClass = currentClass.getSuperclass();
        }
        return allFields;
}
0
aman
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);
    }
}

Dies ist eine Umformulierung der akzeptierten Antwort von @ user1079877. Möglicherweise handelt es sich dabei um eine Version, die einen Parameter der Funktion nicht ändert und auch einige moderne Java-Funktionen verwendet.

public <T> Field[] getFields(final Class<T> type, final Field... fields) {
    final Field[] items = Stream.of(type.getDeclaredFields(), fields).flatMap(Stream::of).toArray(Field[]::new);
    if (type.getSuperclass() == null) {
        return items;
    } else {
        return getFields(type.getSuperclass(), items);
    }
}

Diese Implementierung macht das Aufrufen auch etwas prägnanter:

var fields = getFields(MyType.class);
0
scrutari