java的反射性能测试
2015-08-02 15:28
393 查看
测试反射实现的对象生成、方法调用的性能。在这里被测试的类代码如下所示。
首先建立了一个测试框架,对给定的测试类统计用时。代码如下所示。
这里用到了一个类TestBeanRun,这个类实现了接口Runnable,用以执行方法调用,如对象生成,get/set方法调用。测试框架对这个类的三个类型的方法调用分别执行10^8次,然后统计用时,计算平均时间。
TestBeanRun的代码如下所示。这个类里面用一个标志位来选择执行哪种调用,生成对象,或者get调用,set调用。这里默认的是进行常规的直接调用。普通反射和带缓存反射的测试通过继承这个类,并重写那三个方法。
测试代码如下所示。
这里对每个单元测试了十遍,结果如下所示。
有结果可知。在JDK1.8下,常规调用和反射调用的差距并没有那么大。普通的反射调用的速度很差,原因在于调用了Class.forName查找类很费时,getMethod查找方法也很费时。如果可以将类或者方法预先缓存下来再执行,也就是第三种方法,则效率差不太多了。
public class TestBean { public final static String DEFAULT="default"; private String word; public TestBean() { word=DEFAULT; } public String getWord(){ return word; } public void setWord(String word){ this.word=word; } }这个类很简单,提供一个构造函数,一个get和set属性值的方法。再比较直接调用的性能,普通反射的性能,带缓存的反射性能。
首先建立了一个测试框架,对给定的测试类统计用时。代码如下所示。
package reflectTest; /**简易测试框架,统计运行时间 * */ public class TestBeanCount{ public static void testBean(TestBeanRun tbr){ System.out.printf("%10s\t%5s\t%6s\n","method","time","avr" ); long[]time=new long[3]; String[] methods = new String[] { "construct", "get", "set" }; for (int t = 10; t-- > 0;) { tbr.setTestMethod(TestBeanRun.CONSTRUCT); time[0] = getUsedTime(tbr); tbr.setTestMethod(TestBeanRun.GET); time[1] = getUsedTime(tbr); tbr.setTestMethod(TestBeanRun.SET); time[2] = getUsedTime(tbr); for (int k = 0; k < 3; ++k) { System.out.printf("%10s\t%5d\t%6.3f\n", methods[k], time[k], time[k] * 0.001); } } } public static final long DEFAULT_RUN_TIME=100000000L; public static long getUsedTime(Runnable run,long runTime){ long start=System.currentTimeMillis(); while(runTime-->0){ run.run(); } return System.currentTimeMillis()-start; } public static long getUsedTime(Runnable run){ return getUsedTime(run,DEFAULT_RUN_TIME); } }
这里用到了一个类TestBeanRun,这个类实现了接口Runnable,用以执行方法调用,如对象生成,get/set方法调用。测试框架对这个类的三个类型的方法调用分别执行10^8次,然后统计用时,计算平均时间。
TestBeanRun的代码如下所示。这个类里面用一个标志位来选择执行哪种调用,生成对象,或者get调用,set调用。这里默认的是进行常规的直接调用。普通反射和带缓存反射的测试通过继承这个类,并重写那三个方法。
package reflectTest; public class TestBeanRun implements Runnable{ public static final int CONSTRUCT=1; public static final int GET=2; public static final int SET=3; private int testMethod; protected String s; protected TestBean tb; private final static TestBean TB = new TestBean(); public void setTestMethod(int testMethod){ this.testMethod=testMethod; } @Override public void run() { switch(this.testMethod){ case CONSTRUCT: testConstruct(); break; case GET: testGet(); break; case SET: testSet(); break; default: } } public void testConstruct(){ tb=new TestBean(); } public void testGet(){ s=TB.getWord(); } public void testSet(){ TB.setWord("ANOTHER"); } }
测试代码如下所示。
package reflectTest; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /**测试正常调用和反射调用下的执行效率问题。 * 测试范围:构造函数,get,set方法; * 测试类:TestBean; * 测试过程:分别执行1,00,000,000次,统计时间; * 测试环境:JDK1.8,Intel i3,双核四线程,2.13GHz,内存2GB * */ public class ReflectTest { public static void main(String[]args){ //普通调用 TestBeanRun normal=new TestBeanRun(); TestBeanCount.testBean(normal); // TestBeanRun norRef = new TestBeanRun() { @Override public void testConstruct() { Class<?> clazz; try { // clazz = TestBean.class; clazz=Class.forName("reflectTest.TestBean"); super.tb = (TestBean) clazz.newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } } @Override public void testGet() { try { Method m = TestBean.class.getMethod("getWord"); s = (String) m.invoke(tb); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } } @Override public void testSet() { try { Method m = TestBean.class.getMethod("setWord",String.class); m.invoke(tb, "testSet"); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } } }; TestBeanCount.testBean(norRef); TestBeanCount.testBean(new TestBeanRun(){ Class<?>clazz=TestBean.class; Method mget; Method mset; { try { mget=TestBean.class.getMethod("getWord"); mset=TestBean.class.getMethod("setWord",String.class); } catch (NoSuchMethodException | SecurityException | IllegalArgumentException e) { } } @Override public void testConstruct() { try { super.tb=(TestBean) clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } @Override public void testGet() { try { s=(String)mget.invoke(tb,null); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } } @Override public void testSet() { try { mset.invoke(tb,"testSet"); } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } } }); } }
这里对每个单元测试了十遍,结果如下所示。
普通调用 | 普通反射 | 缓存的反射 | ||||||
method | time/ms | avr/ns | time/ms | avr/ns | time/ms | avr/ns | ||
construct | 970 | 9.70 | 145401 | 1454.01 | 2294 | 22.94 | ||
get | 637 | 6.37 | 30690 | 306.90 | 1536 | 15.36 | ||
set | 682 | 6.82 | 32830 | 328.30 | 2413 | 24.13 | ||
construct | 883 | 8.83 | 143928 | 1439.28 | 2122 | 21.22 | ||
get | 611 | 6.11 | 44981 | 449.81 | 1472 | 14.72 | ||
set | 707 | 7.07 | 55214 | 552.14 | 2382 | 23.82 | ||
construct | 893 | 8.93 | 251054 | 2510.54 | 2125 | 21.25 | ||
get | 619 | 6.19 | 52653 | 526.53 | 1443 | 14.43 | ||
set | 713 | 7.13 | 58730 | 587.30 | 2370 | 23.70 | ||
construct | 890 | 8.90 | 188971 | 1889.71 | 2131 | 21.31 | ||
get | 593 | 5.93 | 29949 | 299.49 | 1429 | 14.29 | ||
set | 656 | 6.56 | 32276 | 322.76 | 2400 | 24.00 | ||
construct | 901 | 9.01 | 141805 | 1418.05 | 2101 | 21.01 | ||
get | 577 | 5.77 | 30169 | 301.69 | 1452 | 14.52 | ||
set | 654 | 6.54 | 31594 | 315.94 | 2387 | 23.87 | ||
construct | 895 | 8.95 | 138948 | 1389.48 | 2144 | 21.44 | ||
get | 570 | 5.70 | 29739 | 297.39 | 1471 | 14.71 | ||
set | 649 | 6.49 | 31638 | 316.38 | 2403 | 24.03 | ||
construct | 864 | 8.64 | 137625 | 1376.25 | 2113 | 21.13 | ||
get | 596 | 5.96 | 30532 | 305.32 | 1427 | 14.27 | ||
set | 676 | 6.76 | 31447 | 314.47 | 2352 | 23.52 | ||
construct | 904 | 9.04 | 138463 | 1384.63 | 2143 | 21.43 | ||
get | 600 | 6.00 | 29677 | 296.77 | 1429 | 14.29 | ||
set | 674 | 6.74 | 31492 | 314.92 | 2383 | 23.83 | ||
construct | 889 | 8.89 | 139524 | 1395.24 | 2105 | 21.05 | ||
get | 597 | 5.97 | 29642 | 296.42 | 1426 | 14.26 | ||
set | 674 | 6.74 | 31579 | 315.79 | 2429 | 24.29 | ||
construct | 865 | 8.65 | 138246 | 1382.46 | 2128 | 21.28 | ||
get | 573 | 5.73 | 29879 | 298.79 | 1423 | 14.23 | ||
set | 652 | 6.52 | 31571 | 315.71 | 2386 | 23.86 |
相关文章推荐
- JAVA学习第十二天
- java并发编程中CountDownLatch和CyclicBarrier的使用
- Tarena - Java开发环境
- JavaWeb 全站乱码过滤
- Spring MVC JSON数据交互-解析和返回JSON
- JAVA入门基础文章3-类的概念-什么是继承
- java中,数值型Double运算出错问题
- 简单的struts2案例
- Java比较String ==和equals() 解析
- JNI中 Java 中字符串 转换成C中的字符数组方法
- spring配置文件详解
- Web Service学习-CXF与Spring整合为JavaEE应用发布WebService(三)
- Java:注解(Annotation)自定义注解入门
- @interface java注解
- java 自动拆箱的陷阱
- JDK环境配置
- java编程的一些建议
- Exception in thread "main" java.lang.UnsupportedClassVersionError
- 用 Spring Security 4+Spring MVC+Spring4 构建健壮且安全的web应用
- Java Metrics