Understanding Reflection in Java
Reflection is a powerful feature in Java that enables runtime examination and manipulation of classes, methods, and fields. It allows programs to dynamically inspect and modify their own structure and behavior, providing capabilities similar to function pointers in other programming languages.
Core Reflection Concepts
The reflection API provides tools to:
- Analyze class structures during program execution
- Inspect objects and they properties
- Manipulate arrays programmatically
- Work with Method objects for dynamic invocation
Three Approaches to Obtain Class Objects
Using Class.forName() with Fully Qualified Name
Class<?> targetClass = Class.forName("java.util.ArrayList");
This approach is commonly used with configuration files where class names are specified as strings.
Using .class Syntax
Class<String> stringClass = String.class;
This method is typically employed for parameter passing and compile-time class references.
Using getClass() on Object Instances
String example = "test";
Class<?> runtimeClass = example.getClass();
This retrieves the runtime class of an existing object instance.
Working with Class Metadata
Accessing Field Information
// Get public fields
Field[] publicFields = targetClass.getFields();
// Get all declared fields including private ones
Field[] allFields = targetClass.getDeclaredFields();
Retrieving Constructor Details
// Access public constructors
Constructor<?>[] publicConstructors = targetClass.getConstructors();
// Access all constructors including private ones
Constructor<?>[] allConstructors = targetClass.getDeclaredConstructors();
Examining Method Information
// Retrieve public methods
Method[] publicMethods = targetClass.getMethods();
// Retrieve all declared methods
Method[] declaredMethods = targetClass.getDeclaredMethods();
Additional Class Information Methods
int modifiers = targetClass.getModifiers();
String fullName = targetClass.getName();
String simpleName = targetClass.getSimpleName();
Package classPackage = targetClass.getPackage();
Bypassing Access Restrictions
Field privateField = targetClass.getDeclaredField("privateFieldName");
privateField.setAccessible(true);
Practical Field Operations
Object fieldValue = fieldInstance.get(targetObject);
fieldInstance.set(targetObject, newValue);
Constructor Operations
Object newInstance = constructor.newInstance(arguments);
Method Invocation
Object result = methodInstance.invoke(targetObject, parameters);
Implementation Example: Dynamic Class Loader
Configuration file (config.properties):
targetClass=com.example.Processor
targetMethod=execute
Dynamic reflection implementation:
public class DynamicExecutor {
public static void main(String[] args) throws Exception {
// Load configuration
Properties config = new Properties();
ClassLoader loader = DynamicExecutor.class.getClassLoader();
InputStream configStream = loader.getResourceAsStream("config.properties");
config.load(configStream);
// Extract configuration values
String className = config.getProperty("targetClass");
String methodName = config.getProperty("targetMethod");
// Load and instantiate class
Class<?> loadedClass = Class.forName(className);
Object instance = loadedClass.newInstance();
// Execute specified method
Method targetMethod = loadedClass.getMethod(methodName);
targetMethod.invoke(instance);
}
}
This implementation demonstrates how reflection enables dynamic class loading and method execution based on external configuration, providing flexibility in application behavior without code modifications.