之前总结了下匿名内部类,想到了js的闭包,那么java有没有闭包相关的动作呢?
回去翻了翻《JAVA编程思想》发现有闭包和回调的相关说明,但书中的说法不是很好理解,因为有些兴趣,仿照着书中代码做个例子看看。稍微研究下。代码如下:
// 增加计数功能定义
// 注意,接口只存在一个void increment(),所以所有实现它的对象中,
// 只存在public的void increment,其他的成员都是private
interface Incremental {
void increment();
}
// 调用者:保存计数功能对象,并调用
class Caller{
private Incremental callbackReference;
Caller(Incremental incrementable){callbackReference = incrementable;}
void go(){callbackReference.increment();}
}
// 实现class1:简单的实现增加计数
class Callee1 implements Incremental {
private int num = 0;
@Override
public void increment() {
System.out.println("Callee1:增加计数功能实现"+(++num));
}
}
// 实现class2:在实现功能的同时实现回调
class Callee2 extends Callback implements Incremental {
private int num = 0;
@Override
public void increment(){
System.out.println("Callee2:增加计数功能实现"+(++num));
super.increment();
}
// 闭包,内部类Closure调用了外部变量num
private class Closure implements Incremental {
@Override
public void increment() {
System.out.println("Callee2-Closure:增加计数功能实现"+(++num));
Callee2.super.increment();
}
}
public Incremental getCallbackReference(){
return new Closure();
}
}
// 回调用类
class Callback {
public void increment(){System.out.println("回调内容执行...");}
static void fun(Callback myIncrement){myIncrement.increment();}
}
public class test_closure {
// 执行部分
public static void main(String[] arge){
// 简单的实现,使用调用者调用
Caller caller1 = new Caller(new Callee1());
caller1.go();
caller1.go();
// 结果:
// Callee1:增加计数功能实现1
// Callee1:增加计数功能实现2
// 追加回调方法的实现
// 回调对象执行实现对象
Callee2 callee2 = new Callee2();
Callback.fun(callee2);
// 结果:
// Callee2:增加计数功能实现1
// 回调内容执行...
// 使用调用者调用
Caller caller2 = new Caller(callee2.getCallbackReference());
caller2.go();
caller2.go();
// 结果:
// Callee2-Closure:增加计数功能实现2
// 回调内容执行...
// Callee2-Closure:增加计数功能实现3
// 回调内容执行...
}
}
以上是经过理解并追加注释的结果,书上的代码例子,不敲下来实在太难理解了……
注意是Callee1只是对比用,没回调和闭包,Callee2中存在内部类,内部类调用了Callee2的私有变量num——闭包;Callee2的getCallbackReference方法返回内部类,而内部类中,实现了接口的同时,调用了回调类的内容——回调。
……说实话,不知道是思维方式还是理解能力的问题,觉得这个例子实在很麻烦。还是自己弄个例子吧。
****
闭包
那么,首先是闭包。说道闭包,还是js比较多,那么,这里随便写个例子。
function Incrementable(){
var num = 0;
return function(){ // 这里,类似java直接返回内部类
num = num+1;
console.log(num)
}
}
var Callee = Incrementable();
Callee();
Callee();
console.log(num);
// 执行结果:
1
2
Uncaught ReferenceError: i is not defined
这个例子其实和之前java的闭包例子是一样,同样是自增的实现,内部变量num在Incrementable之外无法访问,但是Incrementable内的function内部可以访问。
将以上的例子转成java的话是这样的:
// 自增长接口和实现类
interface Incrementable{
void increment();
}
class Callee {
private int num = 0;
public Incrementable getIncrementable(){
return new Incrementable(){
@Override
public void increment() {
System.out.println("Callee:增加计数功能实现"+(++num));
}
};
}
}
public class test_closure2 {
// 执行部分
public static void main(String[] arge){
Callee callee = new Callee();
callee.getIncrementable().increment();
callee.getIncrementable().increment();
callee.getIncrementable().increment();
// 结果:
// Callee:增加计数功能实现1
// Callee:增加计数功能实现2
// Callee:增加计数功能实现3
}
}
可以看到,java类似js一样的,对内部的num变量实现了改变。一般工作中可能不这么写,但是翻翻源码,如此定义的方式还是很多的。原因在于这是一种不改变原本结构进行更新的方法,也可以根据结构的变化,切换功能,需要注意。