Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我可以在构造函数中引用对象吗?_Java_Oop_Constructor_This - Fatal编程技术网

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是否应该这样做。从技术上讲,该对象当时已经创建(否则你也无法访问其属性),但它尚未完全正确初始化。