對(duì)象的發(fā)布
“發(fā)布對(duì)象”指的是使對(duì)象能夠在當(dāng)前作用于之外的代碼中使用
例如讨盒,將一個(gè)指向該對(duì)象的引用保存到其他代碼可以訪(fǎng)問(wèn)的地方(情況一),或者在某一個(gè)非私有的方法中返回該引用(情況二),或者將引用傳遞到其他類(lèi)的方法中(情況三)绩郎。
//情況一
public class Person(){
private String name;
private int age;
}
public class Record{
Person p;
}
//情況二
public class Person(){
private String name;
private int age;
public Person get(){
return new Person();
}
}
//情況三
public class Person(){
private String name;
private int age;
}
public class Record{
private void getPersonMessage(Person p){
.....
}
}
對(duì)象逸出
當(dāng)某個(gè)不應(yīng)該發(fā)布的對(duì)象被發(fā)布時(shí)蔼水,這種情況就被稱(chēng)為“對(duì)象逸出”。
常見(jiàn)的對(duì)象逸出:
- 內(nèi)部的可變狀態(tài)逸出
class UnsafeStates{
private String[] states = {"AK","AL",...};
public String[] getStates(){
return states;
}
}
如上女揭,數(shù)組states本事私有的變量蚤假,但是以public公有的方式發(fā)布出去,導(dǎo)致states已經(jīng)逸出了它所在的作用域吧兔,任何調(diào)用者都能修改這個(gè)數(shù)組的內(nèi)容磷仰。
- 隱式地使this引用逸出
public class ThisEscape{
public ThisEscape(EventSource source){
source.registerListener(
new EventListener(){
public void onEvent(Event e){
dosomething(e);
}
})
}
}
實(shí)際上,這里是需要發(fā)布內(nèi)部類(lèi)實(shí)例境蔼,而這樣的做法導(dǎo)致當(dāng)ThisEscape發(fā)布EventListener時(shí)灶平,也隱含地發(fā)布了ThisEscape實(shí)例本身伺通。因?yàn)樵谶@個(gè)內(nèi)部類(lèi)的實(shí)例中包含了對(duì)ThisEscape實(shí)例的隱含引用。
這樣的逸出會(huì)出現(xiàn)什么問(wèn)題呢逢享?
public class ThisEscape{
private int count;
public ThisEscape(EventSource source){
source.registerListener(
new EventListener(){
public void onEvent(Event e){
dosomething(e);
}
})
//在這里count初始化為1
count = 1;
}
}
舉個(gè)例子罐监,如上,我們知道this逸出會(huì)導(dǎo)致ThisEscape也發(fā)布出去瞒爬,也就是ThisEscape還沒(méi)有構(gòu)建完成就發(fā)布出去弓柱,也就是count=1;
這一句還沒(méi)執(zhí)行就發(fā)布了ThisEscape對(duì)象,如果要使用count時(shí)侧但,很有可能會(huì)出現(xiàn)對(duì)象不一致的狀態(tài)矢空。
那么如何解決這個(gè)問(wèn)題呢?
使用工廠(chǎng)方法來(lái)防止this引用在構(gòu)造函數(shù)過(guò)程中逸出
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;
}
}
如此禀横,便能保證在對(duì)象為構(gòu)造完成之前屁药,是不會(huì)發(fā)布該對(duì)象。