Java 闭包
关于“闭包”,重在理解思想,总结一下,如有不正确的地方,多多指教。
首先来看一个例子,如下:
public class SingleCalculator {
int x;
int addWith(int y){
return x + y;
}
public static void main(String[] args) {
SingleCalculator cal = new SingleCalculator();
cal.x = 1;
int result = cal.addWith(2);
System.out.println("1 + 2 = " +result);
}
}
在上面,AddWith方法有一个参数y,且必须依赖AddWith方法体(相当于一个代码块)外部的自由变量x,因此,AddWith方法本身就是一个闭包;
闭包是指包含自由变量的代码块,它是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域。
拥有自由变量的函数是一种形式,如上图所示,外部环境持有内部函数所使用的自由变量,对内部函数形成“闭包”,简单但不严格的说,一个函数的“自由变量”就是既不是参数也不是局部变量的变量。
从上面的例子中,我们应该注意到一个小细节,也就是addWith方法持有一个外部对象的引用this,实际形式应该是这样:
int addWith(int y){
return this.x + y;
}
这让我们想到了Java内部类,它不仅包含外部类对象(创建内部类的作用域)的信息,而且还拥有一个指向外部类对象的引用,在此作用域内,内部类可以访问外部类的所有成员,包括private成员;内部类是面向对象的闭包。
内部类的形式有好多种:
- 内部类
public class InnerClassCalculator {
int x;
class Calculable{
int addWith(int y){
System.out.println("自由变量 x="+x);
return x + y;
}
}
public static void main(String[] args) {
InnerClassCalculator cal = new InnerClassCalculator();
cal.x = 1;
int result = cal.new Calculable().addWith(2) ;
System.out.println("1 + 2 = " +result);
}
}
- 局部内部类
import java.util.Random;
public class LocalInnerClassCalculator {
int x;
int addWith(int y){
class Calculable{
void printNum(){
System.out.println("自由变量 x="+x);
}
}
new Calculable().printNum();
return x+y;
}
public static void main(String[] args) {
LocalInnerClassCalculator cal = new LocalInnerClassCalculator();
cal.x = 1;
int result = cal.addWith(2) ;
System.out.println("1 + 2 = " +result);
}
}
- 匿名内部类
public class AnonymousInnerClassCalculator {
int x;
int result;
Calculable innerCal = new Calculable(){
int addWith(int y) {
System.out.println("自由变量 x="+x);
return x+y;
}
};
public static void main(String[] args) {
AnonymousInnerClassCalculator cal = new AnonymousInnerClassCalculator();
cal.x = 1;
int result = cal.innerCal.addWith(2);
System.out.println("1 + 2 = " +result);
}
}
abstract class Calculable{
abstract int addWith(int y);
}
当然上面的例子只是说明自由变量在内部类的存在形式,实际上内部类的好处有很多,比如
(1)内部类可以很好的实现细节隐藏
(2)内部类拥有外围类的所有元素的访问权限
(3)内部类可以实现多重继承
(4)内部类可以避免修改接口而实现同一个类中两种同名方法的调用
这些你都可以间接理解为闭包的好处。闭包的价值在于可以做为函数对象或者匿名函数,持有上下文数据,作为第一级对象进行传递和保存。闭包广泛用于回调函数、函数式编程中。
参考资料
https://rednaxelafx.iteye.com/blog/245022
https://www.cnblogs.com/uu5666/p/8185061.html