android java 闭包

来源:互联网 发布:网络投资项目 编辑:程序博客网 时间:2024/06/06 20:11


这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

var result=[];function foo(){    var i= 0;    for (;i<3;i=i+1){        result[i]=function(){            alert(i)        }    }};foo();result[0](); // 3result[1](); // 3result[2](); // 3



这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

<pre name="code" class="javascript">var result=[];function foo(){    var i= 0;    for (;i<3;i=i+1){        result[i]=(function(j){            return function(){                alert(j);            };        })(i);    }};foo();result[0](); // 0result[1](); // 1result[2](); // 2


让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值

java

</pre><pre code_snippet_id="1560752" snippet_file_name="blog_20160121_4_4788078" name="code" class="java">interface Action {     void Run(); } public class ShareClosure {     List<Action> list = new ArrayList<Action>();     int i;    public void Input()     {         for(i=0;i<10;i++)         {             list.add(new Action() {                    @Override                 public void Run() {                     System.out.println(i);                 }             });         }     }         public void Output()     {         for(Action a : list){a.Run();}     }         public static void main(String[] args) {         ShareClosure sc = new ShareClosure();         sc.Input();         sc.Output();     } } 
输出:全部为10


<<Java编程思想>> 

  是一个匿名的代码块,可以接受参数,并返回一个返回值,也可以引用和使用在它 

周围的,可见域中定义的变量。-- Groovy ['ɡru:vi] 

  是一个表达式,它具有自由变量及邦定这些变量的上下文环境。 

  闭包允许你将一些行为封装,将它像一个对象一样传来递去,而且它依然能够访问 

到原来第一次声明时的上下文。 

  是指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这 

些变量也是该表达式的一部分。 

  闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任 

何全局上下文中定义的,而是在定义代码块的环境中定义。 

  在这些定义中都有一些关键字:变量、函数、上下文等,闭包在回调函数、函数式 

编程、Lambda表达式中有重要的应用


interface Action {     void Run(); } public class ShareClosure {     List<Action> list = new ArrayList<Action>();         public void Input()     {         for(int i=0;i<10;i++)         {             final int copy = i;             list.add(new Action() {                    @Override                 public void Run() {                     System.out.println(copy);                 }             });         }     }         public void Output()     {         for(Action a : list){a.Run();}     }         public static void main(String[] args) {         ShareClosure sc = new ShareClosure();         sc.Input();         sc.Output();     } } 
输出: 0-9



这两种代码是作用域不同引起的与堆栈管理有关




这个例子创建一个接口列表List<Action> ,先向列表中创建 i 个匿名内部类new 

Action(),然后通过for遍历读出。 

因为 i 变量在各个匿名内部类中使用,这里产生了闭包共享,java编译器会强制要求 

传入匿名内部类中的变量添加final 

关键字,所以这里final int copy = i;需要做一个内存拷贝,否则编译不过。(在c#中 

没有强制要求会导致列有被遍历时 

始终会取 i 最大值,这是因为延迟执行引起的) 





                                             
0 0