Fundamentals 11 min read

Does Java Reflection Really Cause Performance Issues? Empirical Tests and Analysis

This article investigates whether Java reflection impacts performance by conducting systematic benchmarks that compare direct method/field access with reflective calls, analyzing the measured overhead, identifying the costly reflection operations, and offering practical guidelines to mitigate any performance penalties.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Does Java Reflection Really Cause Performance Issues? Empirical Tests and Analysis

After explaining the implementation of reflection, the author was asked how reflection actually affects performance, prompting a deeper investigation. While it is widely known that reflection can degrade performance, the article provides concrete measurements and reasoning.

Does reflection really have a performance problem?

Using the demo from the previous article, the author amplified the issue by testing a range of invocation counts (1‑1,000,000) and averaging multiple runs for each scenario: direct method call, reflective method call, direct field access via instance, and reflective field access.

Test code:

public class ReflectionPerformanceActivity extends Activity {
    private TextView mExecuteResultTxtView = null;
    private EditText mExecuteCountEditTxt = null;
    private Executor mPerformanceExecutor = Executors.newSingleThreadExecutor();
    private static final int AVERAGE_COUNT = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reflection_performance_layout);
        mExecuteResultTxtView = (TextView)findViewById(R.id.executeResultTxtId);
        mExecuteCountEditTxt = (EditText)findViewById(R.id.executeCountEditTxtId);
    }

    public void onClick(View v) {
        switch(v.getId()){
            case R.id.executeBtnId:{
                execute();
            }
            break;
            default:{
            }
            break;
        }
    }

    private void execute(){
        mExecuteResultTxtView.setText("");
        mPerformanceExecutor.execute(new Runnable(){
            @Override
            public void run(){
                long costTime = 0;
                int executeCount = Integer.parseInt(mExecuteCountEditTxt.getText().toString());
                long reflectMethodCostTime=0,normalMethodCostTime=0,reflectFieldCostTime=0,normalFieldCostTime=0;
                updateResultTextView(executeCount + "毫秒耗时情况测试");
                for(int index = 0; index < AVERAGE_COUNT; index++){
                    updateResultTextView("第 " + (index+1) + " 次");
                    costTime = getNormalCallCostTime(executeCount);
                    reflectMethodCostTime += costTime;
                    updateResultTextView("执行直接调用方法耗时:" + costTime + " 毫秒");
                    costTime = getReflectCallMethodCostTime(executeCount);
                    normalMethodCostTime += costTime;
                    updateResultTextView("执行反射调用方法耗时:" + costTime + " 毫秒");
                    costTime = getNormalFieldCostTime(executeCount);
                    reflectFieldCostTime += costTime;
                    updateResultTextView("执行普通调用实例耗时:" + costTime + " 毫秒");
                    costTime = getReflectCallFieldCostTime(executeCount);
                    normalFieldCostTime += costTime;
                    updateResultTextView("执行反射调用实例耗时:" + costTime + " 毫秒");
                }
                updateResultTextView("执行直接调用方法平均耗时:" + reflectMethodCostTime/AVERAGE_COUNT + " 毫秒");
                updateResultTextView("执行反射调用方法平均耗时:" + normalMethodCostTime/AVERAGE_COUNT + " 毫秒");
                updateResultTextView("执行普通调用实例平均耗时:" + reflectFieldCostTime/AVERAGE_COUNT + " 毫秒");
                updateResultTextView("执行反射调用实例平均耗时:" + normalFieldCostTime/AVERAGE_COUNT + " 毫秒");
            }
        });
    }

    private long getReflectCallMethodCostTime(int count){
        long startTime = System.currentTimeMillis();
        for(int index = 0 ; index < count ; index++){
            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
            try{
                Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);
                setmLanguageMethod.setAccessible(true);
                setmLanguageMethod.invoke(programMonkey, "Java");
            }catch(IllegalAccessException e){e.printStackTrace();}
            catch(InvocationTargetException e){e.printStackTrace();}
            catch(NoSuchMethodException e){e.printStackTrace();}
        }
        return System.currentTimeMillis()-startTime;
    }

    private long getReflectCallFieldCostTime(int count){
        long startTime = System.currentTimeMillis();
        for(int index = 0 ; index < count ; index++){
            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
            try{
                Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");
                ageField.set(programMonkey, "Java");
            }catch(NoSuchFieldException e){e.printStackTrace();}
            catch(IllegalAccessException e){e.printStackTrace();}
        }
        return System.currentTimeMillis()-startTime;
    }

    private long getNormalCallCostTime(int count){
        long startTime = System.currentTimeMillis();
        for(int index = 0 ; index < count ; index++){
            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
            programMonkey.setmLanguage("Java");
        }
        return System.currentTimeMillis()-startTime;
    }

    private long getNormalFieldCostTime(int count){
        long startTime = System.currentTimeMillis();
        for(int index = 0 ; index < count ; index++){
            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
            programMonkey.mLanguage = "Java";
        }
        return System.currentTimeMillis()-startTime;
    }

    private void updateResultTextView(final String content){
        ReflectionPerformanceActivity.this.runOnUiThread(new Runnable(){
            @Override
            public void run(){
                mExecuteResultTxtView.append(content);
                mExecuteResultTxtView.append("
");
            }
        });
    }
}

Test results: The measurements show that reflection indeed introduces a performance penalty. When the number of reflective calls stays below about 100, the overhead is negligible; beyond that, the difference becomes significant.

Direct instance field access is the fastest.

Direct method invocation is about 1.4× slower than direct field access.

Reflective field access is roughly 3.75× slower than direct field access.

Reflective method invocation is the slowest, about 6.2× slower than direct field access.

Where does reflection become slow?

Source tracing reveals that all four test methods instantiate ProgramMonkey, so object creation is not the cause of the variance. The extra cost stems from the reflective operations themselves: getMethod / getDeclaredField, invoke, and set. Subsequent tests isolate these calls.

Additional benchmarks demonstrate that getMethod and getDeclaredField incur more overhead than the actual invoke and set calls, and the relative cost stabilizes as the iteration count grows.

The author hypothesizes that the overhead arises from runtime class checks, security validations, and the need to locate the target members in the JVM, possibly involving JNI transitions to native code (similar to System.out.println).

How to avoid reflection‑induced performance problems?

Based on the findings, the following guidelines are recommended:

Avoid excessive use of reflection; heavy reflective usage can degrade performance.

Prefer direct instance field access over reflective method calls when possible, as it is considerably faster.

Postscript

The current tests are not exhaustive, but they clearly indicate that reflection can cause performance issues. Future work may explore:

Impact of frequent native method calls.

Cost of numerous conditional checks within a single method.

Effect of class complexity on reflective performance.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaPerformanceReflectionBenchmark
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.