首先,让我们来看闭包的定义:在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
对于这样的定义,会让部分同学更加迷糊。到底什么是闭包?要能清晰认识闭包,从实际的定义闭包代码中可能可以更加快速的了解。首先,我们先用JavaScript来展示闭包。(函数式语言的闭包是最容易理解的。)
function funParent(value) { var upvalue=value; return function (item) { return item > upvalue; } } var ob = funParent(0); //var ob = funParent(10); //var ob = funParent(20); alert(ob(15)); alert(ob(5));
这段代码很简单,通过funParent返回的函数中使用了在funParent的作用域之内的变量upvalue,upvalue离开了被定义的作用域但是没有被GC回收,而是继续被ob所使用,成为了一个自由变量,此时upvalue和ob在一起就形成了闭包。
为了对比,再用下面的2个例子来说明对于闭包的判断:
function funParent() { var upvalue = 10; return function (item) { return item > upvalue; } }
function funParent(value) { var upvalue = value; return function (item) { return item > 10; } }
上面的2个例子都是根据上面的例子改写而来,通过之前的描述,可以发现当例1的funParent执行之后,返回的匿名函数需要使用到自身作用域之外的变量upvalue,如是就需要将upvalue作为自由变量和自己捆绑,于是形成了闭包。而例2中,返回的匿名函数并没有使用到作用域之外的外部变量,因此没有形成闭包(匿名函数经常使用闭包,但匿名函数!=闭包)。
对于函数式语言,函数是第一级的,闭包很清晰很容易理解。理解了函数式语言中的闭包,再来理解Java中的闭包会更加容易。
/**Java Begin*/ public class JavaStart { public static void main(String[] args){ Closure ob=new UpClass(0).GetClass(); //Closure ob=new UpClass(10).GetClass(); //Closure ob=new UpClass(20).GetClass(); System.out.println(ob.Check(5)); System.out.println(ob.Check(15)); } } interface Closure{ Boolean Check(int item); } class UpClass{ private int checkValue; public UpClass(int value){ checkValue=value; } public Closure GetClass(){ return new Closure(){ public Boolean Check(int item){ return item>UpClass.this.checkValue; } }; } }
在Java7中,实现了lambda表达式(代码的书写方式和C#类似),可以不使用内部类来实现闭包。这里就不多说了。
在C#中有委托可以方便的实现闭包(JAVA学习,不过多涉及到C#)。