1. Retrieving information about fields
How getFields() and getDeclaredFields() differ
In Java, each class has fields — variables declared inside the class. With reflection, we can learn their names, types, access modifiers (public/private), and also access them at runtime. The main entry point is a Class<?> object.
Key Class methods for working with fields:
| Method | What it returns |
|---|---|
|
An array of all public fields of the class, its parents, and interfaces |
|
An array of all fields declared in this class |
Analogy: getFields() is like a tour of the showrooms only (public), while getDeclaredFields() also includes the back rooms (private, protected, package-private).
Example: print all fields of a class
Suppose we have the class:
public class Person {
public String name;
private int age;
protected String email;
}
Let’s get information about the fields:
import java.lang.reflect.Field;
Class<?> clazz = Person.class;
// All public fields (including inherited)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
// All declared fields (including private, only those of this class)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
Output:
Public fields:
name : String
Declared fields:
name : String
age : int
email : String
How to get a field’s modifiers?
Each field (Field) has modifiers (public/private/protected, static, final, etc.). You can get them via getModifiers() and convert to a string with Modifier:
import java.lang.reflect.Modifier;
for (Field field : clazz.getDeclaredFields()) {
int mods = field.getModifiers();
System.out.println(field.getName() + " : " + Modifier.toString(mods));
}
2. Retrieving information about methods
Methods getMethods() and getDeclaredMethods()
Methods are actions an object can perform. With reflection, you can learn what methods a class has, their parameters, return types, modifiers, and annotations.
| Method | What it returns |
|---|---|
|
All public methods of the class and its parents (including Object) |
|
All methods declared in this class (including private) |
Example: print all methods of a class
import java.lang.reflect.Method;
System.out.println("Public methods:");
for (Method method : clazz.getMethods()) {
System.out.println(method.getName());
}
System.out.println("\nDeclared methods:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName());
}
Output (for Person):
Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait
Declared methods:
(none, if Person doesn't declare its own methods)
Let’s add a method to Person:
public class Person {
public String name;
private int age;
protected String email;
public void sayHello() {
System.out.println("Hi!");
}
}
Now getDeclaredMethods() will include it as well.
How to get a method’s parameters and return type?
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(Modifier.toString(method.getModifiers()) + " ");
System.out.print(method.getReturnType().getSimpleName() + " ");
System.out.print(method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Output:
public void sayHello();
3. Retrieving information about constructors
Constructors are special methods used to create objects.
| Method | What it returns |
|---|---|
|
All public constructors |
|
All constructors declared in the class |
Example: print all constructors of a class
import java.lang.reflect.Constructor;
System.out.println("Constructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
If the class declares only the default constructor, it will be printed as well.
4. Annotations: how to learn what a class, method, or field is marked with
Annotations are special markers that can be attached to classes, methods, fields, and parameters. With reflection, you can find out what annotations an element has.
Retrieving annotations
- For a class: clazz.getAnnotations()
- For a method: method.getAnnotations()
- For a field: field.getAnnotations()
Example: check for the @Deprecated annotation
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is @Deprecated");
}
}
Example: print all annotations of a class
for (var annotation : clazz.getAnnotations()) {
System.out.println(annotation);
}
5. Practice: a mini program to analyze a class structure
Let’s put it all together and write a small utility that prints a class’s structure by its name: fields, methods, constructors, and annotations.
Code example: ClassInspector
import java.lang.reflect.*;
import java.util.Scanner;
public class ClassInspector {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the fully qualified class name (for example, java.util.ArrayList): ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("\n== Class: " + clazz.getName() + " ==");
// Class annotations
System.out.println("Annotations:");
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(" " + annotation);
}
// Fields
System.out.println("\nFields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(field.getModifiers())
+ " " + field.getType().getSimpleName()
+ " " + field.getName());
}
// Methods
System.out.println("\nMethods:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(" " + Modifier.toString(method.getModifiers())
+ " " + method.getReturnType().getSimpleName()
+ " " + method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
// Constructors
System.out.println("\nConstructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(" " + Modifier.toString(constructor.getModifiers())
+ " " + clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
}
}
How does it work?
- The user enters a fully qualified class name (for example, "java.util.ArrayList" or their own class).
- The program loads the class dynamically and prints its annotations, fields, methods, and constructors.
- Try it on standard JDK classes — you’ll see how much interesting stuff is inside!
6. Useful nuances and visualization
Visual diagram: what you can learn about a class via reflection
graph TD
A[Class<?>] --> B["getFields/getDeclaredFields"]
A --> C[getMethods/getDeclaredMethods]
A --> D[getConstructors/getDeclaredConstructors]
A --> E[getAnnotations]
B --> F[Field: type, name, modifiers]
C --> G[Method: return type, parameters]
D --> H[Constructor: parameters]
E --> I["Annotation[]"]
Table: where to find the information
| What we want to know | How to get it via reflection |
|---|---|
| All public fields | |
| All declared fields | |
| All public methods | |
| All declared methods | |
| All public constructors | |
| All declared constructors | |
| Class annotations | |
| Method/field annotations | |
| Modifiers | |
7. Common mistakes when working with reflection
Error #1: Confusing getFields() and getDeclaredFields().
If you’re looking for private fields, use getDeclaredFields() rather than getFields(). The former returns all fields declared in the class, while the latter returns only public ones (including inherited!).
Error #2: Not handling checked exceptions.
Many reflection methods throw exceptions (for example, ClassNotFoundException or SecurityException). Don’t forget to handle them or declare them in the method signature.
Error #3: Ignoring access modifiers.
Access to private fields and methods is only possible after calling setAccessible(true); otherwise you’ll get IllegalAccessException. Example:
Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // Open access to a private field
int value = (int) field.get(person);
Error #4: Expecting to see only your own methods/fields.
getMethods() and getFields() return public members not only of the current class but also of all its parents, including Object. This may be surprising if you expect to see only what you wrote yourself.
Error #5: Checking for annotations incorrectly.
Use isAnnotationPresent() to check for a specific annotation instead of iterating over the annotations array unnecessarily.
GO TO FULL VERSION