Java中的匿名类和闭包有什么区别?

它看起来像匿名类提供了闭包的基本function,是真的吗?

只要它们都影响其他“私人”的范围,在一个非常有限的意义上,是的。 然而,有太多的分歧,答案可能不是。

由于Java缺乏将代码块作为真正的R值进行处理的能力,所以内部类不能像inheritance中通常所做的那样传递代码块。 因此封闭作为一种延续技术是完全没有的。

虽然被垃圾收集的类的生命周期被持有内部类的人所扩展(类似于闭包在变为活着的同时被重新封闭),但Java通过绑定进行重命名的能力仅限于遵循现有的Java语法。

为了让线程正确地不使用Java的线程争用模型来压低对方的数据,内部类进一步被限制访问保证不会令人不安的数据,也就是最终的本地人。

这完全忽略了其他内部类(又称静态内部类),它们的感觉略有不同。 换句话说,它触及了一些封闭能够处理的事项,但是却达不到大多数人认为必须被称为封闭的最低要求。

几乎没有区别。 事实上,关于封闭物和对象有一句老话。 封闭是穷人的对象,对象是穷人的封闭。 就他们能做的事情而言,两者同样强大。 我们只是在expression性上争论。

在Java中,我们使用匿名对象来build模闭包。 实际上,这里有一点历史,原本Java有能力在不使用final的情况下修改外部范围。 这对于在本地方法范围内分配的对象来说工作得很好,但对于基元来说,这引起了很多争议。 原语被分配在堆栈上,所以为了让它们活过外部方法的执行,Java将不得不在堆上分配内存,并将这些成员移到堆中。 那时人们对垃圾收集是非常陌生的,他们不信任它,所以声称Java不应该在没有程序员的明确指示的情况下分配内存。 为了达成妥协,Java决定使用final关键字。

http://madbean.com/2003/mb2003-49/

现在有趣的是,Java可以删除这个限制,并使用final关键字可选,现在每个人都更加习惯垃圾回收器,并且从语言的angular度来看,它可以完全兼容。 虽然这个问题的解决方法很简单,可以在匿名对象上定义实例variables,并且可以根据需要修改它们。 实际上,通过编译器将公共实例variables添加到匿名类中,并重写源代码以使用那些代码来替代堆栈variables,可能是一种简单的方法来实现对本地作用域的闭包样式引用。

 public Object someFunction() { int someValue = 0; SomeAnonymousClass implementation = new SomeAnonymousClass() { public boolean callback() { someValue++; } } implementation.callback(); return someValue; } 

将被重写为:

  public Object someFunction() { SomeAnonymousClass implementation = new SomeAnonymousClass() { public int someValue = 0; public boolean callback() { someValue++; } } implementation.callback(); // all references to someValue could be rewritten to // use this instance variable instead. return implementation.someValue; } 

我认为人们抱怨匿名内部类的原因更多地与静态types和dynamictypes有关。 在Java中,我们必须为匿名类的实现者和接受匿名类的代码定义一个同意的接口。 我们必须这样做,所以我们可以在编译时键入检查所有内容。 如果我们有第一类函数,那么Java将需要定义一个语法来声明一个方法的参数并返回types作为数据types,以保持types安全的静态types语言。 这几乎和界定界面一样复杂。 (一个接口可以定义多个方法,声明第一类方法的语法只能用于一个方法)。 你可以把它看作一个简短的界面语法。 在编译的时候,编译器可以在编译时将短格式符号翻译成接口。

有很多事情可以通过Java来完成,而不用抛弃语言或大手术来提高匿名类的体验。

恕我直言,他们服务于类似的目的,但封闭意图是更简洁,可能提供更多的function。

假设你想使用一个匿名类的局部variables。

 final int[] i = { 0 }; final double[] d = { 0.0 }; Runnable run = new Runnable() { public void run() { d[0] = i[0] * 1.5; } }; executor.submit(run); 

通过允许你写出预期的内容,封闭避免了大部分的锅炉板编码。

 int i = 0; double d = 0.0; Runnable run = { => d = i * 1.5; }; executor.submit(run); 

甚至

 executor.submit({ => d = i * 1.5; }); 

或者如果closures支持代码块。

 executor.submit() { d = i * 1.5; }