我可以执行以下操作吗?
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
问题是我在其构造函数中引用了一个对象(this
)(在它实际创建之前)。
答案 0 :(得分:4)
虽然它是合法的Java,并且在你描述的情况下(它是构造函数的最后一行),这是一个非常安全的事情(某些边缘情况被豁免),作为一种做法,它是一件坏事要做,并且喜欢使用goto
(在支持关键字的语言中),它应该是你认为漫长而艰难的事情。对于您的情况,更好的做法是将构造函数设为私有,删除对addManager的调用并公开静态工厂方法:
public static Manager createManager(String userName) {
Manager manager = new Manager(userName);
manager.game.addManager(manager);
return manager;
}
我还应该指出,类之间的那种相互依赖性(经理知道游戏和游戏知道经理)绝对是一种代码味道,我会像我一样关注这种需求。是关于从构造函数传递它。
答案 1 :(得分:3)
是的,您可以这样做,但不应该这样做。
问题是在构造函数仍在运行时发布this
会产生各种奇怪的副作用,因为在构造函数仍在运行时,某些常见的保证不成立(例如{{1在构造函数仍然运行时,变量似乎可以改变它们的值。
This IBM developerWorks article描述了构建对象时要采取的预防措施以及这些预防措施背后的原因。虽然本文根据多线程讨论了这个主题,但是当未知/不可信代码在构造期间引用final
时,您可以在单线程环境中遇到类似的问题。
(最后一段从one of my earlier answers被“偷走”)。
答案 2 :(得分:2)
Yup在Java中完全合法,但不推荐。有关this
关键字的详细信息,请参阅here。
答案 3 :(得分:1)
正如@James所说,你可以,但它不一定是你想做的事情。如果game.addManager
尝试访问Manager的某些属性,您最终可能会尝试访问尚未初始化的Manager的属性。更好的方法是让外部对象调用一些init方法(或一些生命周期方法)来添加管理器,而不是在构造函数中执行。
答案 4 :(得分:0)
看看这是否有帮助,它实际上是用于c / c ++,但我认为它与java相同:
答案 5 :(得分:0)
这种技术违反了java并发概念之一 - 安全发布。您应该使用init()
方法来实现此目的或其他技术。
您可以看到,在此引用被转义后,您可以在构造函数中初始化一些最终字段(或执行其他一些初始化)。如果将构造函数中的对象实例传递给另一个对象,则可以在构造期间获得回调。它可能导致行为不一致,NPE,死锁等。
答案 6 :(得分:0)
男孩,这不安全!虽然有效的代码,但不是很好的设计!在正确构造对象之前,您的代码允许“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();
}
}