Недавно мы с тобой разбирались, что такое 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. Так советуем делать не только мы, но и сам Джошуа Блох.

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

undefined
19
Задача
Java Syntax Pro, 19 уровень, 2 лекция
Недоступна
Знакомство с foreach
В классе Solution публичный метод print(ArrayList<Integer>) выводит в консоли все элементы списка по порядку. Сейчас метод реализован с использованием оператора for. Необходимо переписать реализацию метода print(ArrayList<Integer>), используя метод списка forEach(), принимающий лямбда-выражение. Лог
undefined
19
Задача
Java Syntax Pro, 19 уровень, 2 лекция
Недоступна
Прощание с foreach
В классе Solution публичный метод print(ArrayList<String>) выводит в консоли все элементы списка по порядку. Сейчас метод реализован с использованием метода списка forEach(). Необходимо переписать реализацию метода print(ArrayList<String>), используя оператор for, не меняя логику работы метода. Мето
undefined
19
Задача
Java Syntax Pro, 19 уровень, 2 лекция
Недоступна
Знакомство со ссылками на методы
В классе Solution публичный метод print(ArrayList<String>) выводит в консоли все элементы списка по порядку. Сейчас метод реализован с использованием метода списка forEach(), который принимает лямбда-выражение. Необходимо переписать реализацию метода print(ArrayList<String>), чтобы метод списка forE
undefined
19
Задача
Java Syntax Pro, 19 уровень, 2 лекция
Недоступна
Прощание со ссылками на методы
В классе Solution публичный метод print(ArrayList<Integer>) выводит в консоли все элементы списка по порядку. Сейчас метод реализован с использованием метода списка forEach(), который принимает ссылку на метод. Необходимо переписать реализацию метода print(ArrayList<Integer>), чтобы метод списка for
undefined
19
Задача
Java Syntax Pro, 19 уровень, 2 лекция
Недоступна
Преобразование списка в массив
В классе Solution есть два публичных статических метода: - String[] toStringArray(ArrayList<String>), в котором нужно преобразовать список строк в массив строк и вернуть его; - Integer[] toIntegerArray(ArrayList<Integer>), в котором нужно преобразовать список чисел в массив чисел и вернуть его; Для