it-swarm.com.ru

Реализация Singleton с помощью Enum (на Java)

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

public enum MySingleton {
     INSTANCE;   
}

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

150
Anand

Это,

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 ссылаются на первый раз.

182
Elliott Frisch

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

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

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

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

67
Sotirios Delimanolis

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

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

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

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

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

57
ekostadinov

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

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

Что бы это ни стоило, Джошуа Блох подробно описывает этот шаблон как пункт 3 из Действующий Java Второе издание .

9
Jeff Bowman

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

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

4
Bruno Franco

Как в некоторой степени упоминалось ранее, 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 и т.д.

2
Erk