243

I'm a little confused about the difference between the getFields method and the getDeclaredFields method when using Java reflection.

I read that getDeclaredFields gives you access to all the fields of the class and that getFields only returns public fields. If this is the case, why wouldn't you just always use getDeclaredFields?

Can someone please elaborate on this, and explain the difference between the two methods, and when/why you would want to use one over the other?

Flow
  • 23,572
  • 15
  • 99
  • 156
BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156
  • 8
    `getField` can get a field inherited from a superclass but `getDeclaredField` cannot. `getDeclaredField` restrict itself to the class you call the function on. – user2336315 Jun 06 '13 at 15:53
  • 3
    @user2336315 that is correct, however `getField` cannot access private members – Madbreaks Aug 22 '16 at 21:18

4 Answers4

317

getFields()

All the public fields up the entire class hierarchy.

getDeclaredFields()

All the fields, regardless of their accessibility but only for the current class, not any base classes that the current class might be inheriting from.

To get all the fields up the hierarchy, I have written the following function:

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

The exclusiveParent class is provided to prevent the retrieval of fields from Object. It may be null if you DO want the Object fields.

To clarify, Lists.newArrayList comes from Guava.

Update

FYI, the above code is published on GitHub in my LibEx project in ReflectionUtils.

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
John B
  • 32,493
  • 6
  • 77
  • 98
  • 8
    Great answer, but it should be noted that private fields in superclasses cannot be used by instances of the current class for `Field#get` and similar methods. In other words, this approach *does not* allow the current class access to the private interface of its superclass, in the same way the typical compilation does not. – FThompson Jun 06 '13 at 16:07
  • 4
    @Vulcan True unless the code is written to use reflection to change the scope via `setAccessible` and there is no Security Manager in place – John B Jun 06 '13 at 16:11
  • Slight nit, should be "(no matter the accessibility)" not "(no matter the scope)". All fields have the same scope, namely, the [class's body](http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3). – yshavit Jun 06 '13 at 16:25
  • @JohnB Does `setAccessible` allow a subclass to call the private members of a superclass? I've never considered it before, as I've only used it in the context of making private members in the current class accessible. – FThompson Jun 06 '13 at 16:29
  • @Vulcan Yes. From the point of reflection, a `Field` is a `Field` no matter where you are accessing it from (assuming no security manager). So class `A` can manipulate private fields of class `B` even if there is NO relationship between the two. – John B Jun 06 '13 at 16:31
  • @JohnB Interesting, thanks. I wonder if that makes for any unintended side effects when a subclass has a private field with the same type and name as a private field in its superclass; I'll have to test it out later when I can. – FThompson Jun 06 '13 at 16:56
  • 1
    It would not. Since `private` fields can only be accessed via `getDeclaredFields` which is class-specific. Each field (even with same type and name) would be distinct `Field` instances. – John B Jun 06 '13 at 17:00
  • @Nil Next time please do more research before assuming something doesn't compile. Or post a comment asking about it. `Lists.newArrayList` does compile with the appropriate import and saves several lines of code. – John B Oct 22 '13 at 10:35
  • @JohnB would you mind if I proposed to include your function in Apache Commons Lang? The latest version of org.apache.commons.lang.reflect.FieldUtils doesn't seem to have this yet. It would make more sense than copy pasting this code around ;-) – dSebastien Nov 20 '14 at 09:39
  • @dSebastien Sure. Also it is located here at GitHub. https://github.com/dancerjohn/LibEx Specifically - https://github.com/dancerjohn/LibEx/blob/master/libex/src/main/java/org/libex/reflect/ReflectionUtils.java – John B Nov 20 '14 at 11:42
13

From Java Reflection tutorials:

enter image description here

Somnath Musib
  • 3,548
  • 3
  • 34
  • 47
8

As already mentioned, Class.getDeclaredField(String) only looks at the fields from the Class in which you call it.

If you want to search a Field in the Class hierarchy, you can use this simple function:

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

This is useful to find a private field from a superclass, for example. Also, if you want to modify its value, you can use it like this:

/**
 * 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);
}
IvanRF
  • 7,115
  • 5
  • 47
  • 71
  • slight modification to still throw error if not found at all `try try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }` – Sven Dhaens Aug 31 '17 at 09:33
5

public Field[] getFields() throws SecurityException

Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface has no accessible public fields, or if it represents an array class, a primitive type, or void.

Specifically, if this Class object represents a class, this method returns the public fields of this class and of all its superclasses. If this Class object represents an interface, this method returns the fields of this interface and of all its superinterfaces.

The implicit length field for array class is not reflected by this method. User code should use the methods of class Array to manipulate arrays.


public Field[] getDeclaredFields() throws SecurityException

Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface declares no fields, or if this Class object represents a primitive type, an array class, or void.


And what if I need all fields from all parent classes? Some code is needed, e.g. from 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;
}
Community
  • 1
  • 1
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127