使用 Java 反射检索继承的属性名称/值

我有一个 Java 对象“ ChildObj”,它是从“ ParentObj”扩展而来的。现在,是否可以使用 Java 反射机制检索 ChildObj 的所有属性名称和值,包括继承的属性?

GetFields 给出了公共属性的数组,Class.getDeclaredFields给出了所有字段的数组,但是没有一个包含继承的字段列表。

是否也有检索继承属性的方法?

95124 次浏览

不,你需要自己写。这是一个简单的递归方法,在 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));
}

你需要打电话:

Class.getSuperclass().getDeclaredFields()

必要时向上递归继承层次结构。

你可以试试:

   Class parentClass = getClass().getSuperclass();
if (parentClass != null) {
parentClass.getDeclaredFields();
}
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);
}
}
    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;
}
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);
}
}

工作版本的“你是不是意味着 TomHa...”解决方案在上面

递归解决方案是可以的,唯一的小问题是它们返回声明的和继承的成员的超集。注意,getDeclaredFields ()方法也返回私有方法。因此,假设您浏览了整个超类层次结构,您将包括在超类中声明的所有私有字段,而这些字段不会被继承。

使用修改器.isPublic | | 修改器.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);
}
}

如果你想依靠一个库来完成这个任务,Apache Commons Lang3.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));
}
}

更短且实例化的对象更少? ^ ^

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

使用反思图书馆:

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

这是@user1079877对已接受答案的改写。它可能是一个不修改函数参数并且使用一些现代 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);

GetFields () : 获取整个类层次结构中的所有公共字段,并且
GetDeclaredFields () : 获取所有字段,不管其修饰符如何,但仅针对当前类。所以,你必须考虑到所有的等级制度。
我最近在 实用工具上看到了这段代码

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

FieldUtils 没有解决一些怪异的问题——特别是合成字段(例如由 JaCoCo 注入) ,还有一个事实是枚举类型当然对每个实例都有一个字段,如果你遍历一个对象图,获取所有字段,然后获取每个字段的字段等等,那么当你命中一个枚举时,你将进入一个无限循环。一个扩展的解决方案(老实说,我敢肯定这必须住在图书馆的某个地方!)就是:

/**
* Return a list containing all declared fields and all inherited fields for the given input
* (but avoiding any quirky enum fields and tool injected fields).
*/
public List<Field> getAllFields(Object input) {
return getFieldsAndInheritedFields(new ArrayList<>(), input.getClass());
}


private List<Field> getFieldsAndInheritedFields(List<Field> fields, Class<?> inputType) {
fields.addAll(getFilteredDeclaredFields(inputType));
return inputType.getSuperclass() == null ? fields : getFieldsAndInheritedFields(fields, inputType.getSuperclass());


}


/**
* Where the input is NOT an {@link Enum} type then get all declared fields except synthetic fields (ie instrumented
* additional fields). Where the input IS an {@link Enum} type then also skip the fields that are all the
* {@link Enum} instances as this would lead to an infinite loop if the user of this class is traversing
* an object graph.
*/
private List<Field> getFilteredDeclaredFields(Class<?> inputType) {
return Arrays.asList(inputType.getDeclaredFields()).stream()
.filter(field -> !isAnEnum(inputType) ||
(isAnEnum(inputType) && !isSameType(field, inputType)))
.filter(field -> !field.isSynthetic())
.collect(Collectors.toList());


}


private boolean isAnEnum(Class<?> type) {
return Enum.class.isAssignableFrom(type);
}


private boolean isSameType(Field input, Class<?> ownerType) {
return input.getType().equals(ownerType);
}

Spock 中的测试类(Groovy 增加了合成字段) :

class ReflectionUtilsSpec extends Specification {


def "declared fields only"() {


given: "an instance of a class that does not inherit any fields"
def instance = new Superclass()


when: "all fields are requested"
def result = new ReflectionUtils().getAllFields(instance)


then: "the fields declared by that instance's class are returned"
result.size() == 1
result.findAll { it.name in ['superThing'] }.size() == 1
}




def "inherited fields"() {


given: "an instance of a class that inherits fields"
def instance = new Subclass()


when: "all fields are requested"
def result = new ReflectionUtils().getAllFields(instance)


then: "the fields declared by that instance's class and its superclasses are returned"
result.size() == 2
result.findAll { it.name in ['subThing', 'superThing'] }.size() == 2


}


def "no fields"() {
given: "an instance of a class with no declared or inherited fields"
def instance = new SuperDooperclass()


when: "all fields are requested"
def result = new ReflectionUtils().getAllFields(instance)


then: "the fields declared by that instance's class and its superclasses are returned"
result.size() == 0
}


def "enum"() {


given: "an instance of an enum"
def instance = Item.BIT


when: "all fields are requested"
def result = new ReflectionUtils().getAllFields(instance)


then: "the fields declared by that instance's class and its superclasses are returned"
result.size() == 3
result.findAll { it.name == 'smallerItem' }.size() == 1
}


private class SuperDooperclass {
}


private class Superclass extends SuperDooperclass {
private String superThing
}




private class Subclass extends Superclass {
private String subThing
}


private enum Item {


BIT("quark"), BOB("muon")


Item(String smallerItem) {
this.smallerItem = smallerItem
}


private String smallerItem


}
}

使用 spring util 库,可以用来检查类中是否存在一个特定的属性:

Field field = ReflectionUtils.findRequiredField(YOUR_CLASS.class, "ATTRIBUTE_NAME");


log.info(field2.getName());

Api 文档:
Https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/util/reflectionutils.html

或者

 Field field2 = ReflectionUtils.findField(YOUR_CLASS.class, "ATTRIBUTE_NAME");


log.info(field2.getName());

Api 文档:
Https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/reflectionutils.html

@ 干杯

我知道这是一个姗姗来迟的回答,但我只是把我的答案放在这里,只是为了我的参考或任何人谁感兴趣的实现没有反思作为@dfa 的扩展的答案;

public List<Field> getDeclaredFields(Class<?> tClass) {
List<Field> fields = new LinkedList<>();


while (tClass != null) {
fields.addAll(Arrays.asList(tClass.getDeclaredFields()));
tClass = tClass.getSuperclass();
}


return fields;
}