java的反射性能测试

测试反射实现的对象生成、方法调用的性能。在这里被测试的类代码如下所示。

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 

有结果可知。在JDK1.8下,常规调用和反射调用的差距并没有那么大。普通的反射调用的速度很差,原因在于调用了Class.forName查找类很费时,getMethod查找方法也很费时。如果可以将类或者方法预先缓存下来再执行,也就是第三种方法,则效率差不太多了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值