在构造函数中实例化对象

似乎以下代码的结果是相同的,所以我应该何时使用它们?

public class Person { public Person() { this.family = new Family(); } Family family; } 

 public class Person { Family family = new Family(); } 

(我可以想到的一个场景是,当有多个构造函数时,我们只想在其中一个内部创建一个族的实例……这是唯一的情况吗?)

对于类变量 [静态变量],您不能使用第一个,因为您希望初始化只发生一次,而不是每次调用构造函数时都是如此。

例如变量,第二个只是第一个的合成糖。
有时您可能必须使用第二个 – for参数构造函数,它们本身 – 传递给您的构造函数。

后者将保证每个人都会有一个家庭(awww,不是那么好)。 但在前者中,其他构造函数可能会由另一个开发人员添加,而这些开发人员将未初始化为Family。 这往往表明后者,更短的版本是更可取的。 但事实并非如此,因为将Person建模为没有族,这可能是一个有效的条件,在这种情况下,通过构造函数初始化是优越的,因为您可以传递null。

第三种选择是具有提供的setter的(较长的, 叹气的 )基本POJO样式,其中在显式调用setter之前不会初始化Family。 使用它的更好的方法是,如果要为孤立建模,则不必为构造函数提供空值。

这一切都取决于你想如何约束人的建构。

第一种方法为您提供了对如何初始化每个构造函数处理的类对象的自定义控制,而第二个选项将以相同的方式为所有构造函数初始化Family对象。

第一种方法更可取,因为它允许您将一个Family对象放入构造函数中,允许您执行dependency injection等操作,这通常是良好的编程习惯(并允许更容易的测试)。

除此之外,它们都是成员变量(不像其他人说的那样是静态的,你必须使用静态关键字)。 此类的每个实例都将以这种方式包含Family对象的实例。

我会推荐这样的东西

 public class Person { public Person(Family family) { this.family = family; } Family family; } 

编辑:为了解决关于我的post的评论(这在某种程度上是准确的),初始化对象的顺序有所不同。 但是,评论指出,运作的顺序是:
初始化实例变量 – >实例初始化器 – >构造函数

从测试出来,似乎它取决于代码中首先出现的,实例变量或实例初始化器的初始化, 然后在两者之后调用构造函数 。 考虑一下Family对象的构造函数只打印出给它的字符串的示例:

 public class Person { { Family familyB = new Family("b"); } Family familyA = new Family("a"); Family familyC; public Person() { this.familyC = new Family("c"); } } 

在构造person对象时导致此输出:
家庭:b
家庭:a
家庭:c

但是这段代码:

 public class Person { Family familyA = new Family("a"); { Family familyB = new Family("b"); } Family familyC; public Person() { this.familyC = new Family("c"); } } 

在构造person对象时导致此输出:
家庭:a
家庭:b
家庭:c

我建议在子类化时使用第一个。 考虑一下:

 public class Child extends Person { public Child() { // super(); // or this.family = new PatchWorkFamily(); } } 

使用第二种初始化方法,您将始终初始化一个新系列,然后根据需要覆盖它。 这可能不是你想要的 – 如果这些对象在实例化时做了很多工作,则可能对性能有害。

如果你计划扩展课程,第二种风格很糟糕(参见Daff的回答)。

对于实例变量,我认为维护程序员(通常是初级程序员)更清楚地在构造函数中执行所有实例级初始化。 我建议您选择1的变体。

 public class Person { private Family family; public Person() { family = new Family(); } } 

如果没有必要,我宁愿避免this情况,因为它什么也没有增加。

我更喜欢第二种风格。 如果你有多个构造函数,则不必重复初始化,也不会忘记它们。 此外,它还清楚了如何初始化变量。 通常,在阅读程序并遇到变量时,您首先要查看其声明。 使用第二种样式,您可以立即看到默认值。 首先,您需要查看构造函数。

两者都没有计算优势。