Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 числа».
Предыдущая статья — «Java 8 наследование».
Тип enum — это специальный тип, который позволяет переменной иметь одно из предопределённых константных значений. Объявление перечислений схоже с объявлениями классов: модификатор доступа, ключевое слово enum (НЕ class !), имя типа, тело перечисления. Тело перечисления содержит имена предопределённых константных значений.
Пример:
1 2 3 4 5 6 |
public enum Direction { NORTH, SOUTH, EAST, WEST } |
Затем можно объявить переменную нашего созданного типа перечисления:
1 |
Direction direction = Direction.NORTH; |
Используйте перечисления всегда, когда вам нужен набор предопределённых связанных между собой констант.
Пример использования:
Файл «Goblin.java»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
enum Direction { NORTH, SOUTH, EAST, WEST } class Goblin { private int x; private int y; public void move(Direction direction) { switch (direction) { case NORTH: y--; break; case EAST: x++; break; case SOUTH: y++; break; case WEST: x--; break; } } } |
Перечисления в Java являются классами.
Все перечисления неявно наследуются от класса java.lang.Enum. Поскольку в Java нет множественного наследования, то перечисление не может наследоваться от какого-либо другого класса дополнительно, но может реализовывать сколько угодно интерфейсов.
Из класса java.lang.Enum каждое перечисление получает пару полезных методов:
1 |
public final int ordinal() |
Возвращает порядковый номер константы в перечислении. Нумерация начинается с нуля.
1 |
public final String name() |
Метод name() возвращает имя константы так, как оно было объявлено в перечислении. Например, NORTH .
Также все перечисления неявно становятся final, если у них нет ни одной константы с телом класса (описано ниже). Нельзя указывать перечисление в качестве расширяемого класса. Нельзя указывать модификаторы final и abstract для перечислений.
Вложенные перечисления всегда неявно static . Нельзя явно указывать этот модификатор, иначе будет ошибка компиляции.
Так как вложенные перечисления являются статическими, то отсюда вытекает, что анонимные классы; лямбда выражения; внутренние классы, являющиеся нестатическими членами класса, и локальные классы НЕ могут содержать перечислений.
К каждому перечислению компилятор добавляет статический метод values() , который возвращает массив возможных значений для перечисления в том порядке, в котором они объявлены, и статический метод valueOf(String name) , который возвращает ссылку на константу перечисления по её имени.
1 2 3 4 5 |
for (Direction direction : Direction.values()) { System.out.println("toString(): " + direction.toString()); System.out.println("ordinal(): " + direction.ordinal()); System.out.println("name() :" + direction.name()); } |
Выведет:
1 2 3 4 5 6 7 8 9 10 11 12 |
toString(): NORTH ordinal(): 0 name() :NORTH toString(): EAST ordinal(): 1 name() :EAST toString(): SOUTH ordinal(): 2 name() :SOUTH toString(): WEST ordinal(): 3 name() :WEST |
Константные значения перечислений ( Direction.NORTH , Direction, EAST и т. д.) являются экземплярами этого класса перечисления ( Direction ), но их можно сравнивать через == , так как для каждой из этих констант всегда будет существовать только один объект. Нельзя пытаться создать экземпляр перечисления вручную любым способом — будет ошибка компиляции. Reflection, метод clone() и механизм сериализации/десериализации гарантируют, что не произойдёт создания нового объекта.
Для каждого константного значения в перечислении создаётся поле с модификаторами public static final , с тем же именем, что и константное значение. Это поле имеет выражение инициализации этой константой и имеет те же аннотации, что и константное значение.
Объявление констант в перечислении позволяет указать параметры для конструктора перечисления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
enum Monster { GOBLIN(100, 50), HOBGOBLIN(110, 30), GREMLIN(200, 10); private int health; private int magic; Monster(int health, int magic) { this.health = health; this.magic = magic; } public int getHealth() { return this.health; } public int getMagic() { return this.magic; } } class Main { public static void main(String[] args) { System.out.println("Goblin. Health: " + Monster.GOBLIN.getHealth() + " magic: " + Monster.GOBLIN.getMagic()); } } |
Перечисление может иметь несколько конструкторов, тогда подходящий выбирается по параметрам. Перечисление не может содержать конструкторов с модификаторами доступа public или protected. Конструктор без модификатора доступа в перечислении становится приватным ( private ).
Если в перечислении нет ни одного объявления конструктора, то автоматически добавляется конструктор по умолчанию без параметров, с модификатором доступа private и без списка возможных исключений.
Если конструктор перечисления содержит ключевое слово super , то возникает ошибка компиляции.
Нельзя обращаться к статическим полям перечисления, если они не являются константами (например, public static int CONST1 = 200; ), из конструкторов, блоков инициализации экземпляров, выражений инициализации.
Константы перечисления могут содержать тело класса, тогда эти классы автоматически являются анонимными и наследуются от класса текущего перечисления. Перечисление может содержать абстрактные методы, но тогда все константы должны иметь тело класса, в котором обязательно должны реализовать все абстрактные методы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
enum Monster { GOBLIN { void doSomething() { System.out.println("Do something."); } public void someEnumMethod() { // реализация 1. } }, HOBGOBLIN(110, 30) { void doOtherThing() { System.out.println("Do other thing"); } public void someEnumMethod() { // реализация 2. } }, GREMLIN(200, 10) { public void someEnumMethod() { // реализация. } }; private int health; private int magic; Monster() { } Monster(int health, int magic) { this.health = health; this.magic = magic; } // Абстрактный метод public abstract void someEnumMethod(); } |
Перечисление не может содержать метод-финализатор finalize() , иначе возникнет ошибка компиляции.
Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 числа».
Предыдущая статья — «Java 8 наследование».
После прочтения статьи, я не понял, в чем преимущество перечислений перед обычным статическим массивом/объектом констант, хранящимся в каком-нибудь классе (как я это делал в ActionScript 3).
=
Нашел ответ на сторонних ресурсах.
https://habrahabr.ru/post/101280/
Пишут, что благодаря перечислениями можно обойтись без SWITCH.
=
И вот после этого я осознал всё преимущество перечислений
:-{ )
Почему когда я пишу
Direction playerDirection = Direction.NONE;
Программа пишет ошибку у Direction?