java getDeclaredFields: Inspecting Class Fields
java getdeclaredfields: Learn how to use Java's getDeclaredFields() to inspect class fields at runtime, including private and protected members, with practical example...
java getdeclaredfields requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need to inspect the fields of a class at runtime, java.lang.Class.getDeclaredFields() is the method that returns an array of Field objects representing all fields declared by the class, regardless of access modifier. Unlike getFields(), it does not include inherited fields. This method is a cornerstone of reflection in Java, enabling tools like ORMs, serializers, and testing frameworks to discover and manipulate object state dynamically.
What getDeclaredFields() Returns
The getDeclaredFields() method returns an array of Field objects that correspond to every field declared directly in the class or interface. This includes private, protected, package-private, public, and even synthetic fields generated by the compiler. The array does not include fields inherited from superclasses or interfaces. The order of the fields in the array is not specified by the Java Language Specification and may vary between JVM implementations, so you should not rely on any particular sequence.
For example, consider the following class:
public class Person { private String name; public int age; protected boolean active; static final double RATE = 0.5; }
Calling Person.class.getDeclaredFields() returns an array with four Field objects: name, age, active, and RATE. Each Field object provides metadata about the field, such as its name, type, modifiers, and annotations.
Basic Usage Example
Here is a minimal program that prints the names and types of all declared fields:
import java.lang.reflect.Field; public class FieldInspector { public static void main(String[] args) { Field[] fields = Person.class.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName() + " - " + field.getType().getSimpleName()); } } }
This code retrieves the Field array and iterates over it, printing each field's name and simple type name. The output will include name - String, age - int, active - boolean, and RATE - double. Notice that RATE is included even though it is static and final; getDeclaredFields() does not filter by modifiers.
getDeclaredFields() vs getFields()
The most common point of confusion is the difference between getDeclaredFields() and getFields(). The table below summarizes the key distinctions:
| Method | Access Modifiers | Inherited Fields | Typical Use Case |
|---|---|---|---|
getDeclaredFields() | All (public, protected, package, private) | No | Full inspection of class's own fields |
getFields() | Public only | Yes | Accessing public API fields |
Use getDeclaredFields() when you need to know about every field that the class itself declares, regardless of visibility. This is essential for frameworks that need to serialize or map the complete state of an object. Use getFields() when you only care about the public contract, including fields inherited from superclasses.
Accessing and Modifying Private Fields
Reflection allows you to read and write private fields, but you must first call setAccessible(true) on the Field object to suppress Java's access control checks. For example:
Field nameField = Person.class.getDeclaredField("name"); nameField.setAccessible(true); Person person = new Person(); nameField.set(person, "Alice"); String name = (String) nameField.get(person);
This works because setAccessible(true) tells the JVM to skip the access checks for that field. However, this is not a free pass in all environments. Starting with Java 9, the module system may still prevent access if the field's declaring class is in a different module and that module does not opens the package to your module. In such cases, you will get an InaccessibleObjectException at runtime.
Performance and Caching Considerations
Reflection is inherently slower than direct field access because the JVM must perform dynamic lookups and type checks. The overhead is significant when calling getDeclaredFields() repeatedly, as each call allocates a new array and Field objects. If you need to inspect the same class multiple times, cache the result:
private static final Field[] PERSON_FIELDS = Person.class.getDeclaredFields();
This avoids repeated reflection lookups. For even better performance, consider using MethodHandles or VarHandle, which provide more efficient ways to access fields once the lookup is done. However, for most applications, caching the Field array is sufficient.
Security and Module System Constraints
The Java Platform Module System (JPMS) introduced in Java 9 imposes strong encapsulation. By default, a module cannot access private fields of classes in other modules, even with setAccessible(true). The target module must explicitly opens its package to the caller module. For example, if your code is in module app and you want to reflect on a class in module library, the library module must declare opens com.example.library to app; in its module-info.java. This is a deliberate security improvement to prevent unauthorized reflection.
In a non-modular environment (classpath), setAccessible(true) generally works without restrictions, but it can still trigger SecurityException if a security manager is installed. The security manager is deprecated in recent Java versions but may still be present in legacy applications.
Common Use Cases and Limitations
getDeclaredFields() is widely used in serialization libraries (e.g., Jackson, Gson), ORM tools (e.g., Hibernate), and testing frameworks (e.g., JUnit) to discover and manipulate object state. It allows these tools to work with classes without requiring explicit configuration.
However, there are important limitations:
- Inherited fields are not included. If you need all fields from the entire class hierarchy, you must walk up the superclass chain manually using
getSuperclass()and callgetDeclaredFields()on each class. - Synthetic fields (compiler-generated, such as those for inner class references) are included. You may need to filter them using
field.isSynthetic(). - Enum constants are also included as fields. If you are processing a field list for an enum, you might want to exclude them.
- Order is not guaranteed. Do not rely on the order of fields for any logic that depends on declaration order.
Despite these limitations, getDeclaredFields() remains a fundamental tool for runtime introspection. Understanding its behavior and constraints helps you write robust reflection-based code that works across both classpath and module-based applications.