今天看到同事写的代码中将工具类声明为 abstract
,猜测是为了防止将该工具类实例化?个人认为这种方法属于使用不当,如果查看 JDK 中 Arrays
的源码:
1 | public class Arrays { |
可以看出,工具类 Arrays
采用了一个私有的构造函数以防止该类被实例化,同理,观察 JDK 中 Collections
的源码:
1 | public class Collections { |
实现与 Arrays
一致,也是采用的私有化构造器防止工具类被实例化,均未采用抽象类的方式去实现工具类。在 《Effective Java中文版(第3版)》 第 4 条 “通过私有构造器强化不可实例化的能力” 中也有提到,企图通过将类做成抽象类来强制该类不可被实例化,这是行不通的。因为该类可以被子类化,并且该子类也可以被实例化。这样做甚至会误导用户,以为这种类是专门为了继承而设计的。根据 Effective Java 中的描述,建议使用如下的私有构造器:
1 | // Noninstantiable utility class |
相比 JDK 中 Arrays
与 Collections
中的实现,在私有构造器中,还新增了对 Error
的抛出,此行代码可以避免不小心在类的内部调用构造器。它保证该类在任何情况下都不会被实例化。比如 java.util.Objects
类的源代码,即使用了这样的私有构造器:
1 | /** |
如果查看 org.springframework.util
中的工具类,你会发现几乎全部被声明了 abstract
,个人认为这是一个典型的反例,源码参见:spring-framework/spring-core/src/main/java/org/springframework/util at v5.3.10 · spring-projects/spring-framework · GitHub,关于该问题的讨论可以参考:why “NestedExceptionUtils” in spring source code is declared as an abstract class? - Stack Overflow。
Reference
Should Helper/Utility Classes be abstract? - Stack Overflow
What is the best way to write utility classes in Java? - Quora