我正在对一些代码进行微基准测试(请保持友善)并遇到了这个难题:使用反射读取字段时,调用 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
}
我们有两个反射(reflection):
Method m = Foo.class.getDeclaredMethod("getVal", null);
Field f = Foo.class.getDeclaredField("val");
现在我在一个循环中调用这两个反射,invoke
在 Method 上,get
在 Field 上。第一次运行是为了预热 VM,第二次运行是通过 10M 次迭代完成的。 方法调用始终快 30%,但为什么呢?请注意,getDeclaredMethod 和 getDeclaredField 不会在循环中调用。它们被调用一次并在循环中的同一个对象上执行。
我还尝试了一些小的变化:使字段成为非最终的、可传递的、非公开的,等等。所有这些组合导致了统计上相似的性能。
编辑:这是在 WinXP、Intel Core2 Duo、Sun JavaSE build 1.6.0_16-b01 上,在 jUnit4 和 Eclipse 下运行。
最佳答案
我有根据的猜测是 getDeclaredField 和 getDeclaredMethod 的实现方式不同:每次调用时,getDeclaredField 都必须检查变量类型和大小,以便返回实际对象或原始类型,getDeclaredMethod 会将指针返回到同一个方法,该方法静态处理所有其余部分。
编辑:
我的解释是类似的:对于每个类,一个方法在内存中只包含一次,而每个对象实例可以有不同的属性值。当您通过执行方法调用(仍然仅使用方法指针)获取属性值时,编译器已经优化了访问参数的方法,知道确切的类层次结构等,而当您通过使用“get”获取属性值时",你让反射完成 getter 方法的工作,显然没有编译器优化。
关于Java 反射方法调用比字段更快地产生结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4593165/