有时候你只想编写有一组静态方法和静态字段的一个类。这些类获取了一个坏名声,因为一些人滥用它们来避免思考如何面向对象,但是它们确实是有用的。它们以java.lang.Math或java.util.Arrays这种方式组织基本类型或数组。它们也能被使用分组静态方法,包括工厂方法(item1),以java.util.Collections的方式为对象实现一些接口(作为Java8,你也可以放置这些方法在你的接口中,假设这些修改是你的)。最后一点,当你不能放置它们在子类中时,这些类可以在final类中被用来组织方法。
这些工具类(utility classes)并不是为了实例化而设计的:它的实例是没有意义的。没有显式构造方法的情况下,编译器提供了一个公有的,无参的默认构造方法(default constructors)。对于用户来说,这个构造方法对于任何人都是无法区分的。在已发布的API中看到无意中可实例化的类是不罕见的。
尝试通过使一个类抽象的办法强制不可实例化是没用的.因为这个类可以是子类,并且子类是可以被实例化的。此外,它误导用户认为该类是被用来继承的(item19)。这里介绍一个简单的习惯来确保不可实例化。默认构造方法是只在没有显示构造方法的前提下产生的,所以一个类可以通过包含一个私有构造方法来使之不可实例化:
因为该显示构造方法是私有的,在类外部是不可访问的。AssertionError不是必须的,但是当这个类的构造方法突然被调用时提供了保险。它确保了这个类永远不会被实例化在任何条件下。这个习惯有点反常,因为这个构造方法明确提供但是它不能被调用。因此,如前所示,提供注释是明智的。
作为副作用,这个习惯也阻止了该类被子类实例化。所有构造方法必须调用超类的构造方法,显示或隐示的,并且子类将没有调用访问超类的构造方法的权限。
本文写于2018.11.22,历时2天