一、概念
发布 (publish):指一个对象能够在当前作用域之外的代码中使用。
逸出(escape) : 指一个对象尚未构造完成已经发布,该对象引用被发布。
二、逸出方式
1、共有静态变量引用方式逸出
public static Set knownSecrets ;
public void initialize(){
knownSecrets = new HashSet();
}
将对象放入静态变量中,任何类和线程都可以看到该对象,都可以遍历上述集合来获得该对象的引用。
2、非私有方法返回引用方式逸出
class UnsafeStates {
private String[] states = new String[]{“AK”, “AL”};
public String[] getStates() {
return states;
}
}
私有变量通过非私有方法发布出去导致该私有变量逸出当前作用域,成为了共有变量,
任何调用者都可以修改此变量的内容
3、this逸出
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
这种发布是发布一个内部的实现类,ThisEscape发布EventListener时,隐含地发布了ThisEscape实例本身,
因为这个内部类中含有ThisEscape的实例并且调用了ThisEscape的doSomething 方法,此时ThisEscape
对象还未构造完成,已经对外发布了该实例的引用。在构造尚未完成时就发布了对象引用成为不正确构造
注意:不要在构造函数中使this逸出
在构造过程中使this逸出的一个常见错误是:在构造函数中启动一个新线程。当对象在构造函数中
创建一个 线程时,无论是显式创建(通过将他传给构造函数即构造函数中使用了对象引用)还是
隐式创建(由于Thread或Runnable是该对象的一个内部类),this引用都会被新创建的线程共享。
在对象未完成构造之前,新线程就可以看到它。在构造函数中创建线程并没有错,但不要立刻
启动它,而是通过一个start或initialize方法来启动(详解:服务生命周期的内容)。
书中给出解决该种逸出的方法
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;
}
}
一个私有的构造函数和一个共有工厂方法,避免不正确构造。。