我可以做以下事情嗎?我可以在其構造函數中引用一個對象嗎?
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
的問題是,我指的是在其構造方法的對象(this
)(它實際上是創建前)。
我可以做以下事情嗎?我可以在其構造函數中引用一個對象嗎?
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
的問題是,我指的是在其構造方法的對象(this
)(它實際上是創建前)。
是的,你可以做到這一點,但你不應該這樣做。
問題是,當構造函數仍在運行時發佈this
可能會產生各種奇怪的副作用,因爲在構造函數仍在運行時某些常見保證不成立(例如final
變量看起來可能會更改他們的價值,而構造函數仍然運行)。
This IBM developerWorks article描述了構建對象時要採取的預防措施以及這些預防措施背後的推理。雖然本文根據多線程討論了該主題,但在構建期間未知/不可信代碼獲取對this
的引用時,單線程環境中可能會出現類似問題。
(最後一段從one of my earlier answers「被盜」)。
正如@詹姆斯所說,你可以,但它不一定是你想要做的事情。如果game.addManager
嘗試訪問Manager的某些屬性,則最終可能會嘗試訪問尚未初始化的Manager的屬性。更好的方法是讓外部對象調用某個init方法(或某種生命週期方法)來添加管理器,而不是在構造函數中執行。
看看是否有幫助,它實際上是對C/C++,但我認爲它同樣爲Java:
這種技術違反了Java併發概念之一 - 安全的出版物。您應該使用init()
方法用於此目的或其他技術。
你看,你可以在這個引用已經被轉義後,在你的構造函數中初始化一些final字段(或者做一些其他初始化)。如果您在構造函數中將對象的實例傳遞給另一個對象,則可以在構建過程中獲得回調。它會導致不一致的行爲,NPE,死鎖等等。
雖然它是合法的Java,並且在你描述的情況下(它是構造函數的最後一行),這是一件相當安全的事情(在某些邊緣情況下可以免除),作爲一種習慣要做的事情,並且喜歡使用goto
(在支持關鍵字的語言中),它應該是你認爲漫長而艱難的事情。對於你的情況下,更好的做法是使構造私有,取出調用addManager和揭露靜態工廠方法:
public static Manager createManager(String userName) {
Manager manager = new Manager(userName);
manager.game.addManager(manager);
return manager;
}
我還要指出的是階級之間那種相互依存的(經理知道關於遊戲和遊戲知道經理)絕對是一種代碼味道,我會關心這個需求,就像我將要從構造函數中傳遞它一樣。
+1爲相互依賴性代碼異味 – sleske 2010-04-21 14:39:29
男孩,這是不安全的!雖然有效的代碼,但不是很好的設計!您的代碼允許「this」引用在對象正確構造之前轉義。
想象一下,game.addManager()會調用「this」引用上的某個方法xxx()。 而且我們有一個Manager的子類ChildManager,它覆蓋了方法xxx(),並且此方法依賴於ChildManager中的一個字段(超級構造函數到達其最後一行代碼時未初始化)。 game.addManager()會在ChildManager中看到未初始化的字段值,這非常非常危險!
示例代碼:
public class Manager {
Game game;
public Manager (String userName){
game = new Game(userName);
game.addManager(this);
}
public void xxx(){
}
}
public class ChildManager extends Manager {
String name;
public ChildManager (String username){
super(username);
name = username;
}
public void xxx(){
System.out.println(name);
}
}
public class Game {
public Game (String userName){
}
public void addManager (Manager m){
m.xxx();
}
}
技術上的對象已經創建* *在這一點上(否則你不能訪問它的屬性之一),但它並不完全正確初始化* *呢。 – 2010-04-21 14:28:35