Effective Java 第三版读书笔记——条款4:使用私有构造器来强制实现不可实例化
偶尔你会想写一个类,这个类只是一组静态方法和静态属性。 这样的类获得了不好的名声,因为有些人滥用这些类而避免以面向对象的方式思考,但是它们有时候确实有实际的用处:
- 它们可以被用来聚集一组建立在基础类型或数组之上的相关方法,例如
java.lang.Math
或java.util.Arrays
。 - 它们也可以用于一组静态方法,用于实现某个接口的对象,例如
java.util.Collections
。 - 最后,这样的类可以用于 final 类上的一组方法,因为不能将它们放在子类中。
这样的实用类(utility classes)是不能被设计为可实例化类的:一个实例是没有意义的。然而,以下两种实现不可实例化类的方法都是错误的:
- 不提供显示构造器。在没有显式构造器的情况下,编译器提供了一个公共的、无参的默认构造器。对于用户来说,该构造方法与其他构造方法没有什么区别。
- 创建抽象类。抽象类可以被子类化,子类可以被实例化。此外,它误导用户认为该类是为继承而设计的(条款 19)。
不过,有一个简单的方法来确保不可实例化。只有当类不包含显式构造器时,才会生成一个默认构造器,因此可以通过包含一个私有构造器来实现类的不可实例化:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
因为显式构造器是私有的,所以在该类之外是不可访问的。这个习惯用法有点违反直觉,好像构造器就是设计成不能调用的一样。因此,添加注释是种明智的做法。
这种方法还有另一个作用——阻止了类的继承。所有的构造器都必须显式或隐式地调用父类的构造器,而继承该类的子类却没有可访问的父类构造器来调用。