闭包是一块代码可以传入另外一个地方,并且在终点处可以运行该代码。用编程语言来描述,就是指可以把一个函数(类对象)打包传入另一个函数(类对象)里,通常指客户端调用处。java闭包主要是通过接口+内部类来实现,有两种形式:接口+内部类和接口+局部内部类
一、接口+内部类
class Outer {
private class Inner implements Runable {
@Overide
public void run() {
System.out.println("Outer.Inner.run");
}
}
public Runable getRun() {
return new Inner();
}
}
把内部类Inner声明为private,使外界无法访问,getRun方法返回一个内部类的实例。在客户端调用:
Runable run = new Outer().getRun();
run.run(); // 客户端得到Inner实例,并可调用run方法,这就是延迟运行,并inner实例传到外界客户端里
二、接口+局部内部类:
class Outer {
public Runable getRun() {
class Inner implements Runable {
@Overide
public void run() {
System.out.println("Outer.getRun.Inner.run");
}
}
return new Inner();
}
}
这两种方式都可实现闭包,而在客户端调用内部类的过程,称为回调。
下面列出与JS闭包的不同之处:
java:
class Outer {
public List<Runable> getRunList() {
List<Runable> list = new ArrayList(10);
for (int i = 0; i < 10; i++) {
int temp = i;
list.add(new Runable() {
@Override
public void run() {
System.out.print(temp + " ");
}
});
}
return list;
}
}
调用:
List<Runable> list = new Outer().getRunList();
for (Runable item : list) {
item.run();
}
// 循环输出:0 1 2 3 4 5 6 7 8 9
javascript:
function Outer {
var tempList = [];
for (var i = 0; i < 10; i++) {
tempList[i] = function () {
return i;
}
}
return tempList;
}
调用方:
var list = Outer();
for (var i = 0; i < list.length; i++) {
Console.write(list[i]() + " "); // 闭包回调
}
// 输出结果:10 10 10 10 10 10 10 10 10 10
由上可以看出,同样的代码逻辑,java和js执行结果不一样。这是因为js变量作用域在for, if 和 { }块时,它的作用域都超出块体外,在闭包调用时,会取出最后一个值为10。而java作用不同,随着块级}结束而结束,所以调用时,都取的是i的副本(已经将对应值存入)。另外C#的委托也是实现闭包的一种。