记得第一次接触闭包的时候,觉得很奇怪,但从字面上很那理解闭包什么玩意,和闭包有的一比的当属控制反转,真正理解了后觉得就平常了。闭包二字其实是很经典的,闭包代码所表现的东西可不就是一个封闭的、自成一体的功能块吗?简单的说,闭包就是在内部定义的方法,拿到外面去使用。经典的javascript闭包形式如下:
- function f1(){
- var i = 20;
- function closef(x){
- alert(i+x);
- }
- return closef
- }
- var s = f1();
- s(20);
javascript的这种闭包形式的确相当简洁,类似于c语言的函数指针
众所周知,java实现闭包的形式是内部类,更常用的还是匿名内部类,而这通常还需要定义接口,通过接口的引用来操作内部类对象,从而实现闭包,远没有javascript简洁。这里介绍我在开发中使用的一种java闭包形式,当然还是内部类,我在实现的时候把反射机制加了进来,这么做就是尽量使用起来简单一些。代码如下:
先定义一个接口,接口还是需要的,在以后的闭包使用中,只需要这一个接口。
- package p;
- public interface IMethod {
- public Object invoke(Object ... objects );
- }
package p;
public interface IMethod {
public Object invoke(Object ... objects );
}
该接口的实现类,这里引入反射:
- package p;
- import java.lang.reflect.Method;
- public class MethodObject implements IMethod {
- private Object target;//闭包所依赖的对象
- private String methodName;//闭包方法的名字
- public MethodObject(){}
- public MethodObject(Object target, String methodName) {
- super();
- this.target = target;
- this.methodName = methodName;
- }
- public Object invoke(Object... objects) {
- Class clazz = target.getClass();
- try {
- Method[] ms = clazz.getDeclaredMethods();
- Method targetMethod = null;
- for(Method m : ms){
- if(methodName.equals(m.getName())){
- targetMethod = m;
- break;
- }
- }
- targetMethod.setAccessible(true);
- return targetMethod.invoke(target, objects);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- throw new RuntimeException(e);
- }
- }
- public void rebund(Object anothertarget){
- target = anothertarget;
- }
- }
package p;
import java.lang.reflect.Method;
public class MethodObject implements IMethod {
private Object target;//闭包所依赖的对象
private String methodName;//闭包方法的名字
public MethodObject(){}
public MethodObject(Object target, String methodName) {
super();
this.target = target;
this.methodName = methodName;
}
public Object invoke(Object... objects) {
Class clazz = target.getClass();
try {
Method[] ms = clazz.getDeclaredMethods();
Method targetMethod = null;
for(Method m : ms){
if(methodName.equals(m.getName())){
targetMethod = m;
break;
}
}
targetMethod.setAccessible(true);
return targetMethod.invoke(target, objects);
} catch (Exception e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
public void rebund(Object anothertarget){
target = anothertarget;
}
}
下面是具体使用闭包的形式:
- public class Person {
- private int age = 0;
- public Person(int age) {
- super();
- this.age = age;
- }
- public IMethod getClosualMethod(){
- final int i = 10;
- Object o = new Object(){
- Date getBirthday(){
- Calendar c = Calendar.getInstance();
- c.set(Calendar.YEAR,c.get(Calendar.YEAR) - (age+i));
- return c.getTime();
- }
- };
- MethodObject mo = new MethodObject(o,"getBirthday");
- return mo;
- }
- }
public class Person {
private int age = 0;
public Person(int age) {
super();
this.age = age;
}
public IMethod getClosualMethod(){
final int i = 10;
Object o = new Object(){
Date getBirthday(){
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR,c.get(Calendar.YEAR) - (age+i));
return c.getTime();
}
};
MethodObject mo = new MethodObject(o,"getBirthday");
return mo;
}
}
- package test;
- import p.IMethod;
- public class Test {
- /**
- * @param args
- */
- public static void main(String[] args)throws Exception {
- // TODO Auto-generated method stub
- Person p = new Person(20);
- IMethod m = p.getClosualMethod();
- Object o = m.invoke();
- System.out.println(o);
- IMethod m2 = p.getClosualMethod2();
- m2.invoke("Tom");
- }
- }
package test;
import p.IMethod;
public class Test {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
Person p = new Person(20);
IMethod m = p.getClosualMethod();
Object o = m.invoke();
System.out.println(o);
IMethod m2 = p.getClosualMethod2();
m2.invoke("Tom");
}
}
下面是输出结果:
Sun Jun 03 17:35:05 CST 1979
hello Tom, I am 20 years old
从这里可以看到,有了Imethod和MethodObject,在java里使用闭包,就可以像javascript那样方便了。当然,这只是模拟,如果想要达到javascript那样在运行期改变对象的属性和方法,可以在更高一级去模拟。