一、概念
发布 (publish):指一个对象能够在当前作用域之外的代码中使用。
逸出(escape) : 指一个对象尚未构造完成已经发布,该对象引用被发布。
二、逸出方式
1、共有静态变量引用方式逸出
public static Set<Secret> knownSecrets ; public void initialize(){ knownSecrets = new HashSet<Secret>(); }
将对象放入静态变量中,任何类和线程都可以看到该对象,都可以遍历上述集合来获得该对象的引用。
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; } }
一个私有的构造函数和一个共有工厂方法,避免不正确构造。。