我当时勉强搞定其他那些反射方法,变量等等的时候,还不知道java动态代理是个什么东西,闻所未闻,只是实际工作中,遇见一个类似下面的东东,给难倒了:
onClickListener listener=new onClickListener(){ @Override public void onClick() { // TODO Auto-generated method stub } };
一看这种形式怎么反射呀?刚开始看的时候在想,不就是反射onClickListener这个接口出来吗?但是问题来了,里面的onClick方法怎么弄呢?要在onClick里面添加自己的功能代码,按照前面的反射各种接口,还是方法,就是玩不出,后来想起了,看奇虎360公司的开源的360插件代码,但是并不是在代码中琢磨出来的,而是让我想起了我还有个老朋友在奇虎360公司做Android开发的,所以发了一个微信给他,结果很快他就告诉需要用到什么技术,而且给了下面的技术链接 :
https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/
看了之后,让人恍然醒悟,这个东西绝对是在整个反射中最神奇最牛逼的东西.有兴趣可以阅读以下上面链接的文章.
在正式下面使用代理之前,我还在考虑是不是写一个java回调方法的使用,大致举例说一下,也是我在博客园博客上面以前写的,通俗点如下:
用来干什么?
A问B一个问题,B一时想不出结果,A看B一时想不出结果,就对B说,想出结果了在告诉我,我顺便去做我的其他事情,做完事,你在告诉我你的结果.用程序实现如下:
<1> : 新建一个java工程,其中主类如下:
import callback.javaCallBackListener; import out.waitToProblemSolved; public class JavaCallBackTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub waitToProblemSolved wt=new waitToProblemSolved(); //A开始告诉B要去解决问题了 wt.doMyWorkWhenWait2Answer(new javaCallBackListener(){ @Override public void toSolveProblem() { // TODO Auto-generated method stub B终于想去出结果了 System.out.println("solver now have the answer !"); } }); } }
<2> : A要发起问题:waitToProblemSolved.java:
package out; import callback.javaCallBackListener; public class waitToProblemSolved { public void doMyWorkWhenWait2Answer(javaCallBackListener listener) { // problemer could do work himself A自己开始做自己的事情 System.out .println("problemer could do his work now until solver release his answer !"); for (int i = 0; i < 3; i++) { System.out.println("problemer start to solve " + i + " work !"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("problemer finish his " + i + " work !"); } // solver solve the answer B应该可以给出答案了 listener.toSolveProblem(); } }
<3> : 解决问题者B:javaCallBackListener.java
package callback; public interface javaCallBackListener { public void toSolveProblem(); }
大致就是上面的这个意思,为什么给出上面的demo,那是因为下面的代理其实托管接口的东东.
具体Java动态代理理论可以写一本书了,建议关于理论方面参考网上的.
用到的主要类,Proxy.java
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
|
第一个参数被代理类转载器; 第二个参数被代理类; 第三个参数是一个InvocationHandler 返回值为一个代理类的实例 |
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
|
返回代理类实例的InvocationHandler |
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html |
其中上面InvocationHandler是一个接口,这个让代理处理被代理里面具体方法的实现.
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
|
这个是InvocationHandler类必须让使用者必须实现的一个方法. |
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationHandler.html |
下面通过一个具体例子介绍如何使用的:
<1> : 新建一个Java工程,工程树如下:
<2> : 首先先写一个接口类,onClickListener.java, 接口类中有三个方法需要实现,如下
package com.oneplus.interfaces; /** * @author zhibao.liu * @date 2015-11-18 * @company : oneplus.Inc */ public interface onClickListener { void onClick(int arg1,int arg2); int onSumClick(int arg1,int arg2); int onDulClick(int arg1,int arg2); } <3> : 然后写一个单独的类OneplusProxy,并且让其实现InvocationHandler接口: package com.oneplus.invo; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author zhibao.liu * @date 2015-11-18 * @company : oneplus.Inc */ public class OneplusProxy implements InvocationHandler { private Object objs; public OneplusProxy(Object obj) { objs = obj; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object result; int ret = 0; if(method.getName().equalsIgnoreCase("onDulClick")){ if(args.length>1){ ret=Integer.parseInt(args[0].toString())-Integer.parseInt(args[1].toString()); } System.out.println("onDulClick ret : "+ret); return ret; } for (int i = 0; i < args.length; i++) { System.out.println("Object args : " + args[i].toString()); ret += Integer.parseInt(args[i].toString()); } result = ret; System.out.println("oneplus method name : " + method.getName()); return result; } }
<4> : 然后在实现一个OneplusButton.java的类:
package com.oneplus.impl; import com.oneplus.interfaces.onClickListener; /** * @author zhibao.liu * @date 2015-11-18 * @company : oneplus.Inc */ public class OneplusButton{ private onChangeListener listener; private onClickListener clistener; private onClickListener slistener; private onClickListener dlistener; public interface onChangeListener{ void onChanged(); } public void setChangeListener(onChangeListener listener){ System.out.println("setChangeListener ! "); this.listener=listener; listener.onChanged(); } public void setClickedListener(onClickListener listener){ clistener=listener; clistener.onClick(12, 23); } public Object setSumClickedListener(onClickListener listener){ Object ret = null; return ret; } public Object setDulClickedListener(onClickListener listener,int arg1,int arg2){ Object ret = null; return ret; } }
<5> : 主类OneplusMainProxyClass.java,具体如下:
public static void ExcuteOnClick(){ try { Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener"); InvocationHandler handler=new OneplusProxy(null); // 下面listener命名很有意思,让人直观感觉到了 // 代理了OnClickListener接口的一个对象 Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler); //下面再得到实施调用的类 /* 取名OneplusButton想UI控件,因为一般UI控件在设置事件的时候经常oneplusButton.setOnClickListener(new onClickListener(){ //TODO your work here … }) 这里刚好,通过上面得到了listener,那么这个listener还需要这个UI控件通过setOnClickListener(listener)来调用,其实是实现了一个回调 */ Class clazz=Class.forName("com.oneplus.impl.OneplusButton"); try { Object obj = null; try { obj = clazz.newInstance(); } catch (InstantiationException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IllegalAccessException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } /* 正如上面所说的,还需要反射出setClickedListener这个方法,用来消费listener */ Method method=clazz.getDeclaredMethod("setClickedListener", claimpl); method.setAccessible(true); try { /* 调用setClickedListener方法,传入listener */ Object ret=method.invoke(obj, listener); if(ret!=null){ System.out.println("main thread result : "+ret.toString()); } } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
<1> : 当执行Object ret=method.invoke(obj, listener)后;程序立即进入:
public void setClickedListener(onClickListener listener){ clistener=listener; clistener.onClick(12, 23); }
<2> : 根据上面第一步, clistener.onClick(12, 23)程序执行到这一步,后面的onClick在哪里执行呢?这个就是程序:
Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler);
开始由代理做下面的事情了,注意Proxy.newProxyInstance第三个参数handler,handler是一个实现InvocationHandler接口的类,那么就要实现接口的方法,而这个接口的方法:
public Object invoke(Object object, Method method, Object[] args) throws Throwable
正是用来处理onClick方法,从单个或者某种程度上来说invoke代理执行onClick的具体操作过程,onClick里面传递的两个参数,将会全部保存在invoke方法的第三个参数Object[] args中,读者可以通过循环:
for(int i=0;i<args.lenght;i++){ System.out.println(“parameter “ +i+ ” value : ”+args[i].toString()); }
得到的结果分别是12 和23 , 这里面还有一个有意思的参数,那就是第二个参数,它居然还传递method下来,根据上面具体程序,可以打印这个method的名称:
Objectobject=method.getName();
这样获取的名字是:onClick,这个方法名也返回在以后中可能因为还需要继续反射使用,例如method.invoke(object,args).
那么为什么invoke只是在某种程度上执行的就是onClick方法,那是因为如果接口只有一个方法或者只需要代理这一个,就可以勉强这样理解,其实如果onClickListener类有多个方法需要实现时,那么invoke会一个一个的帮助你完成.当然同样,即使是同一个接口onClickListener也可以用不同InvocationHandler分别处理.
<3> : 同理,继续在OneplusButton类中实现:
public Object setSumClickedListener(onClickListener listener){ Object ret; slistener=listener; ret=slistener.onSumClick(11, 32); return ret; } public Object setDulClickedListener(onClickListener listener,int arg1,int arg2){ Object ret = null; dlistener=listener; ret=dlistener.onDulClick(arg1, arg2); return ret; }
public static void ExcuteOnDulClick(){ try { Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener"); InvocationHandler handler=new OneplusProxy(null); Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler); Class clazz=Class.forName("com.oneplus.impl.OneplusButton"); try { Object obj=clazz.newInstance(); try { Method method=clazz.getDeclaredMethod("setDulClickedListener", claimpl,int.class,int.class); try { Object ret=method.invoke(obj, new Object[]{listener,102,201}); System.out.println("3 type main thread ret : "+ ret.toString()); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void ExcuteOnSumClick(){ try { Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener"); InvocationHandler handler=new OneplusProxy(null); Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler); Class clazz=Class.forName("com.oneplus.impl.OneplusButton"); try { Object obj=clazz.newInstance(); try { Method method=clazz.getDeclaredMethod("setSumClickedListener", claimpl);//第二个是传递的参数类型,经常忘记! try { Object ret=method.invoke(obj, listener); System.out.println("main thread ret : "+ ret.toString()); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
注意:可以从上面来看,还能够实现返回值等
上面的方法调用如下 :
public static void main(String[] args) { // TODO Auto-generated method stub ExcuteOnChange(); ExcuteOnClick(); ExcuteOnSumClick(); ExcuteOnDulClick(); }
最终执行的结果如下 :