Don't pass 'this' out of a constructor
在一个类例,this关键字指向一个native对象,当前类的实例。在一个构造函数里,this一般有以下几种使用方式.
1. 在第一行,用this(...)调用其他构造函数
2. 用this.filedName的形式访问设置属性
3. 给其他对象的方法当参数,比如blah.operation(this);
最后一种方式会可能导致麻烦,问题是这样的,在构造函数里,当前对象是没有构造完的。一个构造完整的对象是在构造函数返回后的对象,而不返回之前。而当我们
传参数的时候,this指向的应该是一个完全构造好了的对象。
问题常常发生在listener模式上,下面就是个例子:
import java.util.Observable;
import java.util.Observer;
/**
@author javapractices.com
@author Andrew Sackett
*/
public final class EscapingThisReference {
/** 广播站被其他人监听. */
static final class RadioStation extends Observable {
//elided
}
/**
A listener which waits until this object is fully-formed before
it lets it be referenced by the outside world.
Uses a private constructor to first build the object, and then
configures the fully-formed object as a listener.
*/
static final class GoodListener implements Observer {
/** Factory method. */
static GoodListener buildListener(String aPersonsName, RadioStation aStation){
//first call the private constructor
GoodListener result = new GoodListener(aPersonsName);
//the 'result' object is now fully constructed, and can now be
//passed safely to the outside world
aStation.addObserver(result);
return result;
}
@Override public void update(Observable aStation, Object aData) {
//..elided
}
private String fPersonsName;
/** Private constructor. */
private GoodListener(String aPersonsName){
this.fPersonsName = aPersonsName; //ok
}
}
/**
A listener which incorrectly passes a 'this' reference to the outside world
before construction is completed.
*/
static final class BadListenerExplicit implements Observer {
/** Ordinary constructor. */
BadListenerExplicit(String aPersonsName, RadioStation aStation){
this.fPersonsName = aPersonsName; //OK
//DANGEROUS - the 'this' reference shouldn't be passed to the listener,
//since the constructor hasn't yet completed; it doesn't matter if
//this is the last statement in the constructor!
aStation.addObserver(this);
}
@Override public void update(Observable aStation, Object aData) {
//..elided
}
private String fPersonsName;
}
/**
Another listener that passes out a 'this' reference to the outside
world before construction is completed; here, the 'this' reference
is implicit, via the anonymous inner class.
*/
static final class BadListenerImplicit {
/** Ordinary constructor. */
BadListenerImplicit(String aPersonsName, RadioStation aStation){
this.fPersonsName = aPersonsName; //OK
//DANGEROUS
aStation.addObserver(
new Observer(){
@Override public void update(Observable aObservable, Object aData) {
doSomethingUseful();
}
}
);
}
private void doSomethingUseful() {
//..elided
}
private String fPersonsName;
}
}