← Back to Advanced Java Course | Chapter 11: Advanced & Security | Lesson 1 of 19

Java Reflection API

Accessing Class Objects

Reflection lets you inspect a class's characteristics at runtime -- its fields, superclass references, interfaces, and constructor metadata -- even for classes your code didn't know about at compile time, which is what powers frameworks like Spring and Hibernate under the hood.

Example: Accessing Class Objects

java
public class Main {
	static class Sample { int x; }
	public static void main(String[] args) {
		Class<?> clazz = Sample.class;
		System.out.println(clazz.getName() + " fields: " + clazz.getDeclaredFields().length);
	}
}

Accessing and Modifying Private Fields

Using reflection, you can bypass a field's normal access controls (via setAccessible(true)) to inspect or override private variables from outside the class. This is powerful but should be used sparingly outside of frameworks and tests, since it breaks the encapsulation the class author intended.

Example: Accessing and Modifying Private Fields

java
import java.lang.reflect.Field;
public class Main {
	static class Secret { private int value = 42; }
	public static void main(String[] args) throws Exception {
		Secret s = new Secret();
		Field field = Secret.class.getDeclaredField("value");
		field.setAccessible(true); // bypasses normal access control
		System.out.println(field.getInt(s));
		field.setInt(s, 100);
		System.out.println(field.getInt(s));
	}
}

Calling Methods Dynamically

You can look up and invoke methods dynamically by their string name, passing the target object and runtime arguments to Method.invoke(), which is how frameworks call your annotated methods without knowing their exact signatures at compile time.

Example: Calling Methods Dynamically

java
import java.lang.reflect.Method;
public class Main {
	static class Greeter { String greet(String name) { return "Hello, " + name; } }
	public static void main(String[] args) throws Exception {
		Method method = Greeter.class.getMethod("greet", String.class);
		Object result = method.invoke(new Greeter(), "Riya"); // looked up by name, called dynamically
		System.out.println(result);
	}
}

Instantiating Classes Dynamically

Constructor reflection lets you instantiate objects at runtime without ever writing an explicit 'new ClassName()' in your code, by looking up a Constructor object and calling newInstance() -- essential for frameworks that create objects based on configuration or annotations rather than hardcoded types.

Example: Instantiating Classes Dynamically

java
import java.lang.reflect.Constructor;
public class Main {
	static class Point { int x; Point(int x) { this.x = x; } }
	public static void main(String[] args) throws Exception {
		Constructor<Point> ctor = Point.class.getConstructor(int.class);
		Point p = ctor.newInstance(5); // no explicit "new Point(5)" in this code
		System.out.println(p.x);
	}
}

Performance Impact of Reflection

Reflective calls bypass many JIT compiler optimizations that direct method calls benefit from, so they run measurably slower than ordinary programmatic calls. This is usually fine for one-off framework setup work, but worth avoiding inside performance-critical hot loops.

Example: Performance Impact of Reflection

java
import java.lang.reflect.Method;
public class Main {
	static int square(int n) { return n * n; }
	public static void main(String[] args) throws Exception {
		Method method = Main.class.getDeclaredMethod("square", int.class);
		long start = System.nanoTime();
		for (int i = 0; i < 1000; i++) method.invoke(null, i); // measurably slower than a direct call
		System.out.println("Reflective calls took " + (System.nanoTime() - start) + "ns");
	}
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.