我当时勉强搞定其他那些反射方法,变量等等的时候,还不知道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, 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;
}
<4>: 在主类中添加如下:
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();
}
最终执行的结果如下 :