Enum Singleton

Открыта

Недавно мы с тобой разбирались, что такое Singleton, как его реализовать на Java и для чего он нужен. Но что если я тебе расскажу, что у Java уже есть свой синглтон из коробки? Интересно? Тогда давай разбираться.

Вероятно, ты уже знаешь о классе enum. У него есть особенность, о которой тебе стоит знать. Дело в том, что enum является реализацией синглтона. Такой вариант почти аналогичен подходу с public полем.

Singleton as enum:

public enum Device {
    PRINTER
}

Public variable singleton:

public class Printer {
    public static final Printer PRINTER = new Printer();
    private Printer() {
    }
//…
}

В случае с публичным полем вариант с enum более компактен — не нужно писать свою реализацию. И что самое важное — у енамов нет проблем с сериализацией.

Сериализация здесь работает не так, как для для обычных объектов: сериализируется только значение имени енама. При десериализации метод используется с десериализованным именем, чтобы получить экземпляр. Также enum позволяет защитить себя от рефлексивных атак.

Больше о Reflection ты узнаешь из лекций второго модуля, в теме Reflection API.

Java представляет запрет на инстанциирование енамов, и это закодировано в реализации метода newInstance класса Constructor, который часто вызывают при создании объектов через рефлексию.

Часть кода из Constructor.newInstance для создания enum:

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");

Из минусов создания Singleton через enum стоит назвать:

  • Отсутствие ленивой инициализации, так как объект создается сразу, и нельзя сделать отложенную инициализацию.

  • Невозможно расширять другие классы. То есть использовать enum как Singleton в случаях, когда нужно наследоваться от другого класса, не получится. В таких случаях нужно обращаться к уже знакомым нам вариантам реализации через статический метод или публичную переменную.

  • Используя enum как синглтон, ты можешь использовать только одно поле в enum классе.

public enum Device extends Electricity {
    PRINTER
}

Такой код выдаст нам ошибку компиляции:

No extends clause allowed for enum

Но если нам нужно реализовать интерфейс, нет проблем: enum-ы могут имплементировать интерфейсы:

public enum Device implements Electricity {
    PRINTER
}

Если тебе не нужно использовать наследование, лучше использовать реализацию Singleton через enum. Так советуем делать не только мы, но и сам Джошуа Блох.

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

20
Задача
Java Syntax Pro Beta,  20 уровень,  2 лекция
Недоступна
Создаем главный класс игры
Создаем главный класс игры
20
Задача
Java Syntax Pro Beta,  20 уровень,  2 лекция
Недоступна
Отображаем корабль
Отображаем корабль
20
Задача
Java Syntax Pro Beta,  20 уровень,  2 лекция
Недоступна
Простая программа
Простая программа
Комментарии (25)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Руслан
Уровень 48
18 августа 2025, 12:21
Надо через конструктор в enum задачку решать
Олег
Уровень 106
Expert
31 мая 2024, 14:47
А почему выводится сверху, а не снизу, например?
Александр
Уровень 66
1 июля 2024, 04:58
Пните когда будет ответ. Аналогичный вопрос.
Farhad M.
Уровень 31
27 июля 2024, 07:08
Если рассматривать ваш вопрос, то возникнет встречный: а как объект может использоваться до своего физического создания? Сначала создается и инициализируется объект, а затем он используется. Конструктор вызывается для инициализации состояния объекта на момент создания до использования его (объекта) где-либо еще в коде. Соответственно, строка "создание экземпляра..." будет выведена первой. Здесь очень важно рассматривать константу перечисления как конечный объект, который имеет все те же характеристики, что и обычные - неконечные. Здесь про порядок инициализации объектов
Farhad M.
Уровень 31
27 июля 2024, 07:58
пнул
Сергей Титов
Уровень 1
28 марта 2024, 13:44
Вообще не к месту статья. Вот это: Java представляет запрет на инстанциирование енамов, и это закодировано в реализации метода newInstance класса Constructor, который часто вызывают при создании объектов через рефлексию. Часть кода из Constructor.newInstance для создания enum: if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); вообще прям понятно, слов нет. Как раз про это всё станет известно сильно потом, зачем оно сейчас?
Farhad M.
Уровень 31
27 июля 2024, 07:16
Если коротко: рефлексия используется для извлечения данных о программе во время выполнения. Защита от этого механизма предотвращает создание объекта enum'a с помощью его конструктора. Будет странно, если в программе будет два одинаковых объекта enum, не так ли? Это противоречит самой сути данного типа данных. А вот с классами, насколько мне известно, такой трюк вполне можно провернуть =)
Andrzej
Уровень 32
Expert
22 ноября 2023, 22:29
Если тебе не нужно использовать наследование, лучше использовать реализацию Singleton через enum. Так советуем делать не только мы, но и сам Джошуа Блох. Ссылка не работает к сожалению, если кто-то знает на что она должна вести, поделитесь пожалуйста.
Vitalii
Уровень 32
Expert
27 августа 2023, 17:06
Что это? Зачем это здесь?
jvatechsBackend Developer в Ищу стажировкуExpert
4 декабря 2022, 01:02
https://habr.com/ru/post/129494/ Немного доходчиво
java
Уровень 108
Expert
16 сентября 2022, 20:12
Задача легкая если знать что в enum можно создавать конструктор
Пахопол Юлия
Уровень 51
Expert
18 августа 2022, 18:34
ниче не понятно, но оч интересно
Екатерина
Уровень 70
Expert
8 августа 2022, 08:10
непоняяятно, но пример оч любопытный,
Misha Saharin
Уровень 111
Expert
4 августа 2022, 11:38
если ты ничего не понял - это нормально
public enum YourSingleton {
        BLABLABLA;
        private YourSingleton() {
            System.out.println("something");
        }
да, ты прав)