Retrieving Class Objects
There are three primary ways to obtain a Class instance at runtime:
1. Class<?> clazz = Class.forName("java.util.ArrayList");
2. String text = "example";
Class<?> clazz = text.getClass();
3. Class<?> clazz = Integer.class; // Note the lowercase 'class'
Inspecting Class Fields
1. getFields():
Retrieves all public fields accessible within the class, including those inherited from superclasses.
2. getDeclaredFields():
Retrieves all fields declared within the class regardless of access modifier (public, private, protected), but excludes inherited fields.
Implementation Example:
Consider a BaseProfile class and a UserRecord class where UserRecord extends BaseProfile and overrides toString():
class BaseProfile{
public String fullName = "John Doe";
}
class UserRecord extends BaseProfile{
public int id;
private int creditScore;
@Override
public String toString() {
return "UserRecord{" +
"fullName=" + fullName +
", creditScore=" + creditScore +
'}';
}
}
(1) Using getFields() to accesss the public member id in UserRecord and the inherited public member fullName:
Class<?> userClazz = UserRecord.class;
// Retrieve public field "id":
System.out.println(userClazz.getField("id"));
// Retrieve inherited public field "fullName":
System.out.println(userClazz.getField("fullName"));
(2) Using getDeclaredField() to access the private member creditScore:
Class<?> userClazz = UserRecord.class;
System.out.println(userClazz.getDeclaredField("creditScore"));
(3) Creating an instance via newInstance() and accessing field values:
Field nameField = userClazz.getField("fullName");
System.out.println(nameField.get(userClazz.getDeclaredConstructor().newInstance()));
(4) Modifying private fields using setAccessible():
Field scoreField = userClazz.getDeclaredField("creditScore");
scoreField.setAccessible(true);
UserRecord record = (UserRecord) userClazz.getDeclaredConstructor().newInstance();
scoreField.set(record, 850);
// The setAccessible method bypasses Java access control checks.
// Normally, private or protected members are inaccessible,
// but setting this flag to true allows modification.
Invoking Methods Dynamically
Method getMethod(name, paramTypes): Retrieves a specific public method from the class or its superclass.Method getDeclaredMethod(name, paramTypes): Retrieves a specific method declared in the class regardless of visibility, excluding superclass methods.Method[] getMethods(): Retrieves all public methods available to the class.Method[] getDeclaredMethods(): Retrieves all methods declared in the class, excluding inherited ones.
Implementation Example:
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
String input = "hello";
Method toUpper = String.class.getMethod("toUpperCase");
System.out.println(toUpper.invoke(input));
}
}
// Output: HELLO
For static methods, the object instance parameter is null:
Method m = Integer.class.getMethod("valueOf", String.class);
System.out.println(m.invoke(null, "100"));
// Output: 100
Accessing Constructors
getConstructor(paramTypes): Retrieves a specific public constructor.getDeclaredConstructor(paramTypes): Retrieves a specific constructor regradless of visibility.getConstructors(): Retrieves all public constructors.getDeclaredConstructors(): Retrieves all constructors declared in the class.
Note: Invoking non-public constructors requires calling setAccessible(true) first, though this operation may fail under certain security managers.
Dynamic Command Execution
Executing system commends directly via Java:
// Windows: java.lang.Runtime.getRuntime().exec("cmd /c start notepad");
// MacOS: java.lang.Runtime.getRuntime().exec("open -a TextEdit");
Executing system commands via Reflection:
// Windows:
Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null)
.getClass().getMethod("exec", String.class).invoke(Runtime.getRuntime(), "cmd /c start notepad");
// MacOS:
Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null)
.getClass().getMethod("exec", String.class).invoke(Runtime.getRuntime(), "open -a TextEdit");
Altering Final Modifiers
In a Config class, assume there is a final integer variable STATIC_ID = 666:
The following code demonstrates modifying and printing this value:
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> configClass = Class.forName("com.example.Config");
Config config = (Config) configClass.getDeclaredConstructor().newInstance();
Field field = configClass.getDeclaredField("STATIC_ID");
field.setAccessible(true);
field.setInt(config, 999);
System.out.println(field.get(config));
}
}
// Output:
// 999