Enum java что это
Кроме отдельных примитивных типов данных и классов в Java есть такой тип как enum или перечисление. Перечисления представляют набор логически связанных констант. Объявление перечисления происходит с помощью оператора enum, после которого идет название перечисления. Затем идет список элементов перечисления через запятую:
enum Day
Перечисление фактически представляет новый тип, поэтому мы можем определить переменную данного типа и использовать ее:
public class Program < public static void main(String[] args) < Day current = Day.MONDAY; System.out.println(current); // MONDAY >> enum Day
Перечисления могут использоваться в классах для хранения данных:
public class Program < public static void main(String[] args) < Book b1 = new Book("War and Peace", "L. Tolstoy", Type.BELLETRE); System.out.printf("Book '%s' has a type %s", b1.name, b1.bookType); switch(b1.bookType)< case BELLETRE: System.out.println("Belletre"); break; case SCIENCE: System.out.println("Science"); break; case SCIENCE_FICTION: System.out.println("Science fiction"); break; case PHANTASY: System.out.println("Phantasy"); break; >> > class Book < String name; Type bookType; String author; Book(String name, String author, Type type)< bookType = type; this.name = name; this.author = author; >> enum Type
Само перечисление объявлено вне класса, оно содержит четыре жанра книг. Класс Book кроме обычных переменных содержит также переменную типа нашего перечисления. В конструкторе мы ее также можем присвоить, как и обычные поля класса.
С помощью конструкции switch..case можно проверить принадлежность значения bookType определенной константе перечисления.
Методы перечислений
Каждое перечисление имеет статический метод values() . Он возвращает массив всех констант перечисления:
public class Program < public static void main(String[] args) < Type[] types = Type.values(); for (Type s : types) < System.out.println(s); >> > enum Type
Метод ordinal() возвращает порядковый номер определенной константы (нумерация начинается с 0):
System.out.println(Type.BELLETRE.ordinal()); // 1
Конструкторы, поля и методы перечисления
Перечисления, как и обычные классы, могут определять конструкторы, поля и методы. Например:
public class Program < public static void main(String[] args) < System.out.println(Color.RED.getCode()); // #FF0000 System.out.println(Color.GREEN.getCode()); // #00FF00 >> enum Color < RED("#FF0000"), BLUE("#0000FF"), GREEN("#00FF00"); private String code; Color(String code)< this.code = code; >public String getCode() < return code;>>
Перечисление Color определяет приватное поле code для хранения кода цвета, а с помощью метода getCode оно возвращается. Через конструктор передается для него значение. Следует отметить, что конструктор по умолчанию приватный, то есть имеет модификатор private. Любой другой модификатор будет считаться ошибкой. Поэтому создать константы перечисления с помощью конструктора мы можем только внутри перечисления.
Также можно определять методы для отдельных констант:
public class Program < public static void main(String[] args) < Operation op = Operation.SUM; System.out.println(op.action(10, 4)); // 14 op = Operation.MULTIPLY; System.out.println(op.action(6, 4)); // 24 >> enum Operation < SUM< public int action(int x, int y)< return x + y;>>, SUBTRACT < public int action(int x, int y)< return x - y;>>, MULTIPLY < public int action(int x, int y)< return x * y;>>; public abstract int action(int x, int y); >
Что такое enum?
enum – тип-перечисление. Бывает много разных формулировок вопроса, все они сводятся к разговору о перечислениях вообще. Технически это финальный класс со статическими финальными полями-экземплярами. enum Foo всегда неявно наследуется от Enum – то есть перечислением нельзя расширить другой класс, но всё еще можно реализовать интерфейсы. Из-за generic-параметра разные перечисления не имеют общего предка кроме Object .
Является Comparable (сравнивается позиция по порядку объявления значений) и Serializable (сериализуется только имя константы).
Имеет только заранее заданный набор значений. Значения неявно public static final и это нельзя переопределить. Для инициализации констант действуют все правила статической инициализации.
Копии элементов перечисления не создаются даже при десериализации. Вот почему Effective Java предлагает использовать для сериализуемого синглтона enum .
Экземпляры хранят свойства name и ordinal – имя и порядковый номер константы. Статический метод values вернет список всех констант, valueOf – константу по имени. Спецификация.
Финализация и клонирование перечислений запрещены.
Перечисления enum
В простейшей форме перечисление — это список именованных констант. Но в Java перечисления имеют более сложный функционал, чем в других языках программирования. Они могут иметь конструкторы, методы и переменные экземпляра.
Перечисления создаются с использованием ключевого слова enum. Создадим перечисление семейства кошачьих:
enum Cat
Идентификаторы в фигурных скобках называются константами перечисления. Каждый из них явно объявлен как открытый статический финальный член класса Cat. Объявив перечисление, вы можете создавать переменные этого типа. Но делать это нужно без оператора new, а в упрощенном виде. Объявим переменную manul перечислимого типа Cat.
Cat manul;
Вы можете присвоить переменной только те значения, которые определены в перечислении, например:
manul = Cat.Manul;
Обратите внимание, что во время присваивания вы указываете и тип Cat.
Использование перечисляемых переменных позволят избежать ошибок. Например, мы хотим использовать только числа 1, 2, 3 и такой способ не позволит использовать числа 0, 5, 9 и т.д.
Перечислимые константы можно проверить на равенство:
if (manul == Cat.Manul)
Также их можно применять в конструкции switch, где у операторов case используются константы из перечисления enum. При этом имена констант используются без имени типа перечисления.
enum Cat < Leopard, Puma, Lion, Tiger, Manul >public void onClick(View v) < Cat cat; cat = Cat.Manul; String result = ""; switch (cat) < case Leopard: result = "Я леопард"; break; case Puma: result = "Я пума"; break; case Lion: result = "Я царь зверей"; break; case Tiger: result = "Я тигра"; break; case Manul: result = "Погладь кота, . "; break; >textViewInfo.setText(result); >
Метод values()
Автоматически предопределённый метод для перечисления values() возвращает массив, содержащий список констант перечисления.
enum Cat < Leopard, Puma, Lion, Tiger, Manul >public void onClick(View v) < Cat[] allcats = Cat.values(); for(Cat cat : allcats) < System.out.println(cat); >>
Для примера использовалась дополнительная переменная allcats, которой присваивается ссылка на массив перечислимых значений. Можно обойтись без дополнительной переменной.
for(Cat cat : Cat.values())
Метод valueOf(String string)
Автоматически предопределённый метод для перечисления valueOf() возвращает константу перечисления, значение которой соответствует строке, переданной в параметре.
enum Cat < Leopard, Puma, Lion, Tiger, Manul >public void onClick(View v)
Так как перечисление в Java — это тип класса, то вы можете использовать конструкторы, добавлять переменных экземпляров, методы и интерфейсы. Следует сказать, что в Android сначала не рекомендовалось использовать перечисления из-за большого потребления памяти. Сейчас вроде это ограничение сняли, но тем не менее пока перечисления не так широко используются в приложениях для мобильных устройств, поэтому подробно разбирать все возможности перечисления не будем.
Метод ordinal()
У перечислений есть несколько удобных методов. Например, вы можете получить значение, которое указывает позицию константы в списке констант перечисления (порядковое значение или ordinal value), с помощью метода ordinal(). Порядковые значения начинаются с нуля.
for(Cat cat : Cat.values())
Методы compareTo() и equals()
Также можно сравнивать порядковые значения констант одного и того же перечисления с помощью метода compareTo(). Или сравнить на эквивалентность через метод equals().
Увлекаться не стоит из-за большого потребления памяти. Сравним.
// занимает 1112 байт public static enum Things < THING_1, THING_2 >; // другой вариант, занимает 128 байт public static int THING_1 = 0; public static int THING_2 = 1;
По этой причине на сегодняшний день в Android рекомендуется избегать enum. Хотя в последнее время я встречал использование перечислений в исходных кодах Android.
Перечисления (enums)
Иногда нужно описать ограниченное множество элементов. Встарь это делали посредством целочисленных констант:
public final class HairColourInt < // не позволим никому создавать экземпляры private HairColourInt() <>public static final int BLONDE = 0; public static final int FAIR = 1; public static final int RED = 2; public static final int BROWN = 3; public static final int BLACK = 4; >
Минусов у такого подхода несколько:
- Можно, добавляя в новую константу, по ошибке использовать старое числовое значение, например, добавить GREEN = 4 , в то время как BLACK тоже = 4 .
- int приводится к строке как число, это неудобно для отладки.
- В метод, который ожидает на вход значение такой константы, можно передать произвольное число. Например, здесь мы используем числа от нуля до четырёх, но можно передать хоть -1 , хоть 2_000_000_000 .
Enum
enum — это вид класса. У него есть ограниченный набор элементов, и все они доступны статически.
Другие названия: enumerated type, перечисляемый тип, перечисление.
public enum HairColour
Если объявить метод, скажем, findPersonWith(HairColour colour) , то все значения, которые можно передать в метод, ограничиваются следующими: BLONDE , FAIR , RED , BROWN , BLACK и null .
Person redhead = findPersonWith(HairColour.RED);
Стандартные методы enum’ов
Все enum’ы являются наследниками класса java.lang.Enum и обладают следующими instance-методами:
name() Имя константы. HairColour.BROWN.name() == «BROWN» ordinal() Порядковый номер. HairColor.BLONDE.ordinal() == 0
Также компилятор генерирует для каждого enum-класса следующие статические методы:
valueOf(String name) Находит константу по имени. HairColour.valueOf(«BROWN») == HairColour.BROWN; HairColour.valueOf(«YELLOW») бросит IllegalArgumentException, т. к. константы с таким именем нет values() Массив допустимых значений. HairColor.values() == [BLONDE, FAIR, RED, BROWN, BLACK]
Стоит учитывать, что, т. к. в Java массивы изменяемы, метод values() каждый раз возвращает новую копию массива (производит защитное копирование). Подробнее об экономии памяти в этой ситуации — в статье «Enum в Java. Маленькая недоработка».
Добавление собственных полей и методов
Очень часто нужно добавить какую-нибудь информацию к элементам enum’а. Это можно сделать так:
public enum HairColour < // Пусть у каждого цвета волос // будет степень яркости. BLONDE(1), FAIR(.8f), RED(.7f), BROWN(.4f), BLACK(0); // Поле для хранения данных. // Должно быть финальным: // недопустимо, чтобы у элемента перечисления // было состояние, т. к. он — константа. private final float brightness; // Конструктор. Он приватный, // изменить это нельзя. HairColour(float brightness) < this.brightness = brightness; >// геттер для поля public float getBrightness() < return brightness; >// Метод для поиска цвета // по уровню яркости. public static HairColour withBrightness(float brightness) < // обходим все возможные значения for (HairColour colour : values()) < // если у очередного цвета // подходящий уровень яркости — возвращаем if (colour.brightness == brightness) < return colour; >> // если нужный цвет не найден — // выбрасываем исключение throw new NoSuchElementException( "There's no HairColour with brightness " + brightness); > >
В этом примере HairColour.RED.getBrightness() == .7f , HairColour.withBrightness(0) == HairColour.BLACK , а HairColour.withBrightness(.003f) бросит исключение NoSuchElementException .
Реализация интерфейсов
Enum’ы могут реализовывать интерфейсы.
public enum HairColour implements Runnable < . @Override public void run() < System.out.println("person with " + name().toLowerCase() + " hair runs"); >>
HairColour.FAIR.run() выведет person with fair hair runs .
Собственные методы элементов enum’а
Отдельные элементы перечисления могут быть анонимными классами и иметь собственные методы. Например:
public enum HairColour implements Runnable < BLONDE(1), FAIR(.8f), RED(.7f) < // тело анонимного класса @Override public boolean hasSoul() < return false; >>, BROWN(.4f), BLACK(0); . public boolean hasSoul() < return true; >>
Таким образом, enum — это не просто набор констант, это почти полноценный класс и очень мощный инструмент.