Reflection提取的方法的执行时间是否更长?

时间:2015-01-12 02:43:17

标签: java performance reflection

众所周知,可以使用Reflection获取方法并通过返回的Method实例调用它。

然而,我的问题是;一旦它被Reflection提取并且我一遍又一遍地调用Method,方法的性能会比调用方法的正常方式慢吗?

例如:

import java.lang.reflect.Method;

public class ReflectionTest {

    private static Method test;

    public ReflectionTest() throws Exception {
        test = this.getClass().getMethod("testMethod", null);
    }

    public void testMethod() {
        //execute code here
    }

    public static void main(String[] args) throws Exception {
        ReflectionTest rt = new ReflectionTest();
        for (int i = 0; i < 1000; i++) {
            rt.test.invoke(null, null);
        }

        for (int i = 0; i < 1000; i++) {
            rt.testMethod();
        }
    }
}

我问这个是因为我正在创建一个事件系统,在注册监听器时会扫描注释。将这些方法放入映射中,然后在每次发生所需参数类型的事件时执行它们。我不知道这是否足够高效,例如游戏。

2 个答案:

答案 0 :(得分:3)

使用没有反射的方法快一个数量级。我测试了它像

public static void main(String[] args) throws Exception {
    ReflectionTest rt = new ReflectionTest();
    // Warm up
    for (int i = 0; i < 100; i++) {
        test.invoke(rt, null);
    }
    for (int i = 0; i < 100; i++) {
        rt.testMethod();
    }

    long start = System.nanoTime();
    for (int i = 0; i < 10000; i++) {
        test.invoke(rt, null);
    }
    long end = Math.abs((start - System.nanoTime()) / 1000);
    start = System.nanoTime();
    for (int i = 0; i < 10000; i++) {
        rt.testMethod();
    }
    long end2 = Math.abs((start - System.nanoTime()) / 1000);
    System.out.printf("%d %d%n", end, end2);
}

我还将test移到static字段,以便编译并运行

private static Method test;
static {
    try {
        test = ReflectionTest.class.getMethod("testMethod");
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    }
}

我与

获得了相当一致的差异(或输出一致)
4526 606

这表示跨10000次调用反射比直接调用慢约7倍。

答案 1 :(得分:2)

@Elliot Frisch的回答提供了确凿的 1 证据,表明使用Method.invoke()的速度较慢。

无论如何,你会期待这一点,因为反射版本涉及额外的工作; e.g。

  • 包含varags的数组的创建和初始化
  • 检查数组的长度,
  • 将数组中的参数从Object转换为相应的参数类型。

在某些情况下,JIT可能会优化这一点......


1 - 好......没有结论。该基准测试值得怀疑,因为它没有采取适当的措施来处理可能的JVM预热异常。