Java 在构造函数中设置父子关系而不泄漏";这";变量

Java 在构造函数中设置父子关系而不泄漏";这";变量,java,constructor,thread-safety,Java,Constructor,Thread Safety,我正在编写一些物理代码,将对象组织成层次关系,类主体的每个对象都有一个父对象(一个子类处理根条件)和零到多个子对象。然而,为了实例化一个新的主体,我必须将其添加到其父对象中,因此构造函数将“this”泄漏到其父对象的addChild方法中 目前Body的addChild方法是私有的;在Body构造函数之外访问它的唯一方法是通过Body.setParent。然而,我担心的是,在某些边缘情况下,这仍然可能会暴露一个非完全实例化的对象。以下代码仅简化为相关元素: import java.util.Se

我正在编写一些物理代码,将对象组织成层次关系,类主体的每个对象都有一个父对象(一个子类处理根条件)和零到多个子对象。然而,为了实例化一个新的主体,我必须将其添加到其父对象中,因此构造函数将“this”泄漏到其父对象的addChild方法中

目前Body的addChild方法是私有的;在Body构造函数之外访问它的唯一方法是通过Body.setParent。然而,我担心的是,在某些边缘情况下,这仍然可能会暴露一个非完全实例化的对象。以下代码仅简化为相关元素:

import java.util.Set;
导入java.util.TreeSet;
公共阶级团体{
私人机构家长;
私人儿童;
公共机构(母机构){
//首先实例化其他所有内容
this.children=新树集;
this.parent=parent;
parent.addChild(this);
}
公共无效集合父对象(主体父对象){
this.parent.removeChild(this);
this.parent=parent;
parent.addChild(this);
}
私有无效子对象(实体子对象){
添加(child);
}
私有void removeChild(主体子对象){
儿童。移除(儿童);
}
}

正如所料,这段代码“在构造函数中泄漏了这一点”,但似乎没有任何其他方法来设置树结构。是否有另一种设计模式可用于避免主体在其构造函数完成运行之前可见?

保持构造函数简单是一个好主意。在您的情况下,与另一个对象交互会使问题变得复杂。其中一个原因是错误处理在构造函数中可能很困难

与其使用带参数的构造函数,不如删除该参数并像这样调用它

var newBody = new Body();
newBody.setParent(parent);
public Body() {
    this.children = new TreeSet<Body>;
}
构造函数将如下所示

var newBody = new Body();
newBody.setParent(parent);
public Body() {
    this.children = new TreeSet<Body>;
}
请注意,我还更改了setParent参数的名称,以避免与类变量冲突。当您忘记使用“this”来区分您所指的“家长”时,很难发现错误

我删除的构造函数代码实际上只是setParent方法的一个副本

我向该方法添加了synchronized,这样可以确保对该方法的多个调用是同步进行的,否则层次结构可能会受到损坏


当然,有很多方法可以做到这一点。但这是我将使用的一种简单方法。

保持构造函数简单是一个好主意。在您的情况下,与另一个对象交互会使问题变得复杂。其中一个原因是错误处理在构造函数中可能很困难

与其使用带参数的构造函数,不如删除该参数并像这样调用它

var newBody = new Body();
newBody.setParent(parent);
public Body() {
    this.children = new TreeSet<Body>;
}
构造函数将如下所示

var newBody = new Body();
newBody.setParent(parent);
public Body() {
    this.children = new TreeSet<Body>;
}
请注意,我还更改了setParent参数的名称,以避免与类变量冲突。当您忘记使用“this”来区分您所指的“家长”时,很难发现错误

我删除的构造函数代码实际上只是setParent方法的一个副本

我向该方法添加了synchronized,这样可以确保对该方法的多个调用是同步进行的,否则层次结构可能会受到损坏


当然,有很多方法可以做到这一点。但这是一个简单的方法,我会使用。

我会做的进一步更改,与您的问题无关,是检查newParent是否为null,并且仅在newParent不为null时调用addChild。因此,本质上,与其在构造函数中将主体添加到其父体,不如将该位移到首先调用构造函数的代码中?我唯一关心的是,一具尸体有可能成为孤儿;忘记在构造函数后面编写代码,或者用null调用setParent。也许您可以添加isOrphaned()并返回parent==null;然后你可以在需要的地方检查这个。有一种更复杂的方法可以实现这一点,我也很喜欢——使用builder模式,如果没有设置父对象,则让build()方法抛出一个错误。如果您对此感兴趣,请告诉我-我可以为其添加一个答案。与您的问题无关,我要做的进一步更改是检查newParent是否为null,并且仅在newParent不为null时调用addChild。因此,本质上,不是将主体添加到构造函数中的父体,只需将该位移到调用构造函数的代码中?我唯一关心的是,一具尸体有可能成为孤儿;忘记在构造函数后面编写代码,或者用null调用setParent。也许您可以添加isOrphaned()并返回parent==null;然后你可以在需要的地方检查这个。有一种更复杂的方法可以实现这一点,我也很喜欢——使用builder模式,如果没有设置父对象,则让build()方法抛出一个错误。如果你对此感兴趣,请告诉我-我可以为它添加一个答案。