spring boot

java 中的 this 逃逸

2020-10-11  本文已影响0人  你可记得叫安可

This 逃逸指的是对象还未构造完毕就对其进行了对外发布和使用。

多线程或内部类引起的 this 逃逸

这种错误的发生一般是因为在对象的构造函数中又构造了一个内部类,而内部类隐式地包含了 this 指针,并且内部类通过 this 指针隐式地使用了外部类中还未初始化的属性。

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
                new EventListener() {
                    public void onEvent(Event e) {
                        // 这里就可以使用未完全构造的 this 对象了
                        doSomething(e);
                    }
                }
        );
    }
}

上面就是内部类引起的 this 逃逸。上面代码中的 onEvent 可能在 ThisEscape 构造函数调用完毕前就被回调,而此时 ThisEscape 还未被完全构造。
如果想在构造函数中注册一个事件监听器或启动线程,那么可以使用一个私有的构造函数和一个公共的工厂方法,从而避免不正确的构造过程:

public class SafeListener {
    private final EventListener listener;
    
    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
    }
    
    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

因继承关系而导致的 this 逸出

继承导致的 this 逸出
如上所示,当我们在 non-final 类的构造方法中调用一个函数并传入 this 时,Android Studio 会提示我们 this 泄露。这是因为,MyLayout 类是 open 的,可能被子类继承,因此在调用 inflate 时,子类可能还没完成构造。inflate 方法可能会读取 this 中的一些属性,而这些属性可能还没有被初始化,从而导致不可预测的后果。

事实上,即使 MyLayout 不是 open 的类,上面的用法一样会出现 this 逃逸的问题。因为已经将未构造完成的 this 传给了类外的 LayoutInflater.inflate 方法。不过,去掉 open 关键字,将 MyLayout 变为 final 类就不会出现上面的提示,我觉得应该是 Android Studiolint 检查没有适配这种场景。

上一篇下一篇

猜你喜欢

热点阅读