简体   繁体   English

在构造函数中实例化对象

[英]Instantiating object in a constructor

It seems that the result of the following code is the same, so when should I use each? 似乎以下代码的结果是相同的,所以我应该何时使用它们?

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

to

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

(one scenario I can think of, is when having multiple constructors and we want to create an instance of family only inside one of them... is that the only case?) (我可以想到的一个场景是,当有多个构造函数并且我们只想在其中一个内部创建一个族的实例时......这是唯一的情况吗?)

For class variables [static variable] you cannot use the first, since you want the initializtion to happen only once, and not with every time you invoke your constructor. 对于类变量 [静态变量],您不能使用第一个,因为您希望初始化只发生一次,而不是每次调用构造函数时。

For instance variables, the second is just a syntatic sugar of the first. 例如变量,第二个只是第一个的合成糖。
Sometimes you might have to use the second - for argument constructor, which are themselves - passed to your constructor. 有时您可能必须使用第二个 - for参数构造函数,它们本身 - 传递给您的构造函数。

The latter will guarantee that every Person will always have a Family (awww, isn't that nice). 后者将保证每个人都将拥有一个家庭(awww,不是那么好)。 But in the former, other constructors could be added by another developer which leave Family uninitialized. 但在前者中,其他构造函数可能会被另一个开发人员添加,而这些开发人员会将Family保留为未初始化状态。 That tends to suggest the latter, shorter version is preferable. 这往往表明后者,更短的版本是更可取的。 But that is not really true, because it might be a valid condition to model a Person as not having a family, in which case initialization via constructor is superior because you can pass null. 但事实并非如此,因为将Person建模为没有族,这可能是一个有效的条件,在这种情况下,通过构造函数初始化是优越的,因为您可以传递null。

The 3rd alternative is the (longer, sigh ) basic POJO style with provided setter, in which Family is not initialized until a setter is explicitly called. 第三种选择是具有提供的setter的(较长的, 叹气的 )基本POJO样式,其中在显式调用setter之前不会初始化Family。 The nicer thing about using this is that you don't have to provide a null value to a constructor if you are modeling an Orphan. 使用它的更好的方法是,如果要为孤立建模,则不必为构造函数提供空值。

It all depends on how you want to constrain construction of Person. 这一切都取决于你想如何约束人的建构。

The first method gives you custom control over how to initialize the class object that you're dealing with per constructor, whereas the second option will initialize the Family object the same way for all constructors. 第一种方法为您提供了如何初始化每个构造函数处理的类对象的自定义控件,而第二个选项将以相同的方式为所有构造函数初始化Family对象。

The first method is preferable, because it allows you to take a Family object into your constructor allowing you to do things like dependency injection, which is generally good programming practice (and allows for easier testing). 第一种方法更可取,因为它允许您将一个Family对象放入构造函数中,允许您执行依赖注入等操作,这通常是良好的编程习惯(并允许更容易的测试)。

Aside from that, both of them are member variables (not static as someone else said, you have to use the static keyword for that). 除此之外,它们都是成员变量(不像其他人所说的那样是静态的,你必须使用静态关键字)。 Each instance of this class will contain an instance of a Family object this way. 此类的每个实例都将以这种方式包含Family对象的实例。

I would recommend something like this 我会推荐这样的东西

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

Edit: To address the comment that was made about my post (which was accurate, somewhat), there is a difference in which the order of the objects are initialized. 编辑:为了解决关于我的帖子的评论(这在某种程度上是准确的),对象的顺序初始化存在差异。 However, the comment stated that the order of operation is: 但是,评论指出,运作的顺序是:
initialization of instances variables -> instance initializer -> constructor 初始化实例变量 - >实例初始化器 - >构造函数

From testing this out, it seems that it depends on which occur first in the code, initialization of instance variables or instance initializers, and then the constructor is called after both of them . 从测试出来,似乎它取决于代码中首先出现的,实例变量或实例初始化器的初始化, 然后在两者之后调用构造函数 Consider the example where the constructor of the Family object just prints out the string given to it: 考虑这样的示例,其中Family对象的构造函数只打印出给它的字符串:

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

    Family familyC;
    public Person() { 
        this.familyC = new Family("c");
    }
}

results in this output when constructing a person object: 在构造person对象时导致此输出:
Family: b 家庭:b
Family: a 家庭:a
Family: c 家庭:c

but this code: 但是这段代码:

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

    Family familyC;
    public Person() { 
        this.familyC = new Family("c");
    }
}

results in this output when constructing a person object: 在构造person对象时导致此输出:
Family: a 家庭:a
Family: b 家庭:b
Family: c 家庭:c

I would recommend using the first when it comes to subclassing. 我建议在子类化时使用第一个。 Consider this: 考虑一下:

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

With the second way of initializing you will always initialize a new Family and then overwrite it if needed. 使用第二种初始化方法,您将始终初始化一个新族,然后在需要时覆盖它。 That might not be what you want - and can be bad for performance if these object do a lot of work when being instantiated. 这可能不是你想要的 - 如果这些对象在实例化时做了很多工作,则可能对性能有害。

The second style is terrible if you plan to extend the class (see Daff's answer). 如果你计划扩展课程,第二种风格很糟糕(参见Daff的回答)。

For instance variables, I believe that is is clearer to the maintenance programmer - who is typically a junior programmer - to perform all instance level initialization in the constructor. 对于实例变量,我认为维护程序员(通常是初级程序员)更清楚地在构造函数中执行所有实例级初始化。 I recommend a variation of your option 1. 我建议您选择1的变体。

public class Person
{
  private Family family;

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

I prefer to avoid this when it is not necessary, since it adds nothing. 如果没有必要,我宁愿避免this情况,因为它什么也没有增加。

I like the second style better. 我更喜欢第二种风格。 If you have more than one constructor you don't have to repeat the initializations and you wont forget them. 如果你有多个构造函数,则不必重复初始化,也不会忘记它们。 Also, it makes it clear how the variable is initialized. 此外,它还清楚了如何初始化变量。 Typically, when reading a program and coming across a variable, you'll first go to its declaration. 通常,在阅读程序并遇到变量时,您首先要查看其声明。 With the second style, you see the default value right away. 使用第二种样式,您可以立即看到默认值。 With the first, you need to look at the constructor. 首先,您需要查看构造函数。

Neither is computationally superior. 两者都没有计算优势。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM