我可以在其构造函数中引用一个对象吗?

时间:2010-04-21 14:22:16

标签: java oop constructor this

我可以执行以下操作吗?

public Manager(String userName) {
    game = new Game(userName);
    game.addManager(this);
}

问题是我在其构造函数中引用了一个对象(this)(在它实际创建之前)。

7 个答案:

答案 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相同:

http://www.gotw.ca/publications/mill13.htm

答案 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();
    }
}