反射方法类Method
需要callback函数为变量时,java通常用反射(java.lang.reflect)的相关方法。
import java.lang.reflect.Method;
利用Method类和invoke方法实现传递callback
例如 以TestAClass.AddProduce(int a, int b)是需要回调的函数,为了体现函数作为参数可变的优势,这里写2个回调函数:
public class TestAClass {
ArrayList list = new ArrayList<>();
public void AddProduct(int a, int b) {
list.add(a * b);
}
public void AddSum(int a, int b) {
list.add(a + b);
}
}
TestBClass.testCall()是被调函数:
public class TestBClass {
public void testCall(Method func) throws Exception {
TestAClass aobj = new TestAClass();
for (int i = 0; i < 10; i++)
func.invoke(aobj, i, i + 1);
}
}
执行invoke时第一个参数需要执行的对象。在上面代码中是新建了一个AClass对象,这样的话会导致对象的类还是在方法中被严格限制。
虽然这里可能可以用func.getDeclaringClass()来获取目标类型,但是我们仍然有可能希望限制执行回调函数的对象。
因此当我们希望执行回调的对象也是特定变量时,就需要改为:
public class TestBClass {
public void testCall(object obj, Method func) throws Exception {
for (int i = 0; i < 10; i++)
func.invoke(obj, i, i + 1);
}
}
调用这个函数时:
TestAClass tcb = new TestAClass();
TestBClass tc = new TestBClass();
Method callback = new Method(tcb.getClass().getMethod("AddProduct", int.class, int.class));
tc.testCall(tcb, callback);
for (int i : tcb.list) {
System.out.println(i);
}
tcb.list.clear();
System.out.println("-------");
callback = new Method(tcb.getClass().getMethod("AddSum", int.class, int.class));
tc.testCall(tcb, callback);
for (int i : tcb.list) {
System.out.println(i);
}
至此就可以完成传递回调函数作为变量。
封装CallBack类
每当我们需要把一个函数的回调函数改为变参时,我们就需要同时在调用函数的参数和invoke上加上obj、method这2个参数,当频繁添加回调时感觉很麻烦。因此考虑重新封装一个CallBack类,简化回调的参数。 如下:
public class CallBack {
Object ownobj;
Method execute;
public CallBack(Object o, Method method) {
ownobj = o;
execute = method;
}
public Object invoke(Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
return execute.invoke(ownobj, args);
}
}
回调函数无变化:
public class TestAClass {
ArrayList list = new ArrayList<>();
public void AddProduct(int a, int b) {
list.add(a * b);
}
public void AddSum(int a, int b) {
list.add(a + b);
}
}
调用函数简化为:
public class TestBClass {
public void testCall(CallBack func) throws Exception {
for (int i = 0; i < 10; i++)
func.invoke(i, i + 1);
}
}
调用改为:
TestAClass tcb = new TestAClass();
TestBClass tc = new TestBClass();
CallBack callback = new CallBack(tcb, tcb.getClass().getMethod("AddProduct", int.class, int.class));
tc.testCall(callback);
for (int i : tcb.list) {
System.out.println(i);
}
tcb.list.clear();
System.out.println("-------");
callback = new CallBack(tcb, tcb.getClass().getMethod("AddSum", int.class, int.class));
tc.testCall(callback);
for (int i : tcb.list) {
System.out.println(i);
}
执行结果:
0
2
6
12
20
30
42
56
72
90
-------
1
3
5
7
9
11
13
15
17
19
后记
目前发现invoke 不支持以String[]作为多态参数。可以转化为ArrayList传递