📜  Java中使用Enum作为单例的优缺点

📅  最后修改于: 2022-05-13 01:55:41.712000             🧑  作者: Mango

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 中反序列化单例的含义,其中可能已经存在相同类型的单例。