[转] Java内部类之闭包(closure)与回调(callback)

闭包(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

时间: 2024-10-20 19:39:24

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

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

前言 闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域.通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用城内,内部类有权操作所有的成员,包括private成员. Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调(callback).通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象.如果回调是通

【ThinkingInJava】18、 关于java中的闭包与回调

/** * 书本:<Thinking In Java> * 功能:关于java中的闭包与回调,这里回调区别于C++,C++中回调的话寄托于指针 * 文件:Callbacks.java * 时间:2015年4月3日20:26:43 * 作者:cutter_point */ package Lession10innerclasses; import static net.mindview.util.Print.*; //创建一个接口,包含一个函数 interface Incrementable {

Swift 闭包(Closure)回调传值

实现例子由两个界面组成 A - > B 使用属性传值 B - > A 使用闭包进行反向回调传值 Swift 使用闭包(Closure)传值的原理,与OC 中使用代码块(block)传值原理,基本类似 按步骤可以如下理解: 1.定义闭包. 2.闭包赋值(传送) 3.闭包调用. 至于定义闭包应该在哪个页面定义? 想对于当前界面上执行某个操作,就在当前界面上定义, 比如:我想给通过 B 界面回调 给 A 界面上的文本框赋值,赋值操作是在 A 界面上执行的.那么闭包就应该定义在 A 界面上.既然定义在

java内部类之js闭包

前言: 今天写了一个关于Java内部的博客,在内部类的最后一点中谈到了Java闭包的概念,他是这样定义闭包的:闭包是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域.结合Java的内部类可以很好的理解这一点(如有需要可参考https://www.cnblogs.com/jinliang374003909/p/10351877.html).突然之间想到js中的闭包,一直都无法很好的理解,故借此又看了一下js中的闭包,对我个人而言,感悟良多,借此也与大家分享一下,希望可以帮助大家,并一

java内部类的一些看法

java内部类, 我在看<thinking in java>的时候总感觉模棱两可的, 挣扎了好几天之后, 感觉有一部分的问题想的清楚了, 写一个随笔记录一下, 以备以后修改和查看 什么是内部类? 内部类说白了就是类套类, 在一个类里面写一个类, 内部类分为两种, 一种是普通内部类(non-static nested class), 第二种是静态内部类(static nested class),也叫嵌套类. 普通内部类还包括两种特殊的类型, 一种是局部内部类, 另一种是匿名内部类 内部类有什么作

Java内部类

本文是<Java核心技术 卷1>中第六章接口与内部类中关于内部类的阅读总结. Java中的内部类(inner class)是定义在另一个类内部的类.那么内部类有什么用呢?这里主要由三个内部类存在的原因: 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据.即,如果类A中定义了类B,那么类B可以访问类A中的数据,甚至是私有数据,但类A不能访问类B中的私有数据: 内部类可以对同一个包中的其他类隐藏起来.在一个包中,定义一个类时,即使不加上访问权限关键词,这个类也是包内其他类可访问的,不

Java内部类的使用小结

内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. *内部类可以是静态static的,也可用public,default,protected和private修饰.(而外部顶级类即类名和文件名相同的只能使用public和default). 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类.对于一个名为outer的外部类和其内部定义的名为inner的内部类.编译完成后出现outer.class和outer$inner.class两类.所以内部类的成员变量/方法名可

[转] Java内部类详解

作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就来一探究竟.下面是本文的目录大纲: 一.内部类基础 二.

Java内部类学习笔记

这是我学习Java内部类的笔记 1.为什么使用内部类?使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:(1).内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独.(2).在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类.(3).创建内部类对象的时