文章作者:Tyan
博客:noahsnail.com | CSDN | 简书
Item 4: 用私有构造函数强制不能实例化
有时你会想写一个只包含一组静态方法和静态变量的类。这种类的名声很不好,因为有些人滥用它们来避免思考如何面向对象,但它们确实是有用的。它们可以用来以java.lang.Math
或java.util.Arrays
的方式来组织与基本类型或数组相关的方法。它们也可以用来以java.util.Collections
的方式来组织实现特定接口对象的静态方法,包括工厂方法(Item 1)。最后,它们可以用来组织一个fianl类的方法,从而代替扩展这个类。
这种工具类被设计成不能实例化:它的实例是没有意义的。然而,在缺少显式构造函数的情况下,编译器会提供一个公有的无参构造默认函数。对用户而言,这个构造函数与其它的构造函数没有任何差别。在发布的APIs中看到无意义的可实例化类是很罕见的。
企图通过声明一个类为抽象类来强制类不能被实例化是行不通的。这个类可以被子类化,子类可以被实例化。而且,它会使用户误认为这个类是为继承而设计的(Item 17)。然而有一些简单的习惯用法可以确保类不能被实例化。如果一个类没有显式的构造函数,会产生默认的构造函数,因此,一个含有私有构造函数的类不能被实例化:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
因为显式构造函数是私有的,因此类的外部不能访问构造函数。AssertionError
不是必须的,但它可以避免类内部无意的调用构造函数。这种习惯用法有点违背直觉,似乎构造函数的提供就是为了它不能被调用一样。因此明智的做法是在类中加上注释,像上面的例子一样。
这种习惯用法的一个副作用就是阻止了类的子类化。子类的所有的构造函数必须调用父类的构造函数,无论是显式的或隐式的,但这种情况下子类不能调用父类构造函数。