Private Constructors in Java – Java中的私有构造函数

最后修改: 2021年 6月 27日

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

1. Introduction

1.绪论

Private constructors allow us to restrict the instantiation of a class. Simply put, they prevent the creation of class instances in any place other than the class itself.

私有构造函数允许我们对类的实例化进行限制。简单地说,它们可以防止在类本身以外的任何地方创建类的实例。

Public and private constructors, used together, allow control over how we wish to instantiate our classes – this is known as constructor delegation.

公有和私有构造函数一起使用,可以控制我们希望如何实例化我们的类–这被称为构造函数委托。

2. Typical Usage

2.典型用途

There are several patterns and benefits to restricting explicit class instantiation, and we’ll go through the most common ones in this tutorial:

限制显式类的实例化有几种模式和好处,我们将在本教程中介绍最常见的几种模式。

Let’s see how to define a private constructor:

让我们看看如何定义一个私有构造函数

public class PrivateConstructorClass {
    
    private PrivateConstructorClass() {
        // in the private constructor
    }
}

We define private constructors similarly to public constructors; we’ve simply changed the public keyword to private.

我们定义私有构造函数与公有构造函数类似;我们只是将public关键字改为private

3. Using Private Constructors in the Singleton Pattern

3.在单子模式中使用私有构造函数

The singleton pattern is one of the most common places we’ll encounter the use of a private constructor. The private constructor allows us to restrict class instantiation to a single object instance:

单身模式是我们最常遇到的使用私有构造函数的地方之一。私有构造函数允许我们将类的实例化限制在单个对象实例中

public final class SingletonClass {
    
    private static SingletonClass INSTANCE;
    private String info = "Initial info class";

    private SingletonClass() {
    }

    public static SingletonClass getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SingletonClass();
        }

        return INSTANCE;
    }

    // getters and setters
}

We can create an instance by calling SingletonClass.getInstance() – this either returns an existing instance or creates one if this is the first instantiation. We can only instantiate this class by using the getInstance() static method.

我们可以通过调用SingletonClass.getInstance()来创建一个实例–这可以返回一个现有的实例,或者在这是第一次实例化时创建一个。我们只能通过使用getInstance()静态方法来实例化这个类。

4. Using Private Constructors to Delegate Constructors

4.使用私有构造函数来委托构造函数

Another common use case for private constructors is to provide a means of constructor delegation. Constructor delegation allows us to pass parameters through several different constructors while restricting initialization to specific places.

私有构造函数的另一个常见用途是提供一种构造函数委托的方式。构造函数委托允许我们通过几个不同的构造函数传递参数,同时将初始化限制在特定的地方

In this example, ValueTypeClass allows initialization with a value and type – but we only want to allow it for a subset of types. The general constructor must be private to ensure that only permitted types are used:

在这个例子中,ValueTypeClass允许用一个值和类型进行初始化–但我们只想允许它用于一个类型的子集。一般构造函数必须是私有的,以确保只使用允许的类型。

public class ValueTypeClass {
    
    private final String value;
    private final String type;

    public ValueTypeClass(int x) {
        this(Integer.toString(x), "int");
    }

    public ValueTypeClass(boolean x) {
        this(Boolean.toString(x), "boolean");
    }

    private ValueTypeClass(String value, String type) {
        this.value = value;
        this.type = type;
    }

    // getters and setters
}

We can initialize ValueTypeClass via two different public constructors: one accepts an int, and the other a boolean. Each of these constructors then calls a common private constructor to complete the object initialization.

我们可以通过两个不同的公共构造函数初始化ValueTypeClass:一个接受int,另一个接受boolean。然后每个构造函数都调用一个公共的私有构造函数来完成对象的初始化。

5. Using Private Constructors to Create Uninstantiable Classes

5.使用私有构造函数来创建非实质性的类

Uninstantiable classes are classes that we cannot instantiate. In this example, we’ll create a class that simply contains a collection of static methods:

不可实例化的类是我们不能实例化的类。在这个例子中,我们将创建一个仅仅包含静态方法集合的类

public class StringUtils {
    
    private StringUtils() {
        // this class cannot be instantiated
    }

    public static String toUpperCase(String s) {
        return s.toUpperCase();
    }

    public static String toLowerCase(String s) {
        return s.toLowerCase();
    }
}

The StringUtils class contains a couple of static utility methods and can’t be instantiated due to the private constructor.

StringUtils类包含几个静态的实用方法,由于有私有构造函数,所以不能被实例化。

Really, there’s no need to allow object instantiation since static methods don’t require an object instance to be used.

真的,没有必要允许对象实例化,因为静态方法不需要使用对象实例。

6. Using Private Constructors in the Builder Pattern

6.在构建器模式中使用私有构建器

The builder pattern allows us to construct complex objects step by step, rather than having several constructors providing different ways to create the object. A private constructor restricts initialization, allowing the builder to manage object creation instead.

构建器模式允许我们一步一步地构建复杂的对象,而不是由几个构建器提供不同的方式来创建对象。一个私有构造函数限制了初始化,允许构建器代替它来管理对象的创建

In this example, we’ve created an Employee class that holds the name, age, and department of an employee:

在这个例子中,我们创建了一个Employee类,它持有一个雇员的nameagedepartment

public class Employee {

    private final String name;
    private final int age;
    private final String department;

    private Employee(String name, int age, String department) {
        this.name = name;
        this.age = age;
        this.department = department;
    }
}

As we can see, we’ve made the Employee constructor private – therefore, we cannot instantiate the class explicitly.

正如我们所看到的,我们已经把Employee构造函数变成了私有的–因此,我们不能显式地实例化这个类。

We’ll now add an inner Builder class to the Employee class:

我们现在要给Employee类添加一个内部Builder类。

public static class Builder {

    private String name;
    private int age;
    private String department;

    public Builder setName(String name) {
        this.name = name;
        return this;
    }

    public Builder setAge(int age) {
        this.age = age;
        return this;
    }

    public Builder setDepartment(String department) {
        this.department = department;
        return this;
    }

    public Employee build() {
        return new Employee(name, age, department);
    }
}

The builder can now create different employees with a name, age, or department – there’s no constraint on how many fields we must provide:

构建器现在可以用姓名年龄部门创建不同的雇员–对于我们必须提供多少字段没有任何限制。

Employee.Builder emplBuilder = new Employee.Builder();

Employee employee = emplBuilder
  .setName("baeldung")
  .setDepartment("Builder Pattern")
  .build();

We’ve created an Employee with a name of “baeldung” and a department of “Builder Pattern“. Age is not provided, so the default primitive int value of 0 will be used.

我们创建了一个名字为”baeldung“、部门为”Builder Pattern“的Employee。没有提供年龄,所以将使用默认的原始int值0。

7. Using Private Constructors to Prevent Subclassing

7.使用私有构造函数来防止子类化

Another possible use for private constructors is to prevent subclassing of a class. If we tried to create such as subclass, it would be unable to call the super constructor. However, it’s important to note that we’d normally make a class final to prevent subclassing rather than using a private constructor.

私有构造函数的另一个可能用途是防止一个类的子类。如果我们试图创建这样的子类,它将无法调用super 构造函数。然而,需要注意的是,我们通常会让一个类final来防止子类化,而不是使用一个私有构造函数

8. Conclusion

8.结语

The primary use of private constructors is to restrict the instantiation of classes. Private constructors are especially useful when we want to restrict the external creation of a class.

私有构造函数的主要用途是对类的实例化进行限制。当我们想要限制类的外部创建时,私有构造函数特别有用

Singletons, factories, and static method objects are examples of how restricting object instantiation can be useful to enforce a certain pattern.

单胞胎、工厂和静态方法对象都是限制对象实例化的例子,可以有效地执行某种模式。

Constants classes and static method classes also dictate that a class should not be instantiable. It’s important to remember that we can also combine private constructors with public constructors to allow code sharing inside different public constructor definitions.

常量类和静态方法类也决定了一个类不应该是可实例化的。重要的是要记住,我们也可以将私有构造函数与公共构造函数结合起来,以便在不同的公共构造函数 定义

The code for these examples can be found over on GitHub.

这些例子的代码可以在GitHub上找到over