Java getFields() Method: Accessing Public Fields in Reflection
java getfields: Learn how Java's getFields() method returns public fields, including inherited ones, and how it differs from getDeclaredFields() in reflection.
java getfields requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
In Java reflection, the getFields() method on a Class object returns an array of Field objects representing all accessible public fields of the class and its inherited superclasses and interfaces. This method is often confused with getDeclaredFields(), which returns only fields declared directly in the class, regardless of access modifier. Understanding the distinction is essential when writing reflection-based utilities, serialization helpers, or framework code that inspects object structure at runtime.
What getFields() Returns
The Class.getFields() method returns an array containing Field objects for every public field that is accessible from the class, including fields inherited from superclasses and interfaces. A field is considered public if it has the public modifier and is a member of the class or one of its ancestors. For example, consider the following class hierarchy:
public interface Shape { double PI = 3.14159; } public class BaseShape { public String name; private int id; } public class Circle extends BaseShape implements Shape { public double radius; protected String color; }
Calling Circle.class.getFields() returns Field objects for name, radius, and PI. It does not return id because it is private, and it does not return color because it is protected. The inherited public field name from BaseShape is included, as is the public constant PI from the Shape interface.
getFields() vs getDeclaredFields()
The most common source of confusion is the difference between getFields() and getDeclaredFields(). The latter returns all fields declared directly in the class, regardless of access modifier, but it does not include inherited fields. The table below summarizes the key differences:
| Method | Returns public fields | Returns inherited fields | Returns private/protected fields |
|---|---|---|---|
getFields() | Yes | Yes | No |
getDeclaredFields() | No (all declared) | No | Yes |
In practice, getFields() is useful when you need to operate on the public API of an object, such as serializing only the public state. getDeclaredFields() is used when you need to access private fields, often after calling setAccessible(true).
Using getFields() to Inspect Public Fields
A typical use case for getFields() is to iterate over all public fields of an object and process them generically. For example, you might want to print the names and values of all public fields:
public static void printPublicFields(Object obj) { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getFields(); for (Field field : fields) { try { Object value = field.get(obj); System.out.println(field.getName() + " = " + value); } catch (IllegalAccessException e) { // The field is public, so this should not happen in normal use. e.printStackTrace(); } } }
The Field.get(Object) method returns the value of the field for the given object. Because getFields() only returns public fields, IllegalAccessException is unlikely, but it can still be thrown if the field is public but the caller's module does not have access (due to Java module system restrictions).
Accessing and Modifying Field Values
Beyond reading values, getFields() allows you to modify public fields via Field.set(Object, Object). This is straightforward when the field is not final. For example:
public static void setPublicField(Object obj, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException { Class<?> clazz = obj.getClass(); Field field = clazz.getField(fieldName); // throws NoSuchFieldException if not public field.set(obj, newValue); }
Note that getField(String) returns a single public field by name, including inherited ones. If the field is final, the set operation may fail with IllegalAccessException in many Java versions, depending on the target class and the underlying JVM behavior. This is a known limitation of reflection and should be handled carefully.
Performance and Reflection Cost
Reflection is inherently slower than direct field access because the JVM must perform runtime type checks, access checks, and method dispatch. The getFields() call itself is not the main performance bottleneck; it is a simple array lookup that returns precomputed metadata. The cost arises when you repeatedly call get() or set() on Field objects, especially in tight loops.
If you are using reflection in a performance-critical section, consider caching the Field objects after the first lookup. For example:
public class FieldCache { private static final Map<Class<?>, Map<String, Field>> CACHE = new ConcurrentHashMap<>(); public static Field getPublicField(Class<?> clazz, String name) throws NoSuchFieldException { Map<String, Field> fields = CACHE.computeIfAbsent(clazz, c -> { Map<String, Field> map = new HashMap<>(); for (Field f : c.getFields()) { map.put(f.getName(), f); } return map; }); Field field = fields.get(name); if (field == null) { throw new NoSuchFieldException(name); } return field; } }
This reduces the overhead of repeated getFields() calls, but the get() and set() operations still incur reflection cost. If possible, avoid reflection for high-frequency operations and use interfaces or direct access instead.
Common Pitfalls and Edge Cases
One common pitfall is assuming that getFields() returns fields in declaration order. The Java Language Specification does not guarantee any ordering, so you should not rely on the array order for logic. If order matters, sort the fields by name or use a custom annotation.
Another edge case is the handling of synthetic fields. Compiler-generated fields, such as those for inner class references, are not returned by getFields() because they are not public. Similarly, fields introduced by the JVM for lambda expressions are not part of the public API.
With the Java module system, a public field in a class that is not exported to the caller's module may not be accessible, even though getFields() returns it. In such cases, calling get() throws IllegalAccessException. This is a security feature that prevents reflection from bypassing module boundaries.
Choosing Between getFields() and getDeclaredFields()
The decision between getFields() and getDeclaredFields() depends on what you need to access. Use getFields() when you want to work only with the public API of an object, including inherited members. This is common in frameworks that serialize objects to JSON or XML, where only public properties should be exposed.
Use getDeclaredFields() when you need to access private or protected fields, such as in dependency injection containers or ORM tools that need to set fields without setters. Remember that getDeclaredFields() does not include inherited fields, so you may need to walk the class hierarchy manually if you need private fields from superclasses.
A practical rule of thumb: if you are writing code that should respect encapsulation and only interact with the public contract, use getFields(). If you are building a low-level utility that must manipulate internal state, use getDeclaredFields() and call setAccessible(true) where necessary, while being aware of the security implications.