Статьи

Основы типов Enum Java

Независимо от кода, над которым вы работаете, скорее всего, вам рано или поздно понадобится список констант, например, понедельник, вторник и т. Д. Для всех будних дней или январь, февраль и т. Д. Для всех месяцев. В Java есть типы enum , которые обычно называются только enum , что позволяет очень просто определить это. В этой статье я научу вас всему, что вам нужно знать, чтобы стать опытным пользователем перечислений Java.

Основы Enum

В простейшей форме перечисление Java — это просто фиксированное число констант, которые разработчик определяет при написании кода. (Например, он может определять все каналы SitePoint.) Подобно классу, перечисление определяет тип, который можно использовать практически везде, где могут использоваться классы и интерфейсы, например, для полей, переменных и параметров.

Перечисления могут на самом деле быть гораздо больше, чем просто константы, имеющие свои собственные атрибуты и методы, но я вернусь к этому позже. Видеть их как постоянные — хороший способ узнать их.

Определение перечисления

Перечисление определяется аналогично тому, как будет определен класс, но использует enum вместо ключевого слова class . Значения констант перечислены в теле перечисления (то есть в фигурных скобках). Хотя в этом нет необходимости, обычно пишут константы заглавными буквами, чтобы их было легче распознать.

Теперь, когда у нас есть описание для перечислений, пришло время для примера. Вот как выглядит перечисление, в котором перечислены некоторые каналы SitePoint:

 public enum SitePointChannel { JAVA, MOBILE, WEB, PHP, WORDPRESS, JAVASCRIPT, DESIGN } 

Элементы внутри перечисления SitePointChannel называются константами перечисления .

Назначение Enum

Как только перечисление определено, вы можете присвоить его значения переменным. Вот пример:

 private SitePointChannel channel; 

Поле channel имеет тип SitePointChannel , поэтому единственными значениями, которые могут быть ему назначены, являются значения, определенные этим перечислением. Как локальная переменная, которая может выглядеть следующим образом:

 SitePointChannel channel = SitePointChannel.JAVA; 

Использование Enum

Перечисления имеют множество функций в Java. Одна из их основных возможностей заключается в том, что их можно использовать для сравнения идентификаторов и операторов switch .

Сравнение идентичности с ==

Перечислительные константы можно сравнивать на тождественность, используя оператор отношения == . Вот пример условия if() , которое в этом случае всегда ложно.

 SitePointChannel channel = SitePointChannel.JAVA; if (channel == SitePointChannel.MOBILE) { System.out.println("..."); } 

Переключение операторов

Другая очень широко используемая особенность перечислений — способность управлять операторами switch . Вот пример, который печатает содержимое данного канала:

 SitePointChannel channel = ... // specify an enumeration constant switch (channel) { case JAVA: System.out.println("Java, web and desktop technologies"); break; case MOBILE: System.out.println("Mobile technologies"); break; case PHP: // as usual for switch, once a match was found, the execution // "falls through" to the next branch until it hits a break case WEB: case JAVASCRIPT: case WORDPRESS: System.out.println("Web technologies"); break; default: throw new IllegalArgumentException( "Unknown channel '" + channel + "'.") break; } 

В выражениях switch константы перечисления используются без имени типа перечисления. Это связано с тем, что тип enum неявно указан в выражении- switch . Рекомендуется перечислить все константы перечисления (даже если некоторые из них ничего не делают) и добавить ветку по умолчанию, обычно с исключением (в случае, если добавляется новая константа, а кто-то пропускает оператор switch и не обновляет Это.)

Перечисления для списка сонстант - светофоров, может быть?

Перечисления как класс

Рассмотрев основы перечислений Java, мы можем выйти за пределы интерпретации перечислений как фиксированного числа констант. Фактически, перечисления намного больше похожи на классы!

Они могут иметь поля и методы, а также реализовывать интерфейсы, и я объясню все это через минуту. Даже константы перечисления не такие уж особенные — они просто публичные, статические и конечные члены своего типа enum. Единственная причина, по которой нам не нужно ставить public static final заключается в том, что компилятор заполняет его для нас.

Основные отличия от обычных классов заключаются в том, что они не могут расширять другие классы (см. Ниже, почему) и не могут быть созданы с помощью new ключевого слова (для сохранения фиксированного числа констант).

Расширение java.lang.Enum

Все перечисления неявно расширяют java.lang.Enum . В Java класс может расширять только один родительский элемент, и поэтому перечисление не может расширять любой другой класс (но реализуют интерфейсы — см. Ниже).

Расширение Enum означает, что у каждого enum есть несколько методов, которые делают его более удобным:

  • статические values()
  • static valueOf(String)
  • name()
  • ordinal()
  • compareTo(Enum)

Enum ‘s values() Метод

Метод values() возвращает массив переменных типа enum, содержащий все константы перечисления. Вот пример:

 SitePointChannel[] channels = SitePointChannel.values(); for (SitePointChannel channel : channels) { System.out.println(channel + " Channel"); } 

И вывод:

 JAVA Channel MOBILE Channel WEB Channel PHP Channel WORDPRESS Channel JAVASCRIPT Channel DESIGN Channel 

Как видите, методы values() предоставляют хорошее решение для циклического перебора всех констант перечисления.

Метод valueOf(String) Enum

Метод valueOf(String) возвращает константу перечисления, значение которой соответствует переданной ей строке, или выдает исключение IllegalArgumentException если константа с указанным именем не найдена. Осторожно, строки, передаваемые в valueOf , чувствительны к регистру!

 // returns SitePointChannel.JAVA enum SitePointChannel.valueOf("JAVA"); // throws IllegalArgumentException SitePointChannel.valueOf("java"); 

Как указывалось ранее, все перечисления автоматически наследуют java.lang.Enum . Этот класс определяет несколько методов, доступных для всех перечислений.

Метод name()

Этот метод возвращает имя этой константы перечисления, в точности как объявлено в объявлении перечисления. Вот пример:

 SitePointChannel channel = SitePointChannel.JAVA; System.out.println(channel.name()); 

Результатом этого примера является String JAVA .

ordinal() метод

Этот метод используется для получения позиции константы перечисления в списке констант. Это называется порядковым значением. Вот пример:

 SitePointChannel channel = SitePointChannel.JAVA; System.out.println(channel.ordinal()); 

Выходные данные этого примера Sitepoint «0», поскольку JAVA является первой константой перечисления Sitepoint а начальной константе присваивается порядковый номер нуля. Следовательно, следующие выводы «3»:

 SitePointChannel channel = SitePointChannel.PHP; System.out.println(channel.ordinal()); 

Метод compareTo(Enum)

Этот метод используется для сравнения порядкового значения двух констант одного и того же перечисления. Этот метод возвращает отрицательное целое число, ноль или положительное целое число на основе порядковых позиций двух сравниваемых экземпляров.

Вот как это работает. Возьмем, к примеру, в качестве ссылочного экземпляра перечисления SitePointChannel.PHP .

 SitePointChannel channel = SitePointChannel.PHP; 

Конечно, если мы сравним экземпляр channel с SitePointChannel.PHP , метод compareTo() вернет значение 0.

 // returns 0 channel.compareTo(SitePointChannel.PHP); 

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

Например, если он сравнивается с SitePointChannel.JAVA , выходные данные метода compareTo() будут положительными, поскольку SitePointChannel.JAVA расположен перед ссылочным экземпляром:

 // actually returns 3 channel.compareTo(SitePointChannel.JAVA); 

Если ссылочный экземпляр enum сравнивается с экземплярами, которые идут после него в классе enum, он возвращает отрицательное значение. Например, сравнение его с SitePointChannel.JAVASCRIPT вернет значение -2.

 // returns -2 channel.compareTo(SitePointChannel.JAVASCRIPT); 

Перечисления с полями

Константы перечисления Java могут иметь поля, которым должно быть присвоено значение во время создания. Имейте в виду, что, как и в случае с обычным классом, каждая константа перечисления имеет свои собственные поля. Чтобы определить значения, включающий тип должен иметь конструктор, который принимает параметры. Как я упоминал ранее, каждая константа перечисления является объектом своего типа перечисления, поэтому для каждой из констант перечисления вызывается конструктор. Поля и конструкторы (а также методы) должны быть определены ниже списка констант.

Давайте рассмотрим пример для этой проблемы. Предположим, у нас есть перечисление SitePointChannel со списком каналов, и нам нужно добавить к каждому каналу количество опубликованных статей. Я объявлю поле для этого:

 public enum SitePointChannel { JAVA, MOBILE, WEB, PHP, WORDPRESS, JAVASCRIPT, DESIGN; private int numberOfArticles; } 

Пока все хорошо, но поле никогда не присваивается значение. Для этого нам также нужен конструктор:

 // DOES NOT COMPILE public enum SitePointChannel { // [...] list of constants as before private int numberOfArticles; Sitepoint(int numberOfArticles) { this.numberOfArticles = numberOfArticles; } } 

К сожалению, это не компилируется, потому что константы инициируются конструктором no-args, который больше не существует. Чтобы это исправить, мы вызываем новый конструктор:

 public enum SitePointChannel { JAVA(1344), MOBILE(2444), WEB(4311), PHP(5311), WORDPRESS(3221), JAVASCRIPT(3865), DESIGN(3492); // [...] field and constructor as before } 

Та же логика верна для переменных нескольких экземпляров и разных типов данных ( int , double , String ,…).

Перечисления с методами

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

Следующий пример демонстрирует полезность перечислений с методами. Ранее в этой статье я упоминал, что метод valueOf() чувствителен к регистру. Следующее решение даст альтернативное решение для метода valueOf() без ограничения чувствительности к регистру путем создания нашего собственного метода.

 public enum SitePointChannel { JAVA, MOBILE, WEB, PHP, WORDPRESS, JAVASCRIPT, DESING; public static SitePointChannel valueOfIgnoreCase(String channelName) { channelName = channelName.toUpperCase(); return valueOf(channelName); } } 

Чтобы убедиться, что это решение работает, запустите следующий фрагмент кода.

 if (SitePointChannel.valueOfIgnoreCase("jaVa") == SitePointChannel.JAVA){ System.out.println("Ignore case enum"); } 

Как видно из примера, valueOfIgnoreCase() принимает строку «jaVa» и возвращает перечисление JAVA . Это решение работает для любой комбинации символов верхнего и нижнего регистра строки, представляющей экземпляр перечисления SitePointChannel .

Реализация интерфейсов

Учитывая возможность иметь поля и методы, имеет смысл, что перечисления также могут реализовывать интерфейсы. Это работает точно так же, как и в обычных классах, поэтому об этом мало что можно сказать.

Вот простой пример:

 public interface Printable { void print(); } public enum SitePointChannel implements Printable { // [...] constants, field and constructor as before @Override public void print() { System.out.println("Channel " + name() + " has " + numberOfArticles + " articles."); } } 

Резюме

Вот и все, что касается основ Java перечислений. Мы видели, что они могут описывать фиксированное число констант и как могут использоваться методы Enum values() , valueOf(String) , name() , ordinal() и compareTo(Enum) . Но мы также обнаружили, что это полноценные классы, которые позволяют добавлять поля, создавать методы и реализовывать интерфейсы.