一、简介
私有构造函数 允许我们限制类的实例化 。简而言之,它们阻止在类本身以外的任何地方创建类实例。
公共和私有构造函数一起使用,可以控制我们希望如何实例化我们的类 - 这称为构造函数委托。
2. 典型用法
限制显式类实例化有多种模式和好处,我们将在本教程中介绍最常见的模式和好处:
让我们看看 如何定义私有构造函数 :
public class PrivateConstructorClass {
private PrivateConstructorClass() {
// in the private constructor
}
}
我们定义私有构造函数与公共构造函数类似;我们只是将 public 关键字更改为 private 。
3. 在单例模式中使用私有构造函数
单例模式是我们最常遇到使用私有构造函数的地方之一。私有构造函数 允许我们将类实例化限制为单个对象实例 :
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
}
我们可以通过调用 SingletonClass.getInstance() 创建一个实例——这要么返回一个现有实例,要么创建一个实例(如果这是第一个实例化)。我们只能使用 getInstance() 静态方法来实例化此类。
4. 使用私有构造函数来委托构造函数
私有构造函数的另一个常见用例是提供构造函数委托的方法。构造函数委托 允许我们通过几个不同的构造函数传递参数,同时将初始化限制在特定位置 。
在此示例中, 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
}
我们可以通过两个不同的公共构造函数来初始化 ValueType**Class :一个接受 int ,另一个接受 boolean 。然后,每个构造函数都会调用一个公共的私有构造函数来完成对象初始化。
5. 使用私有构造函数创建不可实例化的类
不可实例化类是我们无法实例化的类。在此示例中,我们将创建 一个仅包含静态方法集合的类 :
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();
}
}
StringUtils 类包含几个静态实用方法,并且由于私有构造函数而无法实例化。
实际上,不需要允许对象实例化,因为静态方法不需要使用对象实例。
6. 在构建器模式中使用私有构造函数
构建器模式允许我们逐步构建复杂的对象,而不是让多个构造函数提供不同的方法来创建对象。 私有构造函数限制初始化,从而允许构建器来管理对象创建 。
在此示例中,我们创建了一个 Employee 类,其中包含员工的 姓名 、 年龄 和 部门 :
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;
}
}
正如我们所看到的,我们已经将 Employee 构造函数设为私有——因此,我们无法显式实例化该类。
现在,我们将向 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);
}
}
构建器现在可以创建不同的员工,其 名称 、 年龄 或 部门 ——我们必须提供多少个字段没有限制:
Employee.Builder emplBuilder = new Employee.Builder();
Employee employee = emplBuilder
.setName("baeldung")
.setDepartment("Builder Pattern")
.build();
我们创建了一个名为“ baeldung ”的 员工 和一个名为“ Builder Pattern ”的部门。未提供年龄,因此将使用默认的原始 int 值 0。
7. 使用私有构造函数来防止子类化
私有构造函数的另一个可能用途是防止类的子类化。如果我们尝试创建这样的子类,它将无法调用 超级 构造函数。但是,需要注意的是, 我们通常会将类设为 Final 以防止子类化,而不是使用私有构造函数 。
八、结论
私有构造函数的主要用途是限制类的实例化。 当我们想要限制类的外部创建时,私有构造函数特别有用 。
单例、工厂和静态方法对象是限制对象实例化如何有助于强制实施某种模式的示例。
常量类和静态方法类还规定类不应该是可实例化的。重要的是要记住,我们还可以将私有构造函数与公共构造函数结合起来,以允许在不同的公共构造函数定义内共享代码。
这些示例的代码可以在 GitHub 上找到。