文档章节

生成动态类代替反射

星仔小号
 星仔小号
发布于 2015/07/25 12:50
字数 890
阅读 281
收藏 29

提高反射效率可利用缓存来搞,另一种方法是,生成动态类的方式可直接调用方法,性能跟直接调一样,可代替反射;

做平台,大量使用反射或者动态生成类,泛型,等特性,会极大地提高平台通用行,不仅节省众多代码,灵活性高,提高性能,代码看起来也是非常的优雅;

1,首先我们需要定义个抽象类,为什么要定义抽象类呢,因为我们需要直接通过它去调用目标对象的和函数,所以要明确定义出来还引用嘛

public abstract class MethodInvoker {


	public abstract Object invoke(Object instance, String method,Object[] params);
}

2,然后我们顶一个工厂,用于创建代理MethodInvoker类

public class InvokerFactory {


	public static MethodInvoker createInvoker(Class clazz) throws Exception{

		Method[] methods = clazz.getDeclaredMethods();
		String className = clazz.getName();

	// 创建类  
        ClassPool pool = ClassPool.getDefault();  
        CtClass methodInvoker = pool.makeClass("test.MethodInvokerImpl",pool.getCtClass("test.MethodInvoker"));
        
        
        String methodString = "public Object invoke(Object instance, String method,Object[] params) \n"
        		+ "{\n"
        		+ "	if(method==null||method==\"\") \n"
        		+ "	return null;\n" ;
        
        
        //关键在这里
        for(int i=0;i<methods.length;i++){
        	Method method = methods[i];
        	Class returnType = method.getReturnType();
        	
        	String methodName = method.getName();
        	int paramCount = method.getParameterCount();
        	Class[] parameterTypes = method.getParameterTypes();
        	
        	methodString = methodString + "	if(method.equals(\""+methodName+"\")) \n";
        	
        	if(returnType.getName().equals("void")){
        		methodString = methodString + "	{ \n";
        		methodString = methodString + "		(("+className+")instance)."+methodName+"(";
        	}
        	else
        		methodString = methodString + "		return (("+className+")instance)."+methodName+"(";
        	for(int j=0;j<paramCount;j++){
        		Class cls = parameterTypes[j];
        		methodString = methodString +"("+cls.getName()+")params["+j+"]";
        		if((j+1)<paramCount)
        			methodString = methodString +",";
        	}
        	methodString = methodString +"); \n";
        	
        	if(returnType.getName().equals("void")){
        		methodString = methodString + "		return null; \n";
        		methodString = methodString + "	} \n";
        	}
        }
        
		methodString = methodString	+ "	return null; \n"
		+ "}\n";
        
        // 添加一个方法
        methodInvoker.addMethod(CtNewMethod.make(methodString, methodInvoker));
        
        // 打印创建类的类名 
        Object instance = methodInvoker.toClass().newInstance();
        
        MethodInvoker invoker = (MethodInvoker)instance;

        return invoker;
	}
}

解释一下,这里面其实就是通过反射,分析目标类所有的方法,参数类型,参数个数,返回值类型,从而好根据传入的字符串匹配,一旦匹配到了就直接调用那个方法

例如,对于User这个类来说,会生成一个这样的动态方法出来

public Object invoke(Object instance, String method,Object[] params) 
{
	if(method==null||method=="") 
	return null;
	if(method.equals("setUsername")) 
	{ 
		((test.User)instance).setUsername((java.lang.String)params[0]); 
		return null; 
	} 
	if(method.equals("getUsername")) 
		return ((test.User)instance).getUsername(); 
	if(method.equals("getPassword")) 
		return ((test.User)instance).getPassword(); 
	if(method.equals("setPassword")) 
	{ 
		((test.User)instance).setPassword((java.lang.String)params[0]); 
		return null; 
	} 
	return null; 
}

我的意思已经一目了然了吧,ok,我们实际上就是用javassist来生成类和方法的,这个类继承了MethodInvoker抽象类,实现了它的invoke方法;那么接下来,我们就很好办了,只需要根据我们生成的类实例化一个对象,然后强制转换成MethodInvoker引用,就可以调用了;


        //采用生成动态类,达到直接调用函数的目的
	public static void main(String[] args) throws Exception {
		User user = new User();
		MethodInvoker invoker = InvokerFactory.createInvoker(user.getClass());
		Object[] array = {"xingzai"};
		invoker.invoke(user, "setUsername",array );	
	}

是不是很方便呢;注意,这个invoke方法,如果你调用的函数有返回值,就return,没返回值就返回null;然后传入的参数按顺序构造一个参数数组,目前我这个例子还不支持数组参数和数组返回,大家可以改进一下,无非在生成invoke函数时,多注意判断一些特殊情况哈;


然后,建议大家最好在MethodFactory里,增加一个池化对象map;因为生成这个methodInvoker也是需要耗费时间的,这玩意可以通用,因此还是保存起来好一些,才能真正意义上提升性能

我做了一个性能测试

直接调:动态生成调:反射 = 1:1:30

© 著作权归作者所有

星仔小号
粉丝 14
博文 18
码字总数 16581
作品 0
高级程序员
私信 提问
加载中

评论(3)

星仔小号
星仔小号 博主

引用来自“棒子面er”的评论

搜到了“JavaSist”
恩,是的,你可以试试
棒子面er
棒子面er
搜到了“JavaSist”
棒子面er
棒子面er
大神,你这用的是什么组件(框架)?给个名字,多谢
Java反射机制

1.反射机制是什么 Reflection(反射)是被视为动态语言的关键,反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法...

ciyo_yang
2017/06/26
0
0
kvn-wang/hp-reflect

hp-reflect (high performance reflect) 项目介绍 hp-reflect 是一个高性能的反射工具。它使用字节码技术动态生成 access class。通过不同的 access class,可以高效的获取字段的值,或者调用...

kvn-wang
2018/08/16
0
0
ulua 动态反射在IOS上的问题

ulua同时支持静态代码生成和动态接口反射。 以前在cocos2d中,c++ 没有反射能力,自然需要将所有的接口都静态生成代码给lua使用。 c#动态反射给lua使用,在ios的 il2cpp中存在一个, 如果一个...

李勇2
2016/08/19
69
0
Java程序员从笨鸟到菜鸟之(八)反射和代理机制

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 反射和代理机制是JDK5.0提供的java新特性,反射的出现打破了java一些常规的规则,如,私有变量不可访问。但反...

长平狐
2012/11/12
103
0
java反射与代理

Java反射机制与动态代理,使得Java更加强大,Spring核心概念IoC、AOP就是通过反射机制与动态代理实现的。 1 Java反射 示例: User user = new User();user.setTime5Flag("test"); Class<?> c......

wf王帆
2016/07/24
62
0

没有更多内容

加载失败,请刷新页面

加载更多

关于运维,该怎么决定它的方向,这个似工作又似兴趣的存在

我之前主要从事网络、桌面、机房管理等相关工作,这些工作使我迷惘,这应该是大多数运维人都经历过的过程; 18年国庆,我从国内前三的消费金融公司裸辞,下海创业,就是想要摆脱这样的困境。...

网络小虾米
5分钟前
1
0
Java Timer的用法

Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { System.out.println("11232"); } }, 200000 , 1000); public void schedule(TimerTask task, long delay......

林词
9分钟前
3
0
使用js动态加载外部js文件以及动态创建script脚本

动态脚本指的是在页面加载时不存在,但将来的某一时刻通过修改该DOM动态添加的脚本。和操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入JavaScript代码。 动态加载外的外...

Bing309
16分钟前
2
0
从零开始入门 K8s | Kubernetes 网络概念及策略控制

作者 | 阿里巴巴高级技术专家 叶磊 一、Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法。大家知道 Kubernetes 对于网络具体实现方案,没有什么限制,也没有给出特...

阿里巴巴云原生
20分钟前
2
0
天气获取

本文转载于:专业的前端网站➨天气获取 $.get("http://wthrcdn.etouch.cn/WeatherApi", { citykey: cityCode }, function (d) { //创建文档对象 var parser = new ......

前端老手
21分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部