Программируя мы часто сталкиваемся с необходимостью ограничить множество допустимых значений для некоторого типа данных. Так, например, день недели может иметь 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.EnumINT— объект 1-го класса производного отTypeINTEGER— объект 2-го класса производного отTypeSTRING— объект 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/
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ