用Enum实现Singleton(用Java)
我读过,可以使用Enum
来实现Java中的Singleton
,例如:
public enum MySingleton { INSTANCE; }
但是,上述工作如何? 具体来说,一个Object
必须被实例化。 在这里, MySingleton
如何被实例化? 谁在做new MySingleton()
?
这个,
public enum MySingleton { INSTANCE; }
有一个隐含的空构造函数。 让我们来明确一点,
public enum MySingleton { INSTANCE; private MySingleton() { System.out.println("Here"); } }
如果你用类似main()
方法添加了另一个类
public static void main(String[] args) { System.out.println(MySingleton.INSTANCE); }
你会看到的
Here INSTANCE
enum
字段是编译时间常量,但它们是enum
types的实例。 而且,它们是在第一次引用枚举types时构造的。
在Joshua Bloch的Java最佳实践书中 ,你可以find解释为什么你应该使用私有构造函数或Enumtypes来强制实现Singleton属性。 这一章很长,所以总结一下:
将一个类作为一个Singleton可以使得testing它的客户端变得困难,因为除非它实现了一个types的接口,否则不可能用一个单例替代一个模拟实现。 推荐的方法是通过简单地使用一个元素来枚举types来实现单例:
// Enum singleton - the preferred approach public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } }
这种方法在function上等同于公共领域的方法,除了它更简洁,提供了免费的序列化机制,并且提供了对多重实例化的铁证,即使面对复杂的序列化或reflection攻击。
虽然这种方法尚未被广泛采用,但是单元枚举types是实现单例的最好方法。
enum
types是一种特殊的class
types。
你的enum
声明实际上编译成类似的东西
public final class MySingleton { public final static MySingleton INSTANCE = new MySingleton(); }
当你的代码首先访问INSTANCE
, MySingleton
类将被JVM加载和初始化。 这个过程初始化一次 (懒惰)的static
字段。
像所有枚举实例一样,Java在加载类时实例化每个对象,并保证每个JVM仅实例化一次。 将INSTANCE
声明看作公共静态最终字段:Java将在第一次引用类时实例化对象。
这些实例是在静态初始化过程中创build的,这在Java语言规范第12.4节中定义。
对于什么是值得的, Joshua Bloch详细描述了这个模式,作为Effective Java Second Edition的第 3项。
由于Singleton模式是关于有一个私人的构造函数,并调用一些方法来控制实例(如一些getInstance
),在枚举中,我们已经有一个隐式的私有构造函数。
我不完全知道如何JVM或一些容器控制我们的Enums
实例,但它似乎已经使用隐式Singleton Pattern
,不同之处是我们不调用getInstance
,我们只是调用枚举。
enum Checks { INSTANCE; Checks() { System.out.println("checks"); } public void dowork() { System.out.println(" do work please "); } } public class EnumSingelton { public static void main(String[] args) { Checks.INSTANCE.dowork(); } }