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

发布于 2024-11-16 09:58:22 字数 29 浏览 2 评论 0原文

看起来匿名类提供了闭包的基本功能,是真的吗?

It looks like anonymous class provides the basic functionality of closure, is that true?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枯叶蝶 2024-11-23 09:58:22

几乎没有区别。事实上,有一句关于闭包和对象的老话。闭包是穷人的对象,对象是穷人的闭包。就其功能而言,两者都同样强大。我们只是在争论表达能力。

在 Java 中,我们使用匿名对象对闭包进行建模。事实上,这里有一点历史是,最初Java有能力在不使用final的情况下修改外部作用域。这对于在本地方法范围内分配的对象来说工作得很好,但是当涉及到原语时,这引起了很多争议。基元是在堆栈上分配的,因此为了让它们能够在外部方法执行之后存活下来,Java 必须在堆上分配内存并将这些成员移到堆中。当时人们对垃圾收集还很陌生,他们不相信它,因此有人声称 Java 不应该在没有程序员明确指示的情况下分配内存。为了达成妥协,Java 决定使用 Final 关键字。

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

现在有趣的是Java可以消除这个限制并使用可选的final关键字,因为每个人都对垃圾收集器更加熟悉,并且从语言的角度来看它可以完全兼容。尽管解决此问题的方法很简单,只需在匿名对象上定义实例变量,并且您可以根据需要进行修改。事实上,通过编译器将公共实例变量添加到匿名类,并重写源代码以使用这些变量而不是堆栈变量,这可能是实现对本地范围的闭包样式引用的简单方法。

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;
}

我认为人们抱怨匿名内部类的原因更多地与静态类型与动态类型有关。在Java中,我们必须为匿名类的实现者和接受匿名类的代码定义一个商定的接口。我们必须这样做,以便我们可以在编译时键入检查所有内容。如果我们有第一类函数,那么 Java 需要定义一种语法来声明方法的参数和返回类型作为数据类型,以保持静态类型语言的类型安全。这几乎与定义接口一样复杂。 (一个接口可以定义多个方法,声明第一类方法的语法仅适用于一个方法)。您可以将其视为一种简短的接口语法。在底层,编译器可以在编译时将缩写形式转换为接口。

Java 可以做很多事情来改善匿名类体验,而无需放弃该语言或进行重大手术。

There is almost no difference. In fact the there is an old saying about closures and objects. Closures are the poor man's object, and objects are the poor man's closure. Both are equally powerful in terms of what they can do. We are only arguing over expressiveness.

In Java we are modeling closures with Anonymous Objects. In fact a little history here is that originally Java had the ability to modify the outward scope without the use of final. This works and worked fine for Objects allocated in the local method scope, but when it comes to primitives this caused lots of controversy. Primitives are allocated on the stack so in order for them to live past the execution of the outer method Java would have to allocate memory on the heap and move those members into the heap. At that time people were very new to garbage collection and they didn't trust it so the claim was Java shouldn't allocate memory without explicit instruction from the programmer. In efforts to strike a compromise Java decided to use the final keyword.

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

Now the interesting thing is that Java could remove that restriction and make use of the final keyword optional now that everyone is more comfortable with the garbage collector and it could be completely compatible from a language perspective. Although the work around for this issue is simple to define instance variables on your Anonymous Object and you can modify those as much as you wish. In fact that could be an easy way to implement closure style references to local scope by adding public instance variables to the anonymous class through the compiler, and rewriting the source code to use those instead of stack variables.

public Object someFunction() {
   int someValue = 0;

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

Would be rewritten to:

 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;
}

I think the reason people complain about Anonymous inner classes has more to do with static typing vs dynamic typing. In Java we have to define an agreed upon interface for the implementor of the anonymous class and the code accepting the anonymous class. We have to do that so we can type check everything at compile time. If we had 1st class functions then Java would need to define a syntax for declaring a method's parameters and return types as a data type to remain a statically typed language for type safety. This would almost be as complex as defining an interface. (An interface can define multiple methods, a syntax for declaring 1st class methods would only be for one method). You could think of this as a short form interface syntax. Under the hood the compiler could translate the short form notation to an interface at compile time.

There are a lot of things that could be done to Java to improve the Anonymous Class experience without ditching the language or major surgery.

与之呼应 2024-11-23 09:58:22

就它们都影响其他“私人”范围而言,在非常有限的意义上,是的。然而,差异如此之多,以至于答案可能是否定的。

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

虽然要进行垃圾收集的类的生命周期是通过持有内部类的人来延长的(类似于闭包在反弹到闭包时使变量保持活动状态),但 Java 通过绑定进行重命名的能力仅限于遵守现有的 Java 语法。

并且为了允许线程使用 Java 的线程争用模型正确地不破坏彼此的数据,内部类进一步限制对保证不会扰乱的数据(也称为最终局部变量)的访问。

这完全忽略了其他内部类(又名静态内部类),它们在感觉上略有不同。换句话说,它涉及闭包可以处理的一些项目,但达不到大多数人认为称为闭包所必需的最低要求。

As far as they both affect otherwise "private" scoping, in a very limited sense, yes. however, there are so many differences that the answer might as well be no.

Since Java lacks the ability to handle blocks of code as true R-values, inner classes cannot pass blocks of code as is typically done in continuations. Therefore the closure as a continuation technique is completely missing.

While the lifetime of a class to be garbage collected is extended by people holding inner classes (similar to closures keeping variables alive while being rebound to the closure), the ability of Java to do renaming via binding is limited to comply with the existing Java syntax.

And to allow threads to properly not stomp over each other's data using Java's thread contention model, inner classes are further restricted with access to data that is guaranteed not to upset, aka final locals.

This completely ignores the other inner classes (aka static inner classes) which is slightly different in feel. In other words, it touches upon a few items that closures could handle, but falls short of the minimum requirements that most people would consider necessary to be called a closure.

恏ㄋ傷疤忘ㄋ疼 2024-11-23 09:58:22

恕我直言,它们具有类似的目的,但是闭包旨在更简洁并可能提供更多功能。

假设您想通过匿名类来使用局部变量。

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; });

or if 闭包支持代码块。

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

IMHO, They serve a similar purpose, however a closure is intended to be more concise and potentially provide more functionality.

Say you want to use a local variable using an anonymous class.

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);

Closures avoid the need for most of the boiler plate coding by allowing you write just what is intended.

int i = 0;
double d = 0.0;

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

or even

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

or if closures support code blocks.

executor.submit() {
    d = i * 1.5; 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文