Warning: file_put_contents(/datas/wwwroot/jiajiahui/core/caches/caches_template/2/default/show.php): failed to open stream: Permission denied in /datas/wwwroot/jiajiahui/core/libraries/classes/template_cache.class.php on line 55

Warning: chmod(): Operation not permitted in /datas/wwwroot/jiajiahui/core/libraries/classes/template_cache.class.php on line 56
我可以在其构造函数中引用一个对象吗? - 源码之家

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

问题描述:

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

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

的问题是,我指的是在其构造方法的对象(this)(它实际上是创建前)。

+1

技术上的对象已经创建* *在这一点上(否则你不能访问它的属性之一),但它并不完全正确初始化* *呢。 – 2010-04-21 14:28:35

是的完美法律在Java中,但不建议。有关this关键字的更多详细信息,请参阅here

+1

虽然这种技术在Java中有效,但它非常危险。 – 2010-04-21 14:27:12

+2

完美有效??它只是编译而已,仅此而已。 – Roman 2010-04-21 14:27:26

+2

我认为这个答案会更好,如果它说“它是完全合法的Java”。但就像在生活中一样,仅仅因为它是合法的并不能成为一个好主意。 – Yishai 2010-04-21 14:29:27

是的,你可以做到这一点,但你不应该这样做

问题是,当构造函数仍在运行时发布this可能会产生各种奇怪的副作用,因为在构造函数仍在运行时某些常见保证不成立(例如final变量看起来可能会更改他们的价值,而构造函数仍然运行)。

This IBM developerWorks article描述了构建对象时要采取的预防措施以及这些预防措施背后的推理。虽然本文根据多线程讨论了该主题,但在构建期间未知/不可信代码获取对this的引用时,单线程环境中可能会出现类似问题。

(最后一段从one of my earlier answers“被盗”)。

正如@詹姆斯所说,你可以,但它不一定是你想要做的事情。如果game.addManager尝试访问Manager的某些属性,则最终可能会尝试访问尚未初始化的Manager的属性。更好的方法是让外部对象调用某个init方法(或某种生命周期方法)来添加管理器,而不是在构造函数中执行。

看看是否有帮助,它实际上是对C/C++,但我认为它同样为Java:

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

这种技术违反了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

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