Вопрос по java – Получение имен / значений унаследованных атрибутов с использованием Java Reflection

108

Я "Java-объект" ChildObj " который расширен от "ParentObj". Теперь, если возможно извлечь все имена и значения атрибутов ChildObj, включая унаследованные атрибуты, используя механизм отражения Java?

Class.getFields дает мне массив открытых атрибутов, иClass.getDeclaredFields дает мне массив всех полей, но ни одно из них не включает список унаследованных полей.

Есть ли способ получить унаследованные атрибуты также?

Ваш Ответ

12   ответов
0

org.apache.commons.lang3.reflect.FieldUtils

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

это версия, которая не изменяет параметр функции, а также использует некоторые современные функции Java.

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

Эта реализация также делает вызов немного более кратким:

var fields = getFields(MyType.class);
32

ой цели,Apache Commons Lang версия 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));
    }
}
Boom! Я люблю не изобретать велосипед. Приветствия для этого.
1

   Class parentClass = getClass().getSuperclass();
   if (parentClass != null) {
      parentClass.getDeclaredFields();
   }
77
    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;
    }
это показывает, что рекурсивно не нужно и .. Мне нравятся короткие коды! Спасибо! :)
Я согласен с Пино
Хотя мне очень нравится рекурсивность (это забавно!), Я предпочитаю удобочитаемость этого метода и более интуитивные параметры (не требуется передавать новую коллекцию), не более if (неявно в предложении for) и без итерации над самими полями.
В течение многих лет я всегда думал, что начальное значение для for - это просто целое число, с вопросом @ Veera, который, я думаю, может решить только рекурсив, @ Esko Luontola, ваша команда потрясающая.
Это мое предпочтительное решение, однако я бы назвал его «getAllFields» потому что он возвращает поля данного класса тоже.
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);
    }
}
6

Вам нужно позвонить:

Class.getSuperclass().getDeclaredFields()

Пересматривая иерархию наследования по мере необходимости.

155

ты должен написать это сам. Это простой рекурсивный метод, вызываемый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));
}
это сработало. Благодарю. Veera
да. думал об этом. но хотел проверить, есть ли другой способ сделать это. Благодарю. :) Veera
Передача изменяемого аргумента и его возвращение, вероятно, не является хорошим дизайном. fields.addAll (type.getDeclaredFields ()); будет более обычным, чем расширенный цикл с добавлением.
не стесняйтесь изменять редактировать мой код :-)
Я чувствую необходимость хотя бы скомпилировать его (в stackoverflow!) И, возможно, добавить немного Arrays.asList.
3

единственная небольшая проблема заключается в том, что они возвращают расширенный набор объявленных и унаследованных членов. Обратите внимание, что метод getDeclaredFields () возвращает также закрытые методы. Таким образом, учитывая, что вы перемещаетесь по всей иерархии суперклассов, вы включаете все частные поля, объявленные в суперклассах, и эти поля не наследуются.

Простой фильтр с Modifier.isPublic || Предикат Modifier.isProtected будет делать:

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

5

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

private static Field[] getAllFields(Class<?> type) {
    if (type.getSuperclass() != null) {
        return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
    }
    return type.getDeclaredFields();
}
Этот класс от Apache Commons Lang.
HI @Alexis LEGROS: ArrayUtils не может найти символ.
Apache уже имеет функцию FieldUtils.getAllFields для обработки этого вопроса.

Похожие вопросы