关闭和回调

时间:2010-03-18 09:55:34

标签: java closures

除了内部类之外,java中还有其他方法可以实现回调吗?回调和闭包之间有什么区别?

9 个答案:

答案 0 :(得分:10)

关闭是你如何构建它,回调就是你如何使用它。

回调可以实现为闭包(在具有它们的语言中)或接口的实现(在Java中,作为匿名内部类或常规类)。

回调意味着您将一段代码传递给一个函数,以便该函数可以稍后调用该段代码。这是一种特殊的参数。

这段代码可以是函数指针或闭包或具有众所周知方法的对象,具体取决于语言提供的内容。

答案 1 :(得分:5)

闭包和匿名内部类(以及其他)都可以用作回调。 callback只是一些代码,它作为参数传递给其他代码。

与Java的匿名内部类相比,闭包的一个重要区别在于(在命令式语言中)闭包可以修改周围范围的变量。 Wikipedia给出了以下示例:

var f, g;
function foo() {
  var x = 0;
  f = function() { return ++x; };
  g = function() { return --x; };
  x = 1;
  alert('inside foo, call to f(): ' + f()); // "2"
}
foo();
alert('call to g(): ' + g()); // "1"
alert('call to f(): ' + f()); // "2"

答案 2 :(得分:1)

回调只是作为参数传递给其他代码的任何可执行代码。在频繁使用中,该可执行代码是一个闭包,但不一定。

关闭这个词有点滥用,许多人只是将它用作“匿名函数”的同义词,但至少according to Wikipedia,这是对该术语的误用。维基百科的文章解释得比我能做得更快。

答案 3 :(得分:1)

如果您需要在java中使用闭包,可以尝试lambdajHere你可以看到它如何通过一个非常简单的DSL来定义闭包。

答案 4 :(得分:0)

我不这么认为。

如果有,那么它可能在某种程度上是劣等的,否则匿名的内部类将不会被广泛使用。

答案 5 :(得分:0)

没有区别。

可以将闭包定义为包含可以轻松执行的父上下文的代码块。

事实上,我之间唯一的区别就是写作的简易性。一个典型的groovy / ruby​​闭包确实比Java匿名类更小。

然而,考虑到像guava这样的Java框架,并且自由使用匿名类/接口,特别是对于典型的闭包,使用像filter这样的情况(与groovy的implementation比较),我可以说绝对没有设计差异。

答案 6 :(得分:0)

可悲的是,唯一合理的方式是内部/匿名课程。

您也可以使用反射来实现,但这通常更慢,更难维护(没有语法突出显示,很难在IDE中找到引用等)。一个例子:

myButton.addActionListener(EventHandler.create(ActionListener.class, handlerObject, "onClick"));

答案 7 :(得分:0)

现在,匿名类是处理Java中回调的最佳方法。然而,这可能会改变Java 7,它将实现闭包。 http://en.wikipedia.org/wiki/Closure_(computer_science)

答案 8 :(得分:0)

这是两个使用闭包和回调的实现。

这是一个更好的例子(可以在这里找到http://www.caglargonul.com/2013/04/10/is-it-really-a-closure-yes-it-is/)来理解闭包是什么。关键是

  

闭包带有引用环境而不仅仅是功能代码。

在Java 7及更低版本中实现闭包的最佳方法是使用接口。在此示例中,回调实现为闭包。

首先声明你的界面将保留你的闭包。

public interface CallBack {
    void m(int e);
}

让我们添加一个负责保存闭包数组的类,两个用于添加和删除闭包的公共方法,以及一个在事件发生时调用闭包内函数的公共函数。

public class CCallBack {

    List<CallBack> cbs = new ArrayList<>();

    public void registerCallBack(CallBack f){
        cbs.add(f);
    }

    public void removeCallBack(CallBack f){
        if(cbs.contains(f)){
            cbs.remove(f);
        }
    }

    public void onAction(int i){
        for (CallBack callBack : cbs) {
            callBack.m(i);
        }
    }
}

这是神奇的部分。请参阅实际参考环境。

public class CallBackTester {
    CCallBack cb = new CCallBack();

    @Test
    public void test_callback(){

        CallBack cb1 = new CallBack() {
            int x = 1;
            @Override
            public void m(int e) {
                if(e==1){
                    System.out.println("You register this callback " + x + " time/times");
                    x++;
                }
            }
        };

        cb.registerCallBack(cb1);
        cb.registerCallBack(cb1);
        cb.registerCallBack(cb1);
        cb.removeCallBack(cb1);

        cb.onAction(1);
    }

}

当我们声明cb1时,我们正在添加一个由变量x组成的引用环境。当我们在这个闭包中调用函数时,我们将这个变量递增一个。如果它是一个普通函数,当我们调用该函数时,x将被声明为1。但这不是一个正常的功能。这是一个关闭。所以每次我们在闭包中调用函数时都不会声明x。正如您在每次调用输出时所看到的那样,x正在递增。

You register this callback 1 time/times
You register this callback 2 time/times