1

对于理解 Java 8 中以下两个概念的任何帮助,将不胜感激。

我知道的

  1. lambda 是没有标识的对象,不应用作常规对象。
  2. lambda 表达式不应该从Object类中调用方法,如,toString等。equalshashCode

我想了解更多

  1. lambda表达式必须被称为没有身份的对象有什么区别?

  2. 为什么Object在使用 lambda 表达式时不应该使用类中的方法?

4

2 回答 2

3

1) lambda 是没有标识的对象,不应用作常规对象。

这不是真的。lambda 是一个 Java 对象,它确实有一个标识1。问题是故意指定生命周期以允许 Java 编译器自由优化评估它们的代码。因此,您无法知道何时会创建新的 lambda 对象,或者何时会重用现有的 lambda 对象。

JLS 15.27.4说:

“在运行时,lambda 表达式的求值类似于类实例创建表达式的求值,只要正常完成产生对对象的引用。lambda 表达式的求值不同于 lambda 主体的执行。

分配并初始化具有以下属性的类的新实例,或者引用具有以下属性的类的现有实例。……”


2) lambda 表达式不应调用Object类中的方法,如,toString等。equalshashCode

正如所写,这也是不正确的。一个 lambda 表达式可以调用这些方法。但是,当您在 lambda 对象上调用这些方法时,不建议依赖这些方法具有任何特定行为

JLS 指出:

“该类......可能会覆盖Object该类的方法。”

换句话说,它可能......也可能不......覆盖它们。如果您依赖这些方法的特定行为,则您的应用程序(理论上)是不可移植的。

此外,由于实例化语义也未指定, 和 的行为Object::equalsObject::hashCode不确定的。

最后,未指定 lambda 是否可克隆。


1 - 当然,lambda 没有名称:它是匿名的。但是名称身份是不同的概念。

于 2020-06-14T04:55:51.467 回答
0

基本上,lambda 是这样做的一种便利:

@FunctionalInterface
interface A {
    void b();
}

void c(A a) {
    ...
}

void main() {
    c(new A() {
        void b() {
            ...
        }
    });
}

对于不那么出色的变量名称,我深表歉意,但正如您所见,A它是一种方法的接口。c是一个接受A接口的方法。A但是,您可以在现场创建它,而不是创建自己的实现类。这就是你所说的匿名类,因为它没有名字。这是您的报价:

A lambda is an object without an identify

来自。该类没有身份。它与 lambdas 相关的原因是因为如果一个接口只有一个方法,您可以使用 lamdas 来简化它。

void main() {
    c(
        () -> {
            ...
        }
    );
}

这和以前完全一样。

第二部分,为什么 lambdas 不应该使用Object's 方法,我以前不知道。您可能应该让其他人回答这个问题,但是我的猜测是 lambda 类看起来不像Object直接扩展,因此您不能使用它的方法。

于 2020-06-14T04:47:01.970 回答