Перечисления (enum) в Java: полное руководство с примерами - Вопросы

Всего: 7 вопросов

1. 

Как сравнивать константы перечисления (enum) в Java: через equals() или ==?

Можно использовать и метод equals(), и оператор == — результат одинаковый, потому что каждая константа enum существует в единственном экземпляре. Метод equals() в java.lang.Enum объявлен final и возвращает true только для той же самой константы.

Для enum оператор == даже предпочтительнее: он не выбросит NullPointerException, если слева null, а сравнение констант разных перечислений через == компилятор отклонит сразу. Чтобы сравнить константы по порядку объявления, используют compareTo().

2. 

Что делают методы values() и valueOf() у enum в Java и какие исключения может выбросить valueOf()?

Оба метода статические, их генерирует компилятор в каждом перечислении (в классе java.lang.Enum они не объявлены).

values() возвращает массив всех констант в порядке объявления — это стандартный способ перебрать enum в цикле. Каждый вызов создаёт новую копию массива.

valueOf(String) возвращает константу, имя которой в точности совпадает со строкой (с учётом регистра, без обрезки пробелов). Если такой константы нет, выбрасывается IllegalArgumentException, если передан null — NullPointerException.

CoffeeSize s = CoffeeSize.valueOf("BIG");   // BIG
CoffeeSize.valueOf("big");                  // IllegalArgumentException
3. 

Чем отличаются методы name() и toString() у enum и что возвращает ordinal()?

name() объявлен final и всегда возвращает имя константы точно так, как оно записано в коде. toString() по умолчанию возвращает то же самое, но его можно переопределить, например, чтобы показывать пользователю понятную подпись. Для преобразования enum в строку и обратно через valueOf() используйте name(): valueOf() ищет константу по имени, а не по результату toString().

ordinal() возвращает позицию константы в объявлении, начиная с нуля. Не храните ordinal() в базе данных или файле: при добавлении константы в середину или смене порядка номера сдвинутся. Храните name() или собственное поле-код.

4. 

Каким может быть конструктор enum и как он вызывается?

Конструктор перечисления всегда private: если модификатор не указан, он подразумевается, а public или protected вызовут ошибку компиляции. Создать экземпляр enum через new нельзя.

Конструктор вызывается при инициализации перечисления — аргументы указываются в скобках после имени константы. Список констант должен идти первым и заканчиваться точкой с запятой, если за ним следуют другие члены. Конструкторы можно перегружать: константа без скобок использует конструктор без параметров.

enum CoffeeSize {
    BIG(100), HUGE(150), OVERWHELMING(200);

    private final int ml;

    CoffeeSize(int ml) { this.ml = ml; }

    public int getMl() { return ml; }
}
5. 

Как использовать enum в операторе switch и что произойдёт, если переменная enum равна null?

Метки case должны быть константами того же перечисления, что и выражение switch; обычно пишут простое имя константы (case BIG). Квалифицированное имя case CoffeeSize.BIG разрешено только начиная с Java 21.

В switch-выражении со стрелками (Java 14+) ветка default не нужна, если перечислены все константы: компилятор проверяет полноту, и при добавлении новой константы код перестанет компилироваться.

String message = switch (size) {
    case BIG -> "Big cup";
    case HUGE -> "Huge cup";
    case OVERWHELMING -> "Overwhelming cup";
};

Если переменная enum равна null, классический switch выбрасывает NullPointerException, и ветка default от этого не спасает.

6. 

Может ли enum наследовать класс, реализовывать интерфейсы и иметь абстрактные методы?

Наследовать класс явно enum не может: каждое перечисление неявно расширяет java.lang.Enum, а множественного наследования классов в Java нет, поэтому extends в объявлении enum не компилируется. Унаследоваться от enum тоже нельзя — оно неявно final.

Реализовывать можно любое число интерфейсов: метод интерфейса реализуется один раз для всего enum или отдельно в теле каждой константы.

Enum может объявить абстрактный метод — тогда каждая константа обязана реализовать его в своём теле. Константа с телом — это экземпляр анонимного подкласса, поэтому getClass() вернёт класс вида Operation$1, а сам тип перечисления возвращает getDeclaringClass().

enum Operation {
    PLUS  { public int apply(int a, int b) { return a + b; } },
    MINUS { public int apply(int a, int b) { return a - b; } };

    public abstract int apply(int a, int b);
}
7. 

Что такое EnumSet и EnumMap и чем они лучше HashSet и HashMap для enum?

Это коллекции из пакета java.util, созданные специально для перечислений:

  • EnumSet — множество констант одного enum, внутри хранится как битовая маска;
  • EnumMap — отображение с константами enum в качестве ключей, внутри это массив, индексированный по ordinal().

Поскольку они опираются на порядковые номера констант, они быстрее и компактнее, чем HashSet и HashMap, а элементы перебираются в порядке объявления констант.

Set<CoffeeSize> large = EnumSet.of(CoffeeSize.HUGE, CoffeeSize.OVERWHELMING);
Map<CoffeeSize, Integer> prices = new EnumMap<>(CoffeeSize.class);
Страница 1 из 1