ITEM 4: ENFORCE NONINSTANTIABILITY WITH A PRIVATE CONSTRUCTOR
有时,我们只想写一个仅拥有静态变量和静态方法的类,虽然这样的类名声不好,因为有些人滥用它们来避免面向对象的思想,但它们确实有用武之地。它们可以用来对一些相关的方法进行分组,如 java.lang.Math 和java.util.Arrays。也可以用于对静态方法进行分组(包括工厂),用于实现某个接口,比如 java.util.Collections (在Java8中,你可以把这些静态方法放在接口中)。最后,我们也可以将这种类用于在final类中对方法进行分组,因为不能final类不能被继承。
这样的工具类并不是为实例化而设计的:实例化毫无意义。然而,在我们没有提供显示公共构造函数的情况下,编译器会自动为我们提供一个。对用户来说,这个构造函数和其他的类(的公共构造函数)没什么差别。在已发布的API中经常看到无意识地实例化某个类。试图通过抽象类来强制非实例化是行不通的,这样的类能够被继承,并且子类可以正常实例化。还可能被用户误以为该类是为了被继承而设计的。然而,有一个办法可以确保非实例化:只有显示的声明构造函数才能阻止编译器自动生成一个,那么我们可以将构造器置为私有来达到目的:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
由于构造期被设置为private,因此在类外不可访问。AssertionError 错误并不是必须的,但它能够帮正构造函数不会意外地在类内被调用。这个构造函数保证类在任何情况下都不会被实例化。这个用法有点违反直觉,因为构造函数是明确提供的,但又不能调用它。因此最好注释说明。
还有一个好处,这个用法还可以防止类被继承。子类所有构造函数都必须显式或隐式地调用父类构造函数,而子类将无权访问父类的构造函数。