Java反射中的getFields和getDeclaredFields有什么区别

Bla*_*rai 174 java reflection

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

我读过,它getDeclaredFields允许您访问该类的所有字段,并且 getFields只返回公共字段.如果是这种情况,你为什么不经常使用getDeclaredFields

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

Joh*_*n B 240

getFields()

所有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;
}
Run Code Online (Sandbox Code Playgroud)

exclusiveParent提供一流的,以防止字段检索Object.null如果你想要这些Object领域,可能就是这样.

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

更新

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

  • 很好的答案,但应该注意的是,超类中的私有字段不能被当前类的实例用于"Field#get"和类似的方法.换句话说,这种方法*不允许当前类访问其超类的私有接口,就像典型编译所没有的那样. (8认同)
  • @Vulcan True,除非编写代码使用反射通过`setAccessible`更改范围并且没有安全管理器到位 (4认同)

Iva*_*nRF 7

如前所述,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;
}
Run Code Online (Sandbox Code Playgroud)

例如,这对于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);
}
Run Code Online (Sandbox Code Playgroud)


184*_*615 5

public Field[] getFields() throws SecurityException

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

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

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


public Field[] getDeclaredFields() throws SecurityException

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


如果我需要所有父类的所有字段怎么办?需要一些代码,例如来自/sf/answers/2457235301/

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;
}
Run Code Online (Sandbox Code Playgroud)