Программируя мы часто сталкиваемся с необходимостью ограничить множество допустимых значений для некоторого типа данных. Так, например, день недели может иметь 7 разных значений, месяц в году – 12, а время года – 4. Для решения подобных задач во многих языках программирования со статической типизацией предусмотрен специальный тип данных – перечисление (![Перечисления в Java (java enum) - 1]()
Элементы перечисления — экземпляры
Элементы
То же, но с полиморфизмом:
Последний пример демонстрирует использование наследования в
Здесь объявляется перечисление ![Перечисления в Java (java enum) - 5]()
enum
). В Java перечисление появилось не сразу. Специализированная языковая конструкция enum
была введена начиная с версии 1.5. До этого момента программисты использовали другие методы для реализации перечислений.

Конструкция enum
Начнем с примера. Давайте опишем с помощьюenum
тип данных для хранения времени года:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Ну и простой пример его использования:
Season season = Season.SPRING;
if (season == Season.SPRING) season = Season.SUMMER;
System.out.println(season);
В результате выполнения которого на консоль будет выведено SUMMER. Думаю, что пример очевиден и в пояснениях не нуждается.
Перечисление — это класс
Объявляяenum
мы неявно создаем класс производный от java.lang.Enum
. Условно конструкция enum Season { ... }
эквивалентна class Season extends java.lang.Enum { ... }
. И хотя явным образом наследоваться от java.lang.Enum
нам не позволяет компилятор, все же в том, что enum
наследуется, легко убедиться с помощью reflection
:
System.out.println(Season.class.getSuperclass());
На консоль будет выведено:
class java.lang.Enum
Собственно наследование за нас автоматически выполняет компилятор Java. Далее давайте условимся называть класс, созданный компилятором для реализации перечисления — enum
-классом, а возможные значения перечисляемого типа — элементами enum
-a.
Элементы перечисления — экземпляры enum
-класса, доступные статически
Элементы enum Season (WINTER, SPRING и т.д.)
— это статически доступные экземпляры enum
-класса Season
. Их статическая доступность позволяет нам выполнять сравнение с помощью оператора сравнения ссылок ==
. Пример:
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
Название и порядковый номер элемента enum
Как уже было сказано ранее любойenum
-класс наследует java.lang.Enum
, который содержит ряд методов полезных для всех перечислений. Пример:
Season season = Season.WINTER;
System.out.println("season.name()=" + season.name() + " season.toString()=" + season.toString() + " season.ordinal()=" + season.ordinal());
Будет выведено:
season.name()=WINTER season.toString()=WINTER season.ordinal()=0
Здесь показано использования методов name()
, toString()
и ordinal()
. Семантика методов — очевидна. Следует обратить внимание, что данные методы enum
-класс наследует из класса java.lang.Enum
.
Получение элемента enum
по строковому представлению его имениДовольно часто возникает задача получить элемент enum
по его строковому представлению. Для этих целей в каждом enum
-классе компилятор автоматически создает специальный статический метод: public static EnumClass valueOf(String name)
, который возвращает элемент перечисления EnumClass
с названием, равным name
. Пример использования:
String name = "WINTER";
Season season = Season.valueOf(name);
В результате выполнения кода переменная season будет равна Season.WINTER
. Cледует обратить внимание, что если элемент не будет найден, то будет выброшен IllegalArgumentException, а в случае, если name
равен null
— NullPointerException. Об этом, кстати, часто забывают. Почему-то многие твердо уверенны, что если функция принимает один аргумент и при некоторых условиях выбрасывает IllegalArgumentException, то при передачи туда null
, также будет непременно выброшен IllegalArgumentException. Но это не относится к делу. Продолжим.
Получение всех элементов перечисления
Иногда необходимо получить список всех элементов enum
-класса во время выполнения. Для этих целей в каждом enum
-классе компилятор создает метод public static EnumClass[] values()
. Пример использования:
System.out.println(Arrays.toString(Season.values()));
Получим вывод:
[WINTER, SPRING, SUMMER, AUTUMN]
Обратите внимание, что ни метод valueOf()
, ни метод values()
не определен в классе java.lang.Enum
. Вместо этого они автоматически добавляются компилятором на этапе компиляции enum
-класса.
Добавляем свои методы в enum
-класс
У Вас есть возможность добавлять собственные методы как в enum
-класс, так и в его элементы:


enum
. Об этом — далее.
Наследование в enum
С помощью enum
в Java можно реализовать иерархию классов, объекты которой создаются в единственном экземпляре и доступны статически. При этом элементы enum
могут содержать собственные конструкторы. Приведем пример:

Type
с тремя элементами INT
, INTEGER
и STRING
. Компилятор создаст следующие классы и объекты:
Type
— класс производный отjava.lang.Enum
INT
— объект 1-го класса производного отType
INTEGER
— объект 2-го класса производного отType
STRING
— объект 3-го класса производного отType
Object parse(String)
и конструктором Type(..., boolean)
. При этом объекты классов INT
, INTEGER
и STRING
существуют в единственном экземпляре и доступны статически. В этом можно убедится:
System.out.println(Type.class);
System.out.println(Type.INT.getClass() + " " + Type.INT.getClass().getSuperclass());
System.out.println(Type.INTEGER.getClass() + " " + Type.INTEGER.getClass().getSuperclass());
System.out.println(Type.STRING.getClass() + " " + Type.STRING.getClass().getSuperclass());
Получим вывод:
class Type
class Type$1 class Type
class Type$2 class Type
class Type$3 class Type
Видно, что компилятор создал класс Type
и 3 nested
класса, производных от Type
.
Декомпилированный enum-class с наследованием
В подтверждение вышесказанному приведем еще результат декомпиляции перечисленияType
из примера выше:

Перечисления и параметрический полиморфизм
У читателя может возникнуть вопрос: "почему вышеуказанное перечисление Type не использует генерики (generics)?". Дело в том, что в Java использование генериков вenum
запрещено. Так следующий пример не скомпилируется:
enum Type<T> {}
Дальнейшее изучение
Для более глубокого понимания того, как работают перечисления в Java рекомендую ознакомиться с исходными кодами классаjava.lang.Enum
, а также воспользоваться декопмилятором Jad для изучения сгенерированного кода. Более того, изучение исходных кодов библиотеки Java абсолютно необходимо для понимания принципов работы многих механизмов в Java и полезно как эталон объектно-ориентированного дизайна.
Cсылка на первоисточник: http://alexander.lds.lg.ua/
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ