Реализация Singleton с Enum (на Java)

Я прочитал, что в Java можно реализовать Singleton, используя Enum, например:

public enum MySingleton {
     INSTANCE;   
}

Но как это работает? В частности, необходимо создать экземпляр Object. Здесь, как создается MySingleton? Кто делает new MySingleton()?

Ответ 1

Это,

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. И они создаются, когда на тип enum ссылаются впервые.

Ответ 2

Тип enum - это особый тип class.

Ваше enum будет на самом деле скомпилировано в нечто вроде

public final class MySingleton {
    public final static MySingleton INSTANCE = new MySingleton();
    private MySingleton(){} 
}

Когда ваш код впервые обращается к INSTANCE, класс MySingleton будет загружен и инициализирован JVM. Этот процесс инициализирует static поле выше один раз (лениво).

Ответ 3

В этой книге о лучших практиках Java Джошуа Блоха вы найдете объяснение, почему вам следует применять свойство Singleton с помощью частного конструктора или типа Enum. Эта глава довольно длинная, поэтому ее краткое содержание:

Создание класса Singleton может затруднить тестирование его клиентов, поскольку невозможно заменить фиктивную реализацию на singleton, если он не реализует интерфейс, который служит его типом. Рекомендуемый подход - реализовать Singletons, просто создав тип enum с одним элементом:

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

Этот подход функционально эквивалентен общедоступному полевому подходу, за исключением того, что он более лаконичен, предоставляет механизм сериализации бесплатно и обеспечивает железную гарантию против множественных экземпляров, даже перед сложными атаками сериализации или отражения.

Хотя этот подход еще не получил широкого распространения, одноэлементный тип перечисления является лучшим способом реализации синглтона.

Ответ 4

Как и все экземпляры enum, Java создает каждый объект при загрузке класса с некоторой гарантией того, что он создается только один раз для каждой JVM. Думайте об объявлении INSTANCE как об открытом статическом конечном поле: Java будет создавать экземпляр объекта при первом INSTANCE к классу.

Экземпляры создаются во время статической инициализации, которая определена в Спецификации языка Java, раздел 12.4.

Во что бы то ни стало, Джошуа Блох подробно описывает этот шаблон как пункт 3 второго издания Effective Java.

Ответ 5

Так как Singleton Pattern имеет собственный конструктор и вызывает некоторый метод для управления экземплярами (например, некоторые getInstance), в Enums у нас уже есть неявный частный конструктор.

Я точно не знаю, как JVM или какой-либо контейнер управляет экземплярами нашего Enums, но, похоже, он уже использует неявный Singleton Pattern, разница в том, что мы не называем getInstance, мы просто вызовите Enum.

Ответ 6

Как в некоторой степени упоминалось ранее, enum - это класс java со специальным условием, что его определение должно начинаться хотя бы с одной "константы enum".

Отчасти это класс, как и любой класс, и вы используете его, добавляя методы под определениями констант:

public enum MySingleton {
    INSTANCE;

    public void doSomething() { ... }

    public synchronized String getSomething() { return something; }

    private String something;
}

Вы получаете доступ к одноэлементным методам по этим направлениям:

MySingleton.INSTANCE.doSomething();
String something = MySingleton.INSTANCE.getSomething();

Использование enum вместо класса, как уже упоминалось в других ответах, касается, в основном, поточно-ориентированной реализации синглтона и гарантии того, что он всегда будет только одной копией.

И, пожалуй, самое главное, что такое поведение гарантируется самой JVM и спецификацией Java.

Здесь раздел из спецификации Java о том, как предотвратить несколько экземпляров экземпляра enum:

Тип enum не имеет экземпляров, отличных от определенных его константами. Это ошибка времени компиляции, чтобы попытаться явно создать экземпляр типа enum. Последний метод клонирования в Enum гарантирует, что константы enum никогда не могут быть клонированы, а специальная обработка механизмом сериализации гарантирует, что повторяющиеся экземпляры никогда не будут созданы в результате десериализации. Рефлексивная реализация типов перечислений запрещена. Вместе эти четыре вещи гарантируют, что не существует ни одного экземпляра типа enum, кроме тех, которые определены константами enum.

Стоит отметить, что после создания экземпляра любые проблемы безопасности потоков должны обрабатываться, как и в любом другом классе с ключевым словом synchronized и т.д.

Ответ 7

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();
   }
}