Exploring Java Reflection Capabilities and Usage

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

  1. Method getMethod(name, paramTypes): Retrieves a specific public method from the class or its superclass.
  2. Method getDeclaredMethod(name, paramTypes): Retrieves a specific method declared in the class regardless of visibility, excluding superclass methods.
  3. Method[] getMethods(): Retrieves all public methods available to the class.
  4. 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

  1. getConstructor(paramTypes): Retrieves a specific public constructor.
  2. getDeclaredConstructor(paramTypes): Retrieves a specific constructor regradless of visibility.
  3. getConstructors(): Retrieves all public constructors.
  4. 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

Tags: java reflection introspection runtime Security

Posted on Fri, 08 May 2026 08:32:52 +0000 by MikeSnead