我可以在其构造函数中引用一个对象吗?
我可以做以下事情吗?我可以在其构造函数中引用一个对象吗?
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方法(或某种生命周期方法)来添加管理器,而不是在构造函数中执行。
这种技术违反了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