Effective-Java-4通过私有构造器强化不可实例化的能力

你可能需要编写只包含静态方法和静态域的类(例如一些工具类) 。这些类的名声很不好,因为有些人在面向对象的语言中滥用这样的类来编写过程化的程序。但它们也的确有他们的用处。

这样的工具类 (utility class) 不希望被实例化,实例对它们没有意义。然而,在缺少显式构造器的情况下,编译器会自动提供一个共有的,无参的缺省构造器(default constructor)。对于用户而言,这个构造器与其他的构造器没有任何的区别,在已发行的API中常常可以看到一些被无意识地实例化的类。

企图通过将类做成抽象类来强制该类不可被实例化,这样是行不通的。该类可以被子类化,并且该子类可被实例化。这样甚至会误导用户,以为该类是特意为了继承而设计的。然而,有一些简单的习惯用法可以保证类不被实例化。由于只有当类不包含显式构造器时,编译器才会产生缺省的构造器,因此我们只要让这个类包含私有构造器,它就不能被实例化了:

1
2
3
4
5
6
7
8
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiaility
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}

由于显示的构造器是私有的,所以不可以在该类的外部访问它。AssertionError不是必需的,但是它可以避免不小心在该类的内部调用构造器。他保证该类在任何情况下都不会被实例化。这种习惯用法有点违背直觉,好像构造器的声明就是设计成不能被调用一样。因此,较好的做法是,在代码中增加注释(见上文)。

这种习惯用法也有其副作用,它使得一个类不能被子类化。所有的构造器都必须显示或隐式地调用超类 (superclass) 构造器,在这种情况下,子类就没有可访问的超累构造器可以调用了。