Java enum, также называемый типом перечисления Java, — это тип, поля которого состоят из фиксированного набора констант. Сама цель enum — обеспечить безопасность типов во время компиляции. Ключевое слово enum — одно из зарезервированных ключевых слов в Java.
Мы должны использовать перечисление, когда мы знаем все возможные значения переменной во время компиляции или проектирования, хотя мы можем добавить больше значений в будущем, когда идентифицируем их. В этом руководстве по перечислению Java мы узнаем, что такое перечисления и какие проблемы они решают.
1. Основы перечислений
Перечисления(в общем) — это набор связанных констант. Они были в других языках программирования, таких как C++, с самого начала. После JDK 1.4 разработчики Java решили поддерживать их и в Java, и они были официально выпущены в релизе JDK 1.5.
Перечисление в Java поддерживается ключевым словом enum. Перечисления — это особый тип класса, который всегда расширяет java.lang.Enum.
1.1. Перечисление — это зарезервированное ключевое слово.
Enum — это зарезервированное ключевое слово, которое означает, что мы не можем определить переменную с именем enum. Например, это приведет к ошибке времени компиляции «invalid VariableDeclaratorId».
String enum = "Hello World !!";

1.2 Синтаксис для создания перечислений
Как мы знаем, в повседневной жизни мы обычно имеем дело с четырьмя направлениями. Их названия, углы и другие свойства фиксированы. Поэтому в программах мы можем создать для них перечисление. Синтаксис для создания перечисления следующий:
enum Direction {EAST, WEST, NORTH, SOUTH;}
Логически, каждое перечисление является экземпляром самого типа перечисления. Таким образом, данное перечисление можно рассматривать как следующее объявление. JVM внутренне добавляет методы порядкового и значимого типа к этому классу, которые мы можем вызывать при работе с перечислением.
final class Direction extends Enum<Direction> {public final static Direction EAST = new Direction();public final static Direction WEST = new Direction();public final static Direction NORTH = new Direction();public final static Direction SOUTH = new Direction();}
1.3 Соглашения об именовании
По соглашению перечисления являются константами. В Java константы определяются всеми ЗАГЛАВНЫМИ буквами. Это справедливо и для перечислений.
- Имя перечисления должно быть указано с заглавной буквы(так же, как и имена классов).
- Все поля перечисления должны быть в ВЕРХНЕМ РЕГИСТРЕ(так же, как статические окончательные константы).
1.4 Переменные перечисления
Мы можем создать переменную указанного типа перечисления точно так же, как мы используем конечные статические поля класса.
Direction north = Direction.NORTH;System.out.println(north); //Prints NORTH
2. Конструкторы перечислений
По умолчанию перечисления не требуют определений конструкторов, а их значения по умолчанию всегда являются строкой, используемой в объявлении. Хотя вы можете определить собственные конструкторы для инициализации состояния типов перечислений.
Например, мы можем добавить к направлению атрибут угла. Все направления имеют некоторый угол.
enum Direction {EAST(0), WEST(180), NORTH(90), SOUTH(270);// constructorprivate Direction(final int angle) {this.angle = angle;}// internal stateprivate int angle;public int getAngle() {return angle;}}
Если мы хотим получить доступ к углу для любого направления, мы можем сделать простой вызов метода в ссылке на поле перечисления.
Direction west = Direction.WEST;System.out.println(west);System.out.println(west.getAngle());//orSystem.out.println(Direction.WEST.getAngle());
Вывод программы:
WEST180180
3. Встроенные методы
По умолчанию перечисление будет иметь следующие методы для доступа к своим константам.
3.1. ординал()
Метод ordinal() возвращает порядок экземпляра enum среди списка констант. Он представляет последовательность в объявлении enum, где начальной константе присваивается порядковый номер '0'. Это очень похоже на индексы массива.
Ordinal предназначен для использования в сложных структурах данных на основе перечислений, таких как EnumSet и EnumMap.
Direction.EAST.ordinal(); //0Direction.NORTH.ordinal(); //2
3.2. значения() и значениеOf()
Метод enum values() возвращает все значения перечисления в виде массива перечисления.
Direction[] directions = Direction.values();for(Direction d : directions) {System.out.println(d);}
Вывод программы:
EASTWESTNORTHSOUTH
Метод enum valueOf() помогает преобразовать строку в экземпляр enum.
Direction east = Direction.valueOf("EAST");System.out.println(east);
Вывод программы:
EAST
4. Индивидуальные методы
Помните, что enum по сути является особым типом класса и может иметь методы и поля, как и любой другой класс. Мы можем добавлять методы, которые являются абстрактными, а также неабстрактными методами. Оба метода разрешены в enum.
4.1 Неабстрактные методы
Добавление конкретного метода в enum похоже на добавление того же метода в любой другой класс. Мы можем использовать любой спецификатор доступа, например public, private или protected. Мы можем возвращать значения из методов enum или просто использовать их для выполнения внутренней логики.
public enum Direction {EAST, WEST, NORTH, SOUTH;protected String message() {String message = "Moving in " + this + " direction";return message;}}
Мы можем вызвать метод message() как простой вызов метода для экземпляра перечисления.
Direction.NORTH.message();
4.2 Абстрактные методы
Мы также можем добавлять абстрактные методы в перечисления. В этом случае мы должны реализовать абстрактный метод в каждом поле перечисления, индивидуально.
public enum Direction{EAST {@Overridepublic String message() {return "You are moving in east. You will face sun in morning time.";}},WEST {@Overridepublic String message() {return "You are moving in west. You will face sun in evening time.";}},NORTH {@Overridepublic String message() {return "You are moving in north. Sea behind.";}},SOUTH {@Overridepublic String message() {return "You are moving in south. Sea ahead.";}};public abstract String message();}
Повторите приведенный выше пример.
Direction.WEST.message(); //You are moving in west. You will face sun in evening time.Direction.NORTH.message(); //You are moving in north. Sea behind.
Мы можем обеспечить контракт для всех перечислений, которые будут созданы таким образом. Он может служить шаблоном для создания перечислений.
Например, если мы хотим, чтобы каждый тип перечисления Direction мог выводить имя направления с пользовательским сообщением при необходимости. Это можно сделать, определив абстрактный метод внутри Direction, который каждое перечисление должно переопределить.
5. Наследование
Как упоминалось ранее, enum расширяет класс Enum. Java.lang.Enum — это абстрактный класс. Это общий базовый класс всех типов перечислений Java.
public abstract class Enum<E extends Enum<E>> extends Objectimplements Constable, Comparable<E>, Serializable {//...}
Это означает, что все перечисления сопоставимы и сериализуемы неявно. Кроме того, все перечисления в Java по умолчанию являются синглтонами.
Как было отмечено, все перечисления расширяют java.lang.Enum, поэтому перечисление не может расширять никакой другой класс, поскольку Java не поддерживает множественное наследование таким образом. Но перечисления могут реализовывать любое количество интерфейсов.
6. Сравнение двух перечислений
Все перечисления по умолчанию сопоставимы и являются синглтонами. Это означает, что вы можете сравнивать их с помощью метода equals(), даже с оператором «==».
Direction east = Direction.EAST;Direction eastNew = Direction.valueOf("EAST");System.out.println( east == eastNew ); //trueSystem.out.println( east.equals( eastNew ) ); //true
Мы можем сравнивать типы перечислений, используя оператор «==» или метод equals(), поскольку перечисления по умолчанию являются одиночными и сравнимыми.
7. EnumSet и EnumMap
В пакет java.util добавлены два класса для поддержки перечислений — EnumSet(высокопроизводительная реализация Set для перечислений; все члены набора перечислений должны иметь один и тот же тип перечисления) и EnumMap(высокопроизводительная реализация Map для использования с ключами перечисления).
7.1.ПеречислениеНаборов
Класс EnumSet — это специализированная реализация Set для использования с типами enum. Все элементы в наборе enum должны происходить из одного типа enum, который указывается явно или неявно при создании набора.
Set enumSet = EnumSet.of(Direction.EAST,Direction.WEST,Direction.NORTH,Direction.SOUTH);
Как и большинство реализаций коллекций, EnumSet не синхронизирован. Если несколько потоков одновременно обращаются к набору перечислений и хотя бы один из потоков изменяет набор, он должен быть синхронизирован извне.
Обратите внимание, что нулевые элементы не допускаются в EnumSet. Кроме того, эти наборы гарантируют упорядочивание элементов в наборе на основе их порядка в константах перечисления, объявленных. Преимущества производительности и памяти очень высоки по сравнению с обычной реализацией набора.
7.2.Карта перечисления
EnumMap — это специализированная реализация Map для использования с ключами типа enum. Кроме того, все ключи в карте enum должны происходить из одного типа enum, который указывается явно или неявно при создании карты.
Как и в EnumSet, нулевые ключи не допускаются и не синхронизируются.
Map<Direction, Integer> enumMap = new EnumMap(Direction.class);enumMap.put(Direction.EAST, Direction.EAST.getAngle());enumMap.put(Direction.WEST, Direction.WEST.getAngle());enumMap.put(Direction.NORTH, Direction.NORTH.getAngle());enumMap.put(Direction.SOUTH, Direction.SOUTH.getAngle());
8. Резюме
- Перечисления Java неявно являются конечными подклассами класса java.lang.Enum
- Если перечисление является членом класса, оно неявно статично.
- Ключевое слово new не может быть использовано для инициализации перечисления, даже внутри самого типа перечисления.
- Методы name() и valueOf() используют текст констант перечисления, в то время как метод toString() может быть переопределен для предоставления любого содержимого при желании.
- Для констант перечисления equals() и «==» вычисляют один и тот же результат и могут использоваться взаимозаменяемо.
- Константы enum неявно являются public static final
- Порядок появления списка констант перечисления называется их «естественным порядком» и определяет порядок, используемый также другими элементами: методом compareTo(), порядком итерации значений в EnumSet, EnumSet.range().
- Конструкторы enum должны быть объявлены как private. Компилятор допускает не private-конструкторы, но это может ввести читателя в заблуждение, поскольку new никогда не может использоваться с enum-типами.
- Поскольку все эти экземпляры перечисления фактически являются одиночными, их можно сравнить на равенство с помощью тождества(«==»).
- Мы можем использовать перечисление в операторах switch, например, примитивный тип данных int или char.
В этой статье мы рассмотрели перечисление Java, начиная с основ языка и заканчивая более сложными и интересными вариантами использования в реальной жизни.