java reflect性能测试
针对类的成员set,get方法和创建对象进行了正常和反射的测试。
测试前提:一千万次调用的测试,cpu e5800 @3.2GHz,内存3G
测试代码如下:
Cat.java
public class Cat { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
TestInvoke.java
import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class TestInvoke { private static int testNum = 10000000;// 一千万次 public static void main(String[] args) throws Exception { TestInvoke testInvoke = new TestInvoke(); testInvoke.testSet_reflect(); testInvoke.testSet_normal(); testInvoke.testGet_reflect(); testInvoke.testGet_normal(); testInvoke.testNew_reflect(); testInvoke.testNew_normal(); } /** * set方法反射方式测试 * * @throws Exception */ public void testSet_reflect() throws Exception { Map<String, Method> methodCache = new HashMap<String, Method>(); Class<Cat> classType = Cat.class; Object object = classType.newInstance(); String methodName = "setId"; long startTime = System.currentTimeMillis(); for (int i = 0; i < testNum; i++) { // 如果setMethod直接放在循环里面性能下降10倍。所以可以做个缓存。 Method setMethod = null; if (methodCache.containsKey(methodName)) { setMethod = methodCache.get(methodName); } else { setMethod = classType.getMethod(methodName, new Class[] {int.class}); methodCache.put(methodName, setMethod); } setMethod.invoke(object, 100000); } System.out.println("reflect invoke set method spend time:" + (System.currentTimeMillis() - startTime)); } /** * set方法正常方式测试 * * @throws Exception */ public void testSet_normal() throws Exception { Cat cat = new Cat(); long startTime = System.currentTimeMillis(); for (int i = 0; i < testNum; i++) { cat.setId(100000); } System.out.println("normal invoke set method spend time:" + (System.currentTimeMillis() - startTime)); } /** * get方法反射方式测试 * * @throws Exception */ public void testGet_reflect() throws Exception { Map<String, Method> methodCache = new HashMap<String, Method>(); Class<Cat> classType = Cat.class; Object object = classType.newInstance(); // 设置数据 Method setMethod = classType.getMethod("setId", new Class[] {int.class}); setMethod.invoke(object, 1234); String methodName = "getId"; long startTime = System.currentTimeMillis(); for (int i = 0; i < testNum; i++) { // 如果setMethod直接放在循环里面性能下降10倍。所以可以做个缓存。 Method getMethod = null; if (methodCache.containsKey(methodName)) { getMethod = methodCache.get(methodName); } else { getMethod = classType.getMethod(methodName); methodCache.put(methodName, getMethod); } getMethod.invoke(object); } System.out.println("reflect invoke get method spend time:" + (System.currentTimeMillis() - startTime)); } /** * get方法正常方式测试 * * @throws Exception */ public void testGet_normal() throws Exception { Cat cat = new Cat(); // 设置数据 cat.setId(1234); long startTime = System.currentTimeMillis(); for (int i = 0; i < testNum; i++) { cat.getId(); } System.out.println("normal invoke get method spend time:" + (System.currentTimeMillis() - startTime)); } /** * new方法反射方式测试 * * @throws Exception */ public void testNew_reflect() throws Exception { long startTime = System.currentTimeMillis(); Class<Cat> classType = Cat.class; for (int i = 0; i < testNum; i++) { Object object = classType.newInstance(); } System.out.println("reflect invoke new spend time:" + (System.currentTimeMillis() - startTime)); } /** * new方法正常方式测试 * * @throws Exception */ public void testNew_normal() throws Exception { long startTime = System.currentTimeMillis(); for (int i = 0; i < testNum; i++) { Cat cat = new Cat(); } System.out.println("normal invoke new spend time:" + (System.currentTimeMillis() - startTime)); } }
三次运行结果:
第一次:
reflect invoke set method spend time:1078
normal invoke set method spend time:0(经常结果0,效率真是太高了)
reflect invoke get method spend time:1000
normal invoke get method spend time:15
reflect invoke new spend time:1063
normal invoke new spend time:109
第二次:
reflect invoke set method spend time:1078
normal invoke set method spend time:16
reflect invoke get method spend time:1000
normal invoke get method spend time:0(经常结果0,效率真是太高了)
reflect invoke new spend time:1063
normal invoke new spend time:109
第三次:
reflect invoke set method spend time:1078
normal invoke set method spend time:15
reflect invoke get method spend time:985
normal invoke get method spend time:15
reflect invoke new spend time:1063
normal invoke new spend time:109
得出以下结论:
1 反射不是不能用,没有想象的那么差,只是正常调用方式效率更高,在一千次内的调用可以认为效率相当。
2 set方法效率相差大概:70到来200倍
3 get方法效率相差大概:70到来200倍
4 new方法效率相差大概:10倍