单身公共静态决赛

我一直在想Java中的单身人士。 按照惯例,单例设置如下:

private static MyClass instance = null; public static MyClass getInstance(){ if (instance == null){ instance = new MyClass(); } return instance; } private MyClass(){} 

最近我转而使用以下内容:

 public static final MyClass instance = new MyClass(); private MyClass(){} 

由于没有空检查,因此更短,更快,输入MyClass.instance对我来说比输入MyClass.getInstance()更好。 有没有理由说第二种不是主流方式呢?

第一个版本在第一次实际需要时创建实例,而第二个版本(更短的)在类初始化时运行构造函数

类或接口类型T将在第一次出现以下任何一个之前立即初始化:

  • T是一个类,并且创建了T的实例。
  • T是一个类,调用T声明的静态方法。
  • 分配由T声明的静态字段。
  • 使用由T声明的静态字段,该字段不是常量变量(第4.12.4节)。
  • T是顶级类(第7.6节),并且执行在词典内嵌套在T(第8.1.3节)内的断言语句(第14.10节)。 […]

在类Class和包java.lang.reflect中调用某些reflection方法也会导致类或接口初始化。

首次使用时的初始化是性能改进,如果构造函数中的代码进行昂贵的操作,则可以加速应用程序的启动。 另一方面,第二个版本很容易阅读,并且自动是线程安全的。

无论如何,最先进的技术不是以任何方式创建单例:对于一堆KB,您可以获得dependency injection库,使其适合您,并处理更复杂的场景(例如,查看Spring和AOP支持的注入)。

注意:第一个版本在粘贴的代码段中不是线程安全的

您首次描述的方式称为延迟实例化,即只有在首次调用时才会创建对象。 此方法不是线程安全的,因为第二个线程可以创建第二个实例。

如果您阅读以下书籍:

约书亚布洛赫的有效Java

他解释说,单例模式的最佳实现是通过使用Enum

 public enum Singleton { INSTANCE; public void doSomething() { ... } } 

然后你会通过Enum调用你的单身人士,如下所示:

 public class Test { public void test(){ Singleton.INSTANCE.doSomething(); } } 

这非常适合你所说的内容,它看起来更好更短,但也保证永远不会有第二个实例。

我可以想到两个原因:

第一个是封装 :在您的类暴露给客户端代码之后,您可能会想到如何以及何时初始化单例。 初始化方法为您以后更改策略提供了更多自由。 例如,根据运行时另一个静态变量的值,您可能会改变主意并决定使用两个不同的构造函数而不是一个构造函数。 使用您的解决方案,您必须在将类加载到内存时使用一个构造函数,而使用getInstance()您可以更改初始化逻辑,而不会影响客户端代码的接口。

第二种是惰性初始化 :使用传统的单例实现, MyClass对象仅在客户端代码第一次需要时才加载到内存中。 如果客户端代码根本不需要它,则可以节省应用程序分配的内存。 请注意,在程序运行之前,可能无法确定是否需要单例。 例如,它可能取决于用户与程序的交互。

但是,懒惰初始化不是您可能想要的。 例如,如果您正在编程交互式系统并且单例的初始化非常耗时,那么在程序加载时初始化它可能实际上更好,而不是在用户已经与它进行交互时,因为后者可能会导致第一次调用getInstance()时系统响应中的延迟。 但在这种情况下,您可以使用public方法初始化您的实例,如下所示:

 private static MyClass instance = getInstance(); 

同步线程的最佳方法是使用Double Checked(确保一次只有一个线程进入同步块,并避免每次执行代码时都获得锁定)。

 public class DoubleCheckLocking { public static class SearchBox { private static volatile SearchBox searchBox; // private attribute of this class private String searchWord = ""; private String[] list = new String[]{"Stack", "Overflow"}; // private constructor private SearchBox() {} // static method to get instance public static SearchBox getInstance() { if (searchBox == null) { // first time lock synchronized (SearchBox.class) { if (searchBox == null) { // second time lock searchBox = new SearchBox(); } } } return searchBox; } }