闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它 不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用城内,内部类有权操作所有的成员,包括private 成员。

Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调(callback)。通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。

稍后将会看到这是一个非常有用的概念。如果回调是通过指针实现的,那么就只能寄希望于程序员不会误用该指针。然而,您应该已经了解到,Java更小心仔细,所以没有在语言中包括指针。

通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活、更安全。见下例:

 // innerclasses/Callbacks.java
// Using inner classes for callbacks
package innerclasses
import static net.mindview.util.Print.*; interface Incrementable {
void increment();
} // Very simple to just implement the interface
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++
print(i);
}
} class MyIncrement {
public void increment() {print("Other operation");}
static void f(MyIncrement mi) {mi.increment();}
} // If your class must implement increment() in
// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
private int i=0;
public void increment() {
super.increment();
i++;
print(i);
}
private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise
// you'd get an infinite recursion
Callee2.this.increment();
}
}
Incrementable getCallbackReference() {
return new Closure();
}
} class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {callbackReference = cbh;}
void go() {callbackReference.increment();}
} public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Calleel();
Callee2 c2 = new Callee2();
MyIncrement.f(c2); Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}

输出:

Other operation
   1
   1
   2
   Other operation
   2
   Other operation
   3

这个例子进一步展示了外围类实现一个接口与内部类实现此接口之间的区别。就代码而言,Callee1是简单的解决方式。Callee2继承自MyIncrement,后者已经有了一个不同的increment()方法,并且与Incrementable接口期望的increment()方法完全不相关。

所以如果Callee2继承了MyIncrement,就不能为了Incrementable的用途而覆盖increment()方法,于是只能使用内部类独立地实现Incrementable。还要注意,当创建了一个内部类时,并没有在外围类的接口中添加东西,也没有修改外围类的接口。

注意,在Callee2中除了getCallbackReference()以外,其他成员都是private的。要想建立与外部世界的任何连
接,interface Incrementable都是必需的。在这里可以看到,interface是如何允许接口与接口的实现完全独立的。

内部类Closure实现了Incrementable,以提供一个返Callee2的“钩子”(hook)——而且是一个安全的钩子。无论谁获得此
Incrementable的引用,都只能调用increment(),除此之外没有其他功能(不像指针那样,允许您做很多事情)。

Caller的构造器需要一个Incrementable的引用作为参数(虽然可以在任意时刻捕获回调引用),然后在以后的某个时刻,(Caller对象可以使用此引用回调Callee类。

回调的价值在于它的灵活性——可以在运行时动态地决定需要调用什么方法。

以上来自:《java编程思想第三版》

动态语言的闭包是一个永恒的话题。闭包在编码过程的方便和快捷使得动态语言的拥护者对它津津乐道,而静态语言特别是Java语言的扇子们会拿出匿名内部类来说Java语言也有类似的功能。

JavaScript 中闭包的产生是由于 JavaScript 中允许内部 function,也就是在一个 function 内部声明的
function 。内部 function 可以访问外部 function 中的局部变量、传入的参数和其它内部 function 。当内部
function 可以在包含它的外部 function 之外被引用时,就形成了一个闭包。这个时候,即便外部 function
已经执行完成,该内部 function 仍然可以被执行,并且其中所用到的外部 function 的局部变量、传入的参数等仍然保留外部
function 执行结束时的值。下面是一个例子:

function Outer(){
var i=0;
function Inner(){
alert(++i);
}
return Inner;
}
var inner = Outer();
inner();

因为函数Outer外的变量inner引用了函数Outer内的函数Inner,就是说:当函数Outer的内部函数Inner被函数Outer外的一个变量inner引用的时候,就创建了一个闭包。

闭包有什么作用:简而言之,闭包的作用就是在Outer执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回Outer所占用的资源,因为Outer的内部函数Inner的执行需要依赖Outer中的变量。

闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含创建内部类的
作用域的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。

C++有指针函数,可以实现回调。通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。Java中没有指针,回调是通过匿名类来实现的。

>>>回调的一种理解<<<

回调的基本原理跟好莱坞原则一样,Don't call me,I'll call you.

编程上来说,一般使用一个库或类时,是你主动调用人家的API,这个叫Call,有的时候这样不能满足需要,需要你注册(注入)你自己的程序(比如一个对
象),然后让人家在合适的时候来调用你,这叫Callback。设计模式中的Observer就是例子:所有的观察者都需要向自己关心的主题
Observable注册,然后主题在适当时机(主题类对象的属性发生变化时)通知所有订阅它的观察者并更新,其中观察者都实现了一个统一的
Observer接口中的Update方法。

回调实质上是指一个类尽管实际上实现了某种功能,但是没有直接提供相应的接口,客户类可以通过这个类的内部类的接口来获得这种功能。而这个内部类本身并没有提供真正的实现,仅仅调用外部类的实现。可见,回调充分发挥了内部类所具有的访问外部类的实现细节的优势。

以上转自:http://jiangzhengjun.iteye.com/blog/658354

[转] Java内部类之闭包(closure)与回调(callback)的更多相关文章

  1. java 内部类和闭包

    内部类(inner class) public class Outer{ private String name; class Inner{ public String getOuterName(){ ...

  2. Java内部类(5):应用例

    例1-闭包(Closure) 闭包是一个可调用的对象(通过Callback),它记录了一些信息,这些信息来自于创建它的作用域 interface Incrementable { void increm ...

  3. Java内部类之间的闭包和回调详解

    前言 闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域.通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自 ...

  4. java中的闭包和回调

    闭包(Closure)是一种能被调用的对象,它保存了创建它的作用域的信息.JAVA并不能显式地支持闭包,但是在JAVA中,闭包可以通过“接口+内部类”来实现,因为对于非静态内部类而言,它不仅记录了其外 ...

  5. js闭包vs Java内部类

    前言: 昨天写了一个关于Java内部的博客,在内部类的最后一点中谈到了Java闭包的概念,他是这样定义闭包的:闭包是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域.结合Java的内部类 ...

  6. Java内部类学习笔记

    20160923 定义:将一个类的定义放在另一个类的内部: 从外部类的非静态方法之外,创建某个内部类的对象:OutClassName.InnerClassName: 内部类拥有所有其外部类的成员的访问 ...

  7. java内部类的一些看法

    java内部类, 我在看<thinking in java>的时候总感觉模棱两可的, 挣扎了好几天之后, 感觉有一部分的问题想的清楚了, 写一个随笔记录一下, 以备以后修改和查看 什么是内 ...

  8. JavaScript闭包(Closure)

    JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...

  9. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

随机推荐

  1. Pythonchallenge一起来闯关(二)

    前情提要:Pythonchallenge一起来闯关(一) 这一篇来闯关10-15.感觉这几关比先前的难了不少,有的题目完全没思路. 10. 页面源码中的链接点击后有a = [1, 11, 21, 12 ...

  2. android 05

    控件:RadioButton CheckedBox RatingBar ProgressBar 下拉列表:ListView Spinner <!-- 单选按钮必须放在单选按钮组当中才能生效 ,并 ...

  3. Q我音乐

  4. HTML语义化标签(一)

    总所周知,现在的网页是由HTML.CSS.JS三大元素组成,而HTML是其中最重要的部分,是整个网页的骨架,CSS和js在骨架的基础上进行相应的修饰,使得网页成为一个有血有肉,可以动的“人”.如果HT ...

  5. [Git]Git安装

    1.什么是Git Git是一个分布式版本控制/软件配置管理软件, git是用于Linux内核开发的版本控制工具, 与CVS.Subversion一类的集中式版本控制工具不同,它采用了分布式版本库的作法 ...

  6. CAFFE安装 CentOS无GPU

    前记 由于是在一台用了很久的机器上安装caffe,过程比较复杂,网上说再干净的机器上装比较简单.如果能有干净的机器,就不用再过这么多坑了,希望大家好运!介绍这里就不说了,直接进入正题: Caffe 主 ...

  7. MVC中的路由

    authour: chenboyi updatetime: 2015-05-02 16:10:04 friendly link:   目录 1,思维导图 2,MVC处理机制简图(讲解路由解析) 3,默 ...

  8. 原生网络请求:同步请求、异步请求、GET请求、POST请求

    1.同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作, 2.异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然 ...

  9. Debug与Release有时候确实不一致

    不一致的原因不清楚. 情况1:耗了整整一天,也没查出Debug状况下错误的原因(3个库函数,用了1年多了,已经熟练使用,不会有问题的).到现在还是没搞明白为什么出问题. 情况2:还是上面的三个函数,D ...

  10. pl/sql 在一个程序块里打印日志输出到表格

    declare v_number NUMBER; v_number2 NUMBER; begin execute immediate 'truncate table t2'; insert into ...