翻译
偶尔你需要写一个只有一组静态方法或静态成员变量的工具类,这个类有一个不好的名声,因为调用者考虑到对象的创建时候滥用这个类,而调用者通过构造函数创建对象的方式确实是在合理使用这个工具类。工具类是可以被用来在一个原生值或者数组中的一组关联的方法,就像java.lang.Math或者java.util.Arrays这样的类;工具类也可能包含返回一些实现了接口的静态工厂方法,就像java.util.Collections这样的类,(在java8中,如果你要修改方法实现,你可以把一些方法放到接口中),最后,你需要把你的工具类定义为final类,因为你不想再把这些工具方法放到子类中。
这种工具类通常被设计为不可实例化,缺少明确的构造函数对于不可实例化是无意义的,因为编译器提供了一个无参公共的默认构造函数;对用户来说,难以分辨这个编译器默认提供的构造函数跟自定义的构造函数,在公共API中意外看到可实例化的类很常见。
尝试创建一个抽象类来强制不可实例化是行不通的;这个抽象类可以被继承,而子类是可以被实例化。更糟糕的是,它误导用户去思考这个类是被设计成层级分明的。
然而,有一个简单方式可以保证工具类不可实例化,只有一个类没有定义明确的构造函数的时候编译器才会生成一个默认的构造函数,所以,如果一个类包含一个私有构造函数就可以让它不可实例化。示例代码如下:
// Noninstantiable utility class 不可实例化的工具类 public class UtilityClass { // Suppress default constructor for noninstantiability private UtilityClass() { throw new AssertionError(); } // Remainder omitted }
因为有明确的私有构造函数,外部类是不无法访问构造函数的,AssertionError不是严格需要的,但是它提供了当类的私有构造函数被意外调用的时候的一层保险,它保证了类在任何状况下不会被实例化,这是违反直觉的, 因为提供了明确的无法被调用的构造函数,所以包含一个早期明确的注释是非常明智的。
私下的影响是:因为所有子类的构造函数必须显式或者隐式调用父类的构造函数,而这种类的子类无权调用父类的构造函数,所以这种类可以防止生成子类。
快速记忆
我的看法
写工具类的时候,最好是提供一个私有构造函数,防止被实例化和通过继承的方式扩展子类 ;防止出现工具类被滥用实例化,通过类直接调用工具方法是最保险的方式,而为工具类提供一个私有构造函数,强制调用者必须使用类名来调用工具方法;
原创不易,转载请注明出处,一起学习Effective java 3,提高代码质量,编程技能。欢迎一起讨论。