Java中使用Enum作为单例的优缺点
Enum Singletons 是一种使用 Enum 的新方法,仅通过一个实例来实现Java中的 Singleton 模式。虽然Java中的单例模式已经存在很长时间了,但 Enum Singletons 是一个相对较新的术语,自从Java 5 开始将 Enum 作为关键字和函数实现以来一直在使用。
使用 Enum 作为单例的优点:
1. 枚举单例易于编写:如果您在Java 5 之前一直在编写单例,这是迄今为止最大的好处,您意识到即使使用双重检查锁定,您也可以拥有多个实例。虽然从Java 5开始通过改进Java内存模型和保证volatile变量解决了这个问题,但对于很多初学者来说仍然很难编写。
与带有同步的双重检查锁定相比,Enum 单例非常容易。如果你不认为下面的代码比较了传统的带双重检查锁定和Enum Singletons的单例:
在Java中使用 Enum 的单例:默认情况下,Enum 实例的创建是线程安全的,但任何其他 Enum 方法都是程序员的责任。
public enum EasySingleton{
INSTANCE;
}
您可以通过 EasySingleton.INSTANCE 访问它,比在 Singleton 上调用 getInstance()函数简单得多。
2. Enum Singletons 自己处理序列化
传统单例的另一个问题是,一旦你实现了一个可序列化的接口,它们就不再是单例了,因为 readObject() 方法总是像Java构造函数一样返回一个新实例。通过使用 readResolve() 方法并丢弃新创建的实例,您可以通过替换 Singleton 来避免这种情况,如下例所示:
private Object readResolve(){
return INSTANCE;
}
如果您的 Singleton 类维护状态,这可能会变得更加复杂,因为您需要使它们成为瞬态,但 JVM 保证使用 Enum Singleton 进行序列化。
3. Enum 实例的创建是线程安全的
默认情况下,Enum 实例是线程安全的,您无需担心双重检查锁定。
总之,单例模式是在Java 5 世界中创建单例的最佳方式,考虑到序列化和线程安全的保证以及一些代码行枚举。
Java
// Java program to demonstrate the example
// of using Enum as Singleton
enum SingletonEnum {
INSTANCE;
int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
class Main {
public static void main(String[] args) {
SingletonEnum singleton = SingletonEnum.INSTANCE;
System.out.println(singleton.getValue());
singleton.setValue(2);
System.out.println(singleton.getValue());
}
}
0
2
使用 Enum 作为单例的缺点:
1. 编码约束
在常规类中,有些事情可以实现,但在枚举类中是禁止的。例如,访问构造函数中的静态字段。由于他在特殊级别上工作,因此程序员需要更加小心。
2. 可序列化
对于单身人士来说,有状态是很常见的。一般来说,这些单例不应该是可序列化的。没有真实的例子说明将一个有状态的单例从一个 VM 传输到另一个 VM 是有意义的。单例意味着“在虚拟机中独一无二”而不是“在宇宙中独一无二”
如果序列化对于有状态的单例真的有意义,那么单例应该明确且准确地指定在另一个 VM 中反序列化单例的含义,其中可能已经存在相同类型的单例。
We save some lines of code on enum, but the price is too high, we have to carry all the baggage and enum limitations, we inadvertently inherit enum “features” that have unintended consequences. A disadvantage turns out to be the only alleged benefit – automatic serializability.