Java反射方法调用比Fields更快地产生结果?

时间:2011-01-04 11:38:34

标签: java performance reflection

我对一些代码进行了微基准测试(请保持良好状态)并遇到了这个难题:使用反射读取字段时,调用getter方法比读取字段更快。

简单测试类:

private static final class Foo {
    public Foo(double val) {
        this.val = val;
    }
    public double getVal() { return val; }
    public final double val; // only public for demo purposes
}

我们有两个想法:

Method m = Foo.class.getDeclaredMethod("getVal", null);
Field  f = Foo.class.getDeclaredField("val");

现在我在循环中调用两个反射,在方法上调用invoke,在字段上调用get。完成第一次运行以预热VM,第二次运行以10M次迭代完成。 方法调用始终快30%,但为什么?请注意,循环中调用了getDeclaredMethod和getDeclaredField 。它们被调用一次并在循环中的同一个对象上执行。

我还尝试了一些小的变化:使该字段非最终,传递,非公开等。所有这些组合导致统计上相似的性能。

编辑:这是在WinXP,Intel Core2 Duo,Sun JavaSE版本1.6.0_16-b01上运行,在jUnit4和Eclipse下运行。

3 个答案:

答案 0 :(得分:3)

我有根据的猜测是如何实现getDeclaredField和getDeclaredMethod:每次调用它时,getDeclaredField都必须检查变量的类型和大小,以便返回实际的对象或基本类型,getDeclaredMethod会将指针返回到一个相同的方法,静态处理所有其余的方法。

修改

我的解释类似:每个类只在内存中包含一次方法,而每个对象实例可以有不同的属性值。当您通过执行方法调用(仍然仅使用方法指针)获取属性值时,编译器已经优化了访问参数的方法,知道确切的类层次结构等,而当您通过使用“获取”获取属性的值时“,你让反射做getter方法的工作,显然没有编译器优化。

答案 1 :(得分:1)

在您的微基准测试中,方法调用更快,因为JVM / Hotspot在您的循环中进行了优化。

更改你的microbenchmak:

创建一个循环,其中:通过Reflection读取值,然后增加1(例如),然后通过Reflection分配给相同的Field。在循环之外,进行最后的读取和System.out.println吧......

执行两个变体(Field vs Method),你会发现真正的区别恰恰相反:方法调用实际上要慢30-40%。

此致

答案 2 :(得分:0)

这是否也意味着double d = Foo.getVal()double d = Foo.val快30%?