在构造函数中使用对可覆盖方法的引用是否安全?

Dav*_*lfe 8 java lambda constructor java-8

当我使用在构造函数中调用可覆盖方法的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() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*etz 8

不,这绝对不是安全的.您正在发布this在完全构造对象之前可能被外来代码访问的位置.无论是通过匿名类还是通过lambda或方法引用,都可以从构造函数注册侦听器.你的例子相当于我在本文(12年前)警告过的成语:https://www.ibm.com/developerworks/library/j-jtp0618/

这里方法参考的参与是一个红鲱鱼; 问题是,您正在将对部分构造的对象的引用提供给您无法控制的代码.

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


ysh*_*vit 6

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

所以,这两者基本上是等价的.在方法引用的情况下,目标是显式的this,并且在lambda的情况下,它是隐式的this.所以,他们的"警告"是一样的.接下来的问题是:哪一个编译器出错了?警告是错误的还是没有警告?

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

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