利用反射实现需求

         经常有学弟学妹问我,反射有什么用。

          网上大神建议是反射尽量别用,反射在增加灵活性的同时会消耗一定资源。很多框架要用到它,因为框架需要利用配置文件进行动态配置,需要尽可能的灵活性,这时候就要牺牲一部分的性能了。

         记得我以前的帖子贴出过一个利用反射简单实现spring动态代理的代码:http://709002341.iteye.com/admin/blogs/2266317

         不过那只是个例子,前几天我真遇到一个要用反射实现的需求:

         场景是这样的:我是后端服务器,跟前端交互用的是后端的返回bean以json的形式传给前端,然后前端实现页面展示。但是前端前段时间换了个框架,然后一顿改,结果到我这出错了:如果我的返回bean有null值,在json串里是不体现那个属性的。比如我的bean有一个字符串str,如果str是null的话,返回的json串就没有str这个字段了,所以前台取str的时候出错。。。  老大让我改一下后端。

        后端的场景是这样的,一个返回bean类似这样:

/**
 * returnBean: 所有请求的返回bean
 * 
 * @author xuejupo [email protected] create
 * 
 */
class ReturnBean {
	
	/** 请求的返回状态,1为正常,0为错误 */
	private int status = 0;
	/** 当status为0的时候,errMsg表示错误信息 */
	private String errMsg;
	/** 请求返回的数据个数,当请求为查询的时候该字段有效 */
	private int count = 0;
	/** 请求返回的结果(这是最重要的请求结果,如果是查询请求,这里置入结果bean,如果是其他请求,这里置入其他的请求结果,如String) */
	private Object object;
	
	
	public final int getStatus() {
		return status;
	}

	public final void setStatus(int status) {
		this.status = status;
	}

	public final String getErrMsg() {
		return errMsg;
	}

	public final void setErrMsg(String errMsg) {
		this.errMsg = errMsg;
	}

	public final int getCount() {
		return count;
	}

	public final void setCount(int count) {
		this.count = count;
	}

	public final Object getObject() {
		return object;
	}

	public void setObject(Object object) {
		this.object = object;
	}
}

      所有的请求都是这一个bean返回,然后返回的数据bean部分封装到object里。

       比如我有一个bean:

/**  
* MyBean: 我的查询返回bean 
* @author xuejupo  [email protected] 
* create in 2016-1-29 下午2:13:54  
*    
*/
class MyBean {
	

	/**
	 * 如果业务有需要,这种形式是最好的,给字段赋个初始值
	 */
	private String str1 = "";
	private String str2;
	private String str3;
	private String str4;
	
	public final String getStr1() {
		return str1;
	}

	public final void setStr1(String str1) {
		this.str1 = str1;
	}

	public final String getStr2() {
		return str2;
	}

	public final void setStr2(String str2) {
		this.str2 = str2;
	}

	public final String getStr3() {
		return str3;
	}

	public final void setStr3(String str3) {
		this.str3 = str3;
	}

	public final String getStr4() {
		return str4;
	}

	public final void setStr4(String str4) {
		this.str4 = str4;
	}
}

       最好的方式当然是像str1一样,给所有的字段附上初始值。但是出现个问题,我把setObject改了个名字,想看看到底多少个数据bean需要修改(修改一下setObject名字,然后看文件出错个数即可),结果发现有差不多70多个bean需要修改。。。   同样的工作重复70次,这是任何一个程序员都不能忍的。。。  所以我就想到修改setObject这个方法了。既然所有的数据bean都要用到这个方法,那我修改一下这个方法不就可以了?

       然后就想到反射了。

       把setObject修改为如下代码:

  public void setObject(Object object) {
		this.putEmptyIfNull(object);
		this.object = object;
	}

     增加一个方法,如果object中有属性为空,那么就初始化他:

/**  
	* putEmptyIfNull: 如果object中有属性为null,那么附空
	* @param object 
	* void  返回类型   
	*/
	private void putEmptyIfNull(Object object){
		//获取对象的class类,请注意,执行完这一步,以下所有的操作都跟具体的对象无关了,只跟这个类有关,所以
		//下边的赋值操作,要将对象object当作参数穿进去
		Class<?> c = object.getClass();
		Field[] fields = c.getDeclaredFields();
		for(int i = 0; i < fields.length; i++){
			Field f = fields[i];
			//首先应该把这个字段赋成公开(public)
			f.setAccessible(true);
			try {
				//如果对象object上该字段的值是null
				if(f.get(object) == null){
					//那么就将object对象上该值赋为空
					f.set(object, "");
				}
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}
	}

        测试代码:

public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
		Test1 test = new Test1();
		List<ReturnBean> l = new ArrayList<ReturnBean>();
		long start = System.currentTimeMillis();
		for(int i = 0; i < 1000; i++){
			ReturnBean bean = test.getBean();
			l.add(bean);
		}
		long end = System.currentTimeMillis();
		System.out.println(((MyBean)l.get(0).getObject()).getStr3());
		System.out.println("程序执行:"+(end - start));
	}

     不用初始化null的时候的测试结果:

null
程序执行:3

 初始化null的测试结果:

程序执行:41

 可以看到,反射确实在增加灵活性上的基础上,降低了性能。不过很多时候这种性能上的消耗是可以忍受的(就像这个,1000个对象初始化才消耗41毫秒,这在对前端响应上是完全可以接收的),effect java上大神建议不要用反射,最大的原因还是一旦用反射,如果出错的话很难定位异常。所以,用反射的两大条件:   一是你一定要用,除了反射真的想不出其他好的办法了,二是,一定要做好注释(别看我上面没什么注释,其实我真实环境的注释那是杠杠的。。。)

猜你喜欢

转载自709002341.iteye.com/blog/2275135