All topics
library
advanced

Reflection API

Inspect and modify class structure, fields, methods, and constructors at runtime — and know the costs.

Reflection reads and manipulates classes at runtime. It is how Spring, Hibernate, Jackson and JUnit work at all.

Reflection = X-ray vision. You can see inside any object (private fields), operate on it (invoke methods), and create copies (newInstance). But it's slower than just using the door (normal method calls).

Key Concepts

1
    Class<?> c = Class.forName("com.shop.Order");
    Object o = c.getDeclaredConstructor().newInstance();
2
    Method m = c.getMethod("total");
    double t = (double) m.invoke(o);
3
    Field f = c.getDeclaredField("id");
    f.setAccessible(true);           // reach a private field
    f.set(o, "A-1");
4
The four types you work with.
    Class<T>        the class itself
    Method          invoke(target, args)
    Field           get(target) / set(target, value)
    Constructor<T>  newInstance(args)
5
getMethod versus getDeclaredMethod is the distinction that causes bugs:
getMethodgetDeclaredMethod
6
    getMethod         public only, including inherited
    getDeclaredMethod any access, this class only -- not inherited
7
So a private method on a superclass needs a walk up the hierarchy, not one call.
8
setAccessible(true) defeats private, which is how a JSON library populates your fields without setters. It does not defeat the module system: a package that is not opens throws InaccessibleObjectException regardless.
setAccessible(true)privateopensInaccessibleObjectException
9
It costs real time.
    direct call      baseline
    reflection       roughly 5-50x slower
    MethodHandle     close to direct, after setup
    generated code   direct
10
The overhead is the access check on every call, the lack of inlining, and boxing every argument into an Object[].
Object[]
11
So cache what you look up. Resolving a Method once into a static field and invoking it repeatedly removes most of the cost; doing the lookup inside the loop is what makes reflection notorious.
Method
12
MethodHandle (Java 7) and VarHandle (Java 9) are the faster route for repeated access, because the access check happens once when the handle is created rather than on every call.
MethodHandleVarHandle
13
Reading annotations is the common, cheap use:
    if (m.isAnnotationPresent(Test.class)) run(m);
14
And the honest limitation. Reflection moves errors from compile time to runtime. A renamed field breaks at startup if you are lucky, and on one code path if you are not.
15
What the interviewer is probing.1. "What is the performance cost of reflection, and where does it come from?" Probing: whether you can explain rather than assert. Stalls: "It is slow." Moves up: roughly 5 to 50 times a direct call — access checks on every invocation, no inlining, and boxing every argument into an Object[].
16
2. "How do you reduce that cost?" Probing: caching, which most miss. Stalls: "You cannot." Moves up: resolve the Method once into a static field rather than looking it up in the loop, or use MethodHandle where the check happens at creation.
17
3. "getMethod versus getDeclaredMethod?" Probing: a distinction that causes real bugs. Stalls: "They are the same." Moves up: getMethod returns public methods including inherited ones; getDeclaredMethod returns any access but only on that class, so a private parent method needs a walk up the hierarchy.
18
4. "Does setAccessible(true) always work?" Probing: the module interaction. Stalls: "Yes, it bypasses everything." Moves up: not across module boundaries — a package that is not opened throws InaccessibleObjectException regardless.