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 Studio 的 lint 检查没有适配这种场景。