【问题标题】:Is using a reference to an overridable method in the constructor safe? [duplicate]在构造函数中使用对可覆盖方法的引用是否安全? [复制]
【发布时间】:2014-08-22 09:51:17
【问题描述】:

当我使用调用构造函数中可覆盖方法的 lambda 添加事件侦听器时,我收到警告。如果我使用方法引用,我不会收到任何关于可覆盖方法或泄漏的警告。我应该避免在构造函数中引用方法还是安全?

这是一个简单的例子:

public class SomeClass {

    public SomeClass(SomeObj obj) {
        obj.addListener(this::handleEvent); // no warnings, is it really safe?
        obj.addListener((event) -> handleEvent(event)); // warning about overridable method in constructor
    }

    private void handleEvent(Event event) {
        event.doSomething(someMethod());
    }

    private void someMethod() {
        ...
    }
}

【问题讨论】:

  • 我不确定(因此是评论,而不是回答)——但我看不出它如何是安全的。闭包必须包含 this 引用,并且 afaik 在 lambdas 中没有特殊考虑。
  • @SotiriosDelimanolis 为什么这很重要?警告是因为线程问题以及addListener 可能会调用未完全构造的this 上的方法。
  • @yshavit 给出的例子或多或少是等价的。如果其中一个没有发出警告,则可能只是缺少编译器功能(反之亦然)。
  • @SotiriosDelimanolis 当然,但这并不能回答它是否安全的问题。
  • @yshavit 请注意,他们提出的问题是假设 lambda 不安全,因为他们收到了警告。如果方法参考也有警告,他们可能不会问这个问题。如果他们在不同的编译器上尝试过这个,他们可能已经看到了警告并且没有任何疑问。此外,the examples given are more or less equivalent 暗示如果一个不安全,另一个也不安全。

标签: java constructor lambda java-8


【解决方案1】:

不,这绝对不安全。您正在发布this,在对象完全构建之前,它可能会被外星人代码访问。从构造函数注册侦听器始终是禁忌,无论您是通过匿名类还是通过 lambda 或方法引用。你的例子相当于我在这篇文章中警告过的成语(12年前!):https://www.ibm.com/developerworks/library/j-jtp0618/

这里涉及的方法引用是一个红鲱鱼;问题是您正在提供对部分构造对象的引用,以供您无法控制的代码使用。

编译器不能警告你所有的事情;仅仅因为没有警告并不意味着您的代码是正确的:)

【讨论】:

    【解决方案2】:

    方法引用和 lambda 都评估为相同的东西,一个功能接口:

    所以,两者本质上是等价的。在方法引用的情况下,目标是显式的this,而在 lambda 的情况下,它是隐式的this。所以,他们的“警告”是一样的。下一个问题是:编译器出错了?警告是错误的,还是没有警告?

    出现警告的原因是从构造函数中泄漏this 有几个很大的危险。一个与多线程有关:如果您从参考中泄漏this,您从final 字段语义(以及其他一些保证)获得的任何内存可见性保证都将消失。另一个问题是addListener 方法将在构造函数完成之前立即调用this 上的方法。也就是说,它将在部分构造的对象上调用方法。对于可覆盖的方法,这尤其是有问题,因为这个构造函数可能是用于其他人的超类,并且其他人已经覆盖了相关方法。在这种情况下,您将调用该子类的方法,其构造函数甚至还没有机会启动(因为首先运行超类的构造函数)。

    所以,是的,lambda 上的警告是正确的。它也应该用于方法参考。

    【讨论】:

      猜你喜欢
      • 2012-04-08
      • 2011-09-21
      • 1970-01-01
      • 2013-03-01
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多