Java 我可以在构造函数中引用对象吗?
我能做以下事情吗Java 我可以在构造函数中引用对象吗?,java,oop,constructor,this,Java,Oop,Constructor,This,我能做以下事情吗 public Manager(String userName) { game = new Game(userName); game.addManager(this); } 问题是我在构造函数中引用了一个对象(this)(在它实际创建之前)。是的,它在Java中是完全合法的,但不推荐使用。有关此关键字的更多详细信息,请参阅。是的,您可以这样做,但您不应该这样做 问题在于,在构造函数仍在运行时发布this可能会产生各种奇怪的副作用,因为一些常见的保证在构造函数仍在
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
问题是我在构造函数中引用了一个对象(
this
)(在它实际创建之前)。是的,它在Java中是完全合法的,但不推荐使用。有关此关键字的更多详细信息,请参阅。是的,您可以这样做,但您不应该这样做
问题在于,在构造函数仍在运行时发布this
可能会产生各种奇怪的副作用,因为一些常见的保证在构造函数仍在运行时不成立(例如final
变量似乎会在构造函数仍在运行时更改其值)
描述构造对象时要采取的预防措施以及这些预防措施背后的原因。虽然本文从多线程的角度讨论了这个主题,但在单线程环境中,当未知/不受信任的代码在构建过程中引用了this
时,您可能会遇到类似的问题
(最后一段是“偷来的”。正如@James所说,你可以,但这不一定是你想做的事情。如果
game.addManager
尝试访问管理器的某些属性,则您可能最终尝试访问尚未初始化的管理器的属性。更好的方法是让外部对象调用某个init方法(或某个生命周期方法)来添加管理器,而不是在构造函数中执行它。看看这是否有帮助,它实际上适用于c/c++但我认为对java也是一样的:
此技术违反了java并发概念之一—安全发布。为此,您应该使用
init()
方法或其他技术
您可以看到,在转义了这个引用之后,您可以初始化构造函数中的一些最终字段(或者进行一些其他初始化)。若您在构造函数中将对象的实例传递给另一个对象,那个么您可以在构造过程中得到回调。它可能会导致不一致的行为、NPE、死锁等等。尽管它是合法的Java,而且在您描述的情况下(它是构造函数的最后一行),这是一件非常安全的事情(某些边缘情况除外),作为实践,这是一件坏事,就像使用
goto
(在支持关键字的语言中)这应该是您深思熟虑的事情。对于您的情况,更好的做法是将构造函数设置为私有,删除对addManager的调用并公开静态工厂方法:
public static Manager createManager(String userName) {
Manager manager = new Manager(userName);
manager.game.addManager(manager);
return manager;
}
我还应该指出,类之间的这种相互依赖性(经理知道游戏,游戏也知道经理)这肯定是一种代码气味,我会像从构造函数中传递它一样关心这种需要。男孩,这不安全!虽然代码有效,但设计不好!您的代码允许在正确构造对象之前转义“this”引用 假设game.addManager()将调用“this”引用上的某个方法xxx()。 我们有一个子类Manager,ChildManager,它重写方法xxx(),这个方法依赖于ChildManager中的一个字段(当超级构造函数到达最后一行代码时,该字段不会初始化)。 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();
}
}
虽然这种技术在Java中是有效的,但它是相当危险的。完全有效??它只是编译而已。我认为如果它说“它是完全合法的Java”,这个答案会更好的确如此。但就像生活中一样,仅仅因为它是合法的并不能让它成为一个好主意。是的,我会很快更新我的文字,发布它!我所指的是它是合法的,而不是OP是否应该这样做。从技术上讲,该对象当时已经创建(否则你也无法访问其属性),但它尚未完全正确初始化。