Chaining Constructors in Java – Java中的链式构造函数

最后修改: 2021年 11月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this short tutorial, we’ll see how to chain constructors in Java. It’s a handy design pattern that creates less duplicated code and makes it more readable.

在这个简短的教程中,我们将看到如何在Java中链式构造函数。这是一种方便的设计模式,可以减少重复的代码,使其更具有可读性。

First, we’ll explain what constructors chaining is all about. Then, we’ll see how to chain them in the same class and use constructors from the parent class. Last but not least, we’ll analyze the benefits and drawbacks of this approach.

首先,我们将解释构造函数链是什么意思。然后,我们将看到如何在同一个类中连锁它们,并使用来自父类的构造函数。最后但并非最不重要的是,我们将分析这种方法的好处和坏处。

2. Chaining Constructors Definition with Examples

2.链式构造函数的定义与实例

Constructor chaining is the process of calling a sequence of constructors. We can do it in two ways:

构造函数链是调用一连串构造函数的过程。我们可以通过两种方式来实现它。

  • by using this() keyword for chaining constructors in the same class
  • by using super() keyword for chaining constructors from the parent class

Let’s see examples showing both approaches.

让我们看看显示这两种方法的例子。

2.1. Chaining Constructors Within the Same Class

2.1.同类中的链式构造函数

Let’s define a simple Person class that contains a few attributes:

让我们定义一个简单的Person类,它包含一些属性。

public class Person {
    private final String firstName;
    private final String middleName;
    private final String lastName;
    private final int age;

    //getters, equals and hashcode
}

The firstName, lastName, and age are attributes that we want to always set during object initialization. However, not every person has a middle name. Therefore the middleName attribute is optional.

firstName, lastName, age是我们希望在对象初始化期间始终设置的属性。然而,不是每个人都有中间名。因此,middleName属性是可选的。

With that in mind, we’re going to create two constructors. The first one accepts all four attributes:

考虑到这一点,我们将创建两个构造函数。第一个接受所有四个属性。

public Person(String firstName, String middleName, String lastName, int age) {
    this.firstName = firstName;
    this.middleName = middleName;
    this.lastName = lastName;
    this.age = age;
}

The second constructor is going to accept three required attributes and omit the optional field:

第二个构造函数将接受三个必需的属性,并省略可选字段。

public Person(String firstName, String lastName, int age) {
    this(firstName, null, lastName, age);
}

We’re using the this() keyword. It must always be the first line of the constructor. This ensures that the constructor that we’re chaining to will be invoked in the first place.

我们正在使用this()关键字。它必须始终是构造函数的第一行。这可以确保我们所链接的构造函数将被首先调用。

Keep in mind that the order of constructors in class is not relevant. That means that our second constructor can be placed anywhere in the Person class, and it will still work correctly.

请记住,类中构造函数的顺序并不重要。这意味着我们的第二个构造函数可以放在Person 类中的任何位置,它仍将正确工作。

2.2. Chaining Constructors From the Parent Class

2.2.从父类中串联构造函数

Let’s define a Customer class that inherits from the Person class created in the previous section:

让我们定义一个Customer类,它继承自上一节中创建的Person类。

public class Customer extends Person {
    private final String loyaltyCardId;

   //getters, equals and hashcode
}

It contains an extra attribute. Now, let’s create two constructors in a similar way as in the Person class:

它包含一个额外的属性。现在,让我们以与Person类类似的方式创建两个构造函数。

public Customer(String firstName, String lastName, int age, String loyaltyCardId) {
    this(firstName, null, lastName, age, loyaltyCardId);
}

public Customer(String firstName, String middleName, String lastName, int age, String loyaltyCardId) {
    super(firstName, middleName, lastName, age);
    this.loyaltyCardId = loyaltyCardId;
}

The first constructor uses the this() keyword to chain to the second constructor, which accepts all required and optional attributes. Here, we use the super() keyword for the first time.

第一个构造函数使用this()关键字来链接到第二个构造函数,该构造函数接受所有必需和可选的属性。这里,我们第一次使用super()关键字。

Its behavior is very similar to the this() keyword. The only difference is that super() chains to the corresponding constructor in the parent class, whereas this() chains to the constructor in the same class.

它的行为与 this() 关键字非常相似。唯一的区别是, super()链接到父类中相应的构造函数,而this()链接到同一类中的构造函数

Keep in mind that similar to the previous keyword, super() must always be the first line of the constructorThis means that the parent’s constructor is invoked in the first place. After that, the value is assigned to the loyaltyCardId attribute.

请记住,与前面的关键字类似,super()必须始终是构造函数的第一行这意味着父类的构造函数首先被调用i。之后,值被分配给loyaltyCardId属性。

3. Chaining Constructors Benefits and Drawbacks

3.链式构造器的好处和坏处

The biggest advantage of constructors chaining is less duplicated code. In other words, we use the Don’t Repeat Yourself (DRY) principle. This is because we have the object’s initialization done in a single constructor, typically the one accepting all attributes. Other constructors are just for passing received data and adding default values for missing attributes.

构造函数链的最大优点是 减少重复的代码。换句话说,我们使用了 “不要重复自己”(DRY)原则。这是因为我们让对象的初始化在一个构造函数中完成,通常是接受所有属性的那个。其他构造函数只是用于传递接收的数据和为缺失的属性添加默认值。

Chaining constructors makes code more readable. We don’t have to repeat attribute assignments throughout all constructors. Instead, we do this in one place.

链式构造函数使代码更具可读性。我们不必在所有构造函数中重复属性赋值。相反,我们只需在一个地方做这件事。

On the other hand, we expose more ways of constructing an object when using constructors chaining. This might be a significant drawback in some projects. In those cases, we should look for factory or builder patterns to hide multiple constructors.

另一方面,当使用构造函数链时,我们暴露了更多构造对象的方法。这在某些项目中可能是一个重要的缺点。在这些情况下,我们应该寻找factorybuilder模式来隐藏多个构造函数。

4. Conclusion

4.总结

In this article, we discussed constructors chaining in Java. Firstly, we explained what is called constructors chaining. Then, we showed how to do this with constructors within the same class as well as using parent’s constructors. Finally, we discussed the benefits and drawbacks of chaining constructors.

在这篇文章中,我们讨论了Java中的构造函数链。首先,我们解释了什么是构造函数链。然后,我们展示了如何在同一个类中使用构造函数,以及如何使用父类的构造函数。最后,我们讨论了构造函数链的好处和坏处。

As always, the complete source code of the article is available over on GitHub.

一如既往,该文章的完整源代码可在GitHub上获得