221

我对使用Java反射时getFields方法和方法之间的区别感到有些困惑。getDeclaredFields

我读到它getDeclaredFields使您可以访问该类的所有字段,并且 getFields只返回公共字段。如果是这种情况,你为什么不总是使用getDeclaredFields

有人可以详细说明一下,并解释这两种方法之间的区别,以及何时/为什么要使用其中一种方法?

4

4 回答 4

289

获取字段()

public整个类层次结构中的所有字段。

getDeclaredFields()

所有字段,无论其可访问性如何,但仅适用于当前类,而不是当前类可能继承的任何基类。

为了使层次结构中的所有字段上升,我编写了以下函数:

public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass, 
                                   @Nullable Class<?> exclusiveParent) {

   List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
   Class<?> parentClass = startClass.getSuperclass();

   if (parentClass != null && 
          (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
     List<Field> parentClassFields = 
         (List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
     currentClassFields.addAll(parentClassFields);
   }

   return currentClassFields;
}

提供该类exclusiveParent是为了防止从Object. null如果您确实想要这些Object字段,则可能是这样。

澄清一下,Lists.newArrayList来自番石榴。

更新

仅供参考,上面的代码发布在我的LibEx项目中的 GitHub 上ReflectionUtils

于 2013-06-06T15:54:30.573 回答
8

如前所述,Class.getDeclaredField(String)仅查看Class您调用它的字段。

如果要FieldClass层次结构中搜索 a,可以使用这个简单的函数:

/**
 * Returns the first {@link Field} in the hierarchy for the specified name
 */
public static Field getField(Class<?> clazz, String name) {
    Field field = null;
    while (clazz != null && field == null) {
        try {
            field = clazz.getDeclaredField(name);
        } catch (Exception e) {
        }
        clazz = clazz.getSuperclass();
    }
    return field;
}

private例如,这对于从超类中查找字段很有用。另外,如果你想修改它的值,你可以像这样使用它:

/**
 * Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
 */
public static void setField(Object object, String fieldName, Object value) throws Exception {
    Field field = getField(object.getClass(), fieldName);
    field.setAccessible(true);
    field.set(object, value);
}
于 2016-05-19T19:57:32.097 回答
5

public Field[] getFields() throws SecurityException

返回一个包含 Field 对象的数组,该数组反映了此 Class 对象表示的类或接口的所有可访问公共字段。返回的数组中的元素没有排序,也没有任何特定的顺序。如果类或接口没有可访问的公共字段,或者它表示数组类、原始类型或 void,则此方法返回长度为 0 的数组。

具体来说,如果此 Class 对象表示一个类,则此方法返回该类及其所有超类的公共字段。如果此 Class 对象表示一个接口,则此方法返回此接口及其所有超接口的字段。

此方法不反映数组类的隐式长度字段。用户代码应该使用类 Array 的方法来操作数组。


public Field[] getDeclaredFields() throws SecurityException

返回一个 Field 对象数组,反映由此 Class 对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承的字段。返回的数组中的元素没有排序,也没有任何特定的顺序。如果类或接口未声明任何字段,或者此 Class 对象表示原始类型、数组类或 void,则此方法返回长度为 0 的数组。


如果我需要所有父类的所有字段怎么办?需要一些代码,例如来自https://stackoverflow.com/a/35103361/755804

public static List<Field> getAllModelFields(Class aClass) {
    List<Field> fields = new ArrayList<>();
    do {
        Collections.addAll(fields, aClass.getDeclaredFields());
        aClass = aClass.getSuperclass();
    } while (aClass != null);
    return fields;
}
于 2016-06-20T07:31:39.073 回答
4

来自Java 反射教程

在此处输入图像描述

于 2019-04-09T01:06:14.227 回答