[14-01] 闭包
1、闭包的概念
所谓闭包,就是指“一个持有外部环境变量的函数”,与其说这是一种形式的函数,不如说这是一种程序结构。这个概念更多在JavaScript中提到,在JS中我们知道,函数是可以作为对象返回的,于是看下面这样的方法:
function foo(){
var local = 0
function bar(){
local++
console.log(local)
return local
}
return bar
}9
1
function foo(){ 2
var local = 03
function bar(){4
local++5
console.log(local)6
return local7
}8
return bar9
}外层函数将保存了信息的可执行内层函数作为结果返回,即这里的foo()将保存了local局部变量信息的可执行内层函数bar()作为结果返回。所以刚才我们说的概念“一个持有外部环境变量的函数”,也就是指这种结构情况下的bar()了。
然后使用的时候可能就是这样:
var func = foo()
func()2
1
var func = foo()2
func()打开你的Chrome,试着把这段代码执行一下,看看它有什么用,其实就是个计数器而已,每运行一次func(),就计数一次:

所以这个例子中闭包有什么用呢
- 隐藏变量:给你的方法func()中是有变量的,但是JS中不像Java有private权限修饰,可你能访问吗,能擅自修改吗?不能
2、Java中闭包的实现
好了,我们借用JS来理解一下“闭包”的概念,那么Java如何实现闭包呢,Java并不支持在方法中返回一个方法呀?在JS中是外层函数包含变量和内部函数,Java中其实就是类包含成员变量和内部类。因为内部类可以直接访问外部类的信息(即便是private),这就满足了“一个持有外部环境变量的 '函数' ”:
- 如何用变量去存储方法
- Java中能够保存方法的变量其实就是普通的对象
- 如何让这个对象能够访问所在类的自由变量
- 内部类,其能够访问外部类的所有属性和方法
那么上面那个JS的闭包计数器,用Java来写就是这样:
public class Foo {
//成员变量
private int local = 0;
//内部类
class Bar {
public int func() {
local++;
System.out.println(local);
return local;
}
}
//返回一个内部类的引用
public Bar getBar() {
return new Bar();
}
}19
1
public class Foo {2
//成员变量3
private int local = 0;4
5
//内部类6
class Bar {7
public int func() {8
local++;9
System.out.println(local);10
return local;11
}12
}13
14
//返回一个内部类的引用15
public Bar getBar() {16
return new Bar();17
}18
19
}public class Test {
public static void main(String[] args) {
Foo.Bar bar = new Foo().getBar();
bar.func(); //打印1
bar.func(); //打印2
bar.func(); //打印3
}
}8
1
public class Test {2
public static void main(String[] args) {3
Foo.Bar bar = new Foo().getBar();4
bar.func(); //打印15
bar.func(); //打印26
bar.func(); //打印37
}8
}更多时候我们采用“接口+匿名内部类”的形式,面向接口更加灵活(给外部留出通道,即可以接收这个内部类),同时更好地隐藏内部类,所以我们再修改一下:
public interface Bar {
int func();
}3
1
public interface Bar {2
int func();3
}public class Foo {
//成员变量
private int local = 0;
//匿名内部类
class Inner implements Bar {
@Override
public int func() {
local++;
System.out.println(local);
return local;
}
}
//返回一个匿名内部类的引用
public Bar getBar() {
return new Inner();
}
}20
1
public class Foo {2
//成员变量3
private int local = 0;4
5
//匿名内部类6
class Inner implements Bar {7
8
public int func() {9
local++;10
System.out.println(local);11
return local;12
}13
}14
15
//返回一个匿名内部类的引用16
public Bar getBar() {17
return new Inner();18
}19
20
}public class Test {
public static void main(String[] args) {
Bar bar = new Foo().getBar();
bar.func();
bar.func();
bar.func();
}
}8
1
public class Test {2
public static void main(String[] args) {3
Bar bar = new Foo().getBar();4
bar.func();5
bar.func();6
bar.func();7
}8
}3、一个示例
Teachable接口和Programmer基类都提供了work方法,现在有个人既是老师也是程序员,即他要继承Programmer类又要实现Teachable接口,如何处理work方法同名的问题?闭包。实际上,下面的例子稍作修改,也同样适用于委婉的多继承。
public interface Teachable {
public void work();
}3
1
public interface Teachable {2
public void work();3
}public class Programmer {
private String name;
public Programmer() {
}
public Programmer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void work() {
System.out.println(name + " is coding right now.");
}
}23
1
public class Programmer {2
private String name;3
4
public Programmer() {5
}6
7
public Programmer(String name) {8
this.name = name;9
}10
11
public String getName() {12
return name;13
}14
15
public void setName(String name) {16
this.name = name;17
}18
19
public void work() {20
System.out.println(name + " is coding right now.");21
}22
23
}public class TeachableProgrammer extends Programmer {
public TeachableProgrammer() {
}
public TeachableProgrammer(String name) {
super(name);
}
public void work() {
super.work();
}
public void teach() {
getCallbackReference().work();
}
private class Inner implements Teachable {
@Override
public void work() {
System.out.println(TeachableProgrammer.this.getName() + " is teaching right now.");
}
}
public Teachable getCallbackReference() {
return new Inner();
}
}29
1
public class TeachableProgrammer extends Programmer {2
3
public TeachableProgrammer() {4
}5
6
public TeachableProgrammer(String name) {7
super(name);8
}9
10
public void work() {11
super.work();12
}13
14
public void teach() {15
getCallbackReference().work();16
}17
18
private class Inner implements Teachable {19
20
public void work() {21
System.out.println(TeachableProgrammer.this.getName() + " is teaching right now.");22
}23
}24
25
public Teachable getCallbackReference() {26
return new Inner();27
}28
29
}public class Test {
public static void main(String[] args) {
TeachableProgrammer person = new TeachableProgrammer("David");
person.work();
person.teach();
}
}
//David is coding right now.
//David is teaching right now.x
1
public class Test {2
public static void main(String[] args) {3
TeachableProgrammer person = new TeachableProgrammer("David");4
person.work();5
person.teach();6
}7
}8
9
//David is coding right now.10
//David is teaching right now.4、内部类的意义小结
- 更好的封装和信息隐藏
- 可以访问外部类的所有元素,实现闭包
- 可以避免修改接口而实现同一个类中两种同名方法的调用
- 间接实现多重继承

浙公网安备 33010602011771号