Why Java Reflection Slows Down Your Apps and How to Speed It Up
This article examines Java reflection's advantages and drawbacks, analyzes its core API methods, benchmarks its performance against regular calls, explains why it is slower, and demonstrates how using Hutool's ReflectUtil can dramatically improve execution speed.
Introduction
Reflection allows dynamic class loading, method invocation, and field access in Java. It is used by frameworks such as Spring, MyBatis, and JDBC. While flexible, misuse can increase code complexity and reduce performance.
Reflection API Overview
Core classes are in java.lang.reflect. Important Class methods include forName, newInstance, getMethod, and getDeclaredMethod.
getMethod
The execution flow consists of three steps: (1) checkMemberAccess for visibility checking, (2) retrieve the Method object, (3) create a copy of the method for invocation.
getDeclaredMethod
Same three steps, but can retrieve private methods; getMethod only returns public methods.
invoke
Invocation also follows three steps: (1) access check, (2) obtain a MethodAccessor implementation ( DelegatingMethodAccessorImpl, MethodAccessorImpl, NativeMethodAccessorImpl), (3) call MethodAccessor.invoke.
Performance Comparison
A benchmark creates 10,000 threads and measures time for four scenarios: reflection‑based method call, reflection‑based field access, direct method call, and direct field access. Sample code:
package com.example.system.factory;
import com.example.system.domain.ReflectEntity;
import lombok.SneakyThrows;
import java.lang.reflect.Method;
public class ReflectTest {
private long testReflectMethod() {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(() -> {
try {
Class<?> c = Class.forName("com.example.system.domain.ReflectEntity");
Object obj = c.newInstance();
Method m = c.getDeclaredMethod("getReflectMethod");
m.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
});
t.start();
}
return System.currentTimeMillis() - start;
}
// similar methods for field reflection, normal method, normal field omitted
public static void main(String[] args) {
ReflectTest rt = new ReflectTest();
System.out.println("reflect method: " + rt.testReflectMethod());
// prints for other tests
}
}Results show that reflection‑based calls take the longest time, confirming the overhead.
Why Reflection Is Slow
Visibility check is performed on every invocation. MethodAccessor.invoke validates argument types each time.
Argument packaging and unboxing add extra work.
Improving Performance with Hutool
Hutool’s ReflectUtil provides a thin wrapper that caches reflective metadata, reducing overhead. Example usage:
import cn.hutool.core.util.ReflectUtil;
private long testReflectUtil() {
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
Thread t = new Thread(() -> {
ReflectEntity e = ReflectUtil.newInstance(ReflectEntity.class);
ReflectUtil.setFieldValue(e, "name", "changeLxlxxx");
ReflectUtil.invoke(e, "getReflectMethod");
});
t.start();
}
return System.currentTimeMillis() - start;
}Benchmarking shows the Hutool version runs in less than half the time of native JDK reflection.
Conclusion
Native Java reflection incurs significant performance penalties, especially in high‑frequency scenarios. Understanding its internal steps helps developers replace it with faster utilities such as Hutool’s ReflectUtil, achieving measurable speed improvements.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
