var n=999;
function f1(){
alert(n);
}
f1(); // 999
function f1(){
var n=999;
}
alert(n); // error
function f1(){
n=999;
}
f1();
alert(n); // 999
function f1(){
n=999;
function f2(){
alert(n); // 999
}
}
function f1(){
n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
2.闭包会在父函数外部,改变父函数内部变量的值。
Java 语言本身还没有正式支持闭包,但它却允许模拟闭包(内部类+接口)。可以使用匿名的内部类来实现闭包。
如何让这个普通对象能够访问所在类的自由变量?内部类。内部类能够访问外部类的所有属性及方法。
隐藏具体实现是内部类的作用之一,如何保证隐藏具体实现的同时还能将闭包传递到外部使用?让内部类实现通用接口,然后将内部类对象向上转型为接口类型。 public final static String name = "纯牛奶";// 名称
private static int num = 16;// 数量
public Milk() {
System.out.println(name + ":16/每箱");
}
/**
* 闭包
*
* @return 返回一个喝牛奶的动作
*/
public Active HaveMeals() {
return new Active() {
public void drink() {
if (num == 0) {
System.out.println("木有了,都被你丫喝完了.");
return;
}
num--;
System.out.println("喝掉一瓶牛奶");
}
};
}
/**
* 获取剩余数量
*/
public void currentNum() {
System.out.println(name + "剩余:" + num);
}
}
/**
* 通用接口
*/
interface Active {
void drink();
}
//闭包的使用
public class Person {
public static void main(String[] args) {
//买一箱牛奶
Milk m = new Milk();
Active haveMeals = m.HaveMeals();
//没事喝一瓶
haveMeals.drink();
//有事喝一瓶
haveMeals.drink();
//看看还剩多少?
m.currentNum();
}
}