首页 > java > base > > 正文

深入理解Java闭包概念

发布人:zhoulujun@live.cn    点击:

闭包能够将一个方法作为一个变量去存储,这个方法有能力去访问所在类的自由变量。如何用变量去存储方法?java中能够保存方法的变量指的就是普通的对象?如何让这个普通对象能够访问所在类的自由变量?

闭包又称词法闭包

闭包最早定义为一种包含<环境成分>和<控制成分>的实体.

解释一:闭包是引用了自由变量的函数,这个被引用的变量将和这个函数一同存在。

解释二:闭包是函数和相关引用环境组成的实体。

注:<自由变量>:除了局部变量的其他变量

 

简单理解:闭包能够一个方法作为一个变量存储,这个方法有能力去访问所在类的自由变量。

Java中闭包实现

关键点:

如何用变量去存储方法?

java中能够保存方法的变量指的就是普通的对象

如何让这个普通对象能够访问所在类的自由变量?

纯天然的解决办法是:内部类。内部类能够访问外部类的所有属性及方法。

隐藏具体实现是内部类的作用之一,如何保证隐藏具体实现的同时还能将闭包传递到外部使用?

让内部类实现通用接口,然后将内部类对象向上转型为接口类型。

上述解决办法就是Java最常用的闭包实现办法(内部类+接口)

下面提供一个简单的实现

public class Milk {  
      
    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();  
    }  
  
}

上述例子中,通过调用Active的方法实现对Milk私有变量num进行修改。


有时候觉得直接使用set方法也可以直接修改private变量,但是从现实生活中来说让人去执行喝牛奶的动作比牛奶自己动手喝来的合理一些。


总结

1.实际项目中没怎么用过闭包,因此不能对他的好坏进行评论。

2.建议合理的使用闭包,不完全不使用,也不能滥用。

3.特别注意:闭包会导致资源不被回收,如上例,在main方法中将m设为null,使用haveMeals继续调用drink方法仍然会喝掉一瓶牛奶,说明Milk对象并没有被释放掉。