Перечисления в Java: Полное руководство по enum
- Что такое перечисления?
- Использование в операторе switch
- Класс java.lang.Enum
- Возможности перечисления
- Объявление перечислений
- Переопределение методов
- Перечисления и интерфейсы
1. Что такое перечисления?
В Java 5 были введены перечисления, которые создаются с использованием ключевого слова enum. Перечисления указывают возможные значения для какого-то явления. Например, вы открыли кофейню, в которой продаются три возможные варианты кофе - BIG
, HUGE
и OVERWHELMING
. Других вариантов быть не может. Если задавать значения с помощью String, можно выбрать любое другое значение, например - MIDDLE
, SMALL
. Задавая перечисления, вы ограничиваете возможные варианты:
public enum CoffeeSize {
BIG, HUGE, OVERWHELMING
}
В простейшей форме перечисления - это список именованных констант. Каждая константа перечисления (BIG
, HUGE
и OVERWHELMING
) является объектом класса, в котором она определена. Константы перечисления являются static final
и не могут быть изменены после создания.
Перечисления можно представить в виде класса, содержащего константы, например:
public class CoffeeSize5 {
public static final String BIG = "BIG";
public static final String HUGE = "HUGE";
public static final String OVERWHELMING = "OVERWHELMING";
}
Но у перечислений гораздо больше преимуществ по сравнению с таким классом. Какие - рассмотрим чуть позже.
new
. Переменная перечисления объявляется и применяется практически так же, как и переменные примитивных типов:public class CoffeeSizeExample1 {
public static void main(String[] args) {
CoffeeSize coffeeSize = CoffeeSize.BIG;
if (coffeeSize == CoffeeSize.BIG) {
System.out.println(coffeeSize);
}
}
}
2. Использование в операторе switch
Значения перечислимого типа можно также использовать в управляющем операторе switch. В выражениях ветвей case
должны использоваться константы из того же самого перечисления, что и в самом операторе switch
. В выражениях ветвей case
имена констант указываются без уточнения имени их перечислимого типа. Тип перечисления в операторе switch
уже неявно задает тип enum
для операторов case
.
public class CoffeeSizeExample2 {
public static void main(String[] args) {
CoffeeSize coffeeSize = CoffeeSize.BIG;
switch (coffeeSize) {
case BIG:
System.out.println("Дайте мне большую чашку кофе!");
break;
case HUGE:
System.out.println("Дайте мне огромную чашку кофе!");
break;
case OVERWHELMING:
System.out.println("Дайте мне громадную чашку кофе!");
break;
default:
System.out.println("Чашка не выбрана.");
}
}
}
3. Класс java.lang.Enum
Перечисление в Java относится к типу класса, но перечисление НЕ может наследоваться от другого класса и НЕ может быть супер классом.
Все перечисления автоматически наследуют от класса java.lang.Enum. В этом классе определяется ряд методов, доступных для использования во всех перечислениях: ordinal(), compareTo(), equals(), values() и valueOf().
Перечисления также неявно наследуют интерфейсы Serializable и Comparable.
Рассмотрим методы класса java.lang.Enum
.
3.1. Метод values()
Метод values()
возвращает массив, содержащий список констант перечислимого типа:
public class CoffeeSizeValuesExample {
public static void main(String[] args) {
System.out.println("Константы перечислимого типа CoffeeSize:");
CoffeeSize[] coffeeSizes = CoffeeSize.values();
for (CoffeeSize c : coffeeSizes) {
System.out.println(c);
}
}
}
Результат выполнения:
Константы перечислимого типа CoffeeSize:
BIG
HUGE
OVERWHELMING
3.2. Метод valueOf()
Статический метод valueOf()
возвращает константу перечислимого типа, значение которой соответствует символьной строке, переданной в качестве аргумента. Можно сказать, что этот метод преобразует значение String
в перечисление:
public class CoffeeSizeExample3 {
public static void main(String[] args) {
CoffeeSize coffeeSize = CoffeeSize.valueOf("BIG");
System.out.println("Переменная coffeeSize содержит " + coffeeSize);
}
}
3.3. Метод ordinal()
Вызвав метод ordinal()
, можно получить значение, которое обозначает позицию константы в списке констант перечислимого типа. Порядковые значения начинаются с нуля:
public class CoffeeSizeExample4 {
public static void main(String[] args) {
for (CoffeeSize c : CoffeeSize.values()) {
System.out.println(c + " " + c.ordinal());
}
}
}
3.4. Метод compareTo()
С помощью метода int compareTo(типПеречисления e)
можно сравнить порядковые значения двух констант одного и того же перечислимого типа. Метод возвращает значение типа int
.
Если порядковое значение вызывающей константы меньше, чем у константы е
(this < e
), то метод compareTo()
возвращает отрицательное значение.
Если порядковые значения обеих констант одинаковы (this == e
), возвращается нуль.
Если порядковое значение вызывающей константы больше, чем у константы е
(this > e
), то возвращается положительное значение.
public class CoffeeSizeCompareTo {
public static void main(String[] args) {
CoffeeSize bigCup = CoffeeSize.BIG;
CoffeeSize hugeCup = CoffeeSize.HUGE;
CoffeeSize anotherBigCup = CoffeeSize.BIG;
CoffeeSize overwhelmingCup = CoffeeSize.OVERWHELMING;
System.out.println("bigCup.compareTo(hugeCup): " + bigCup.compareTo(hugeCup));
System.out.println("hugeCup.compareTo(bigCup): " + hugeCup.compareTo(bigCup));
System.out.println("bigCup.compareTo(anotherBigCup): " + bigCup.compareTo(anotherBigCup));
System.out.println("bigCup.compareTo(overwhelmingCup): " + bigCup.compareTo(overwhelmingCup));
}
}
Результат выполнения кода:
bigCup.compareTo(hugeCup): -1
hugeCup.compareTo(bigCup): 1
bigCup.compareTo(anotherBigCup): 0
bigCup.compareTo(overwhelmingCup): -2
3.5. Метод equals()
Вызвав метод equals(), переопределяющий аналогичный метод из класса Object, можно сравнить на равенство константу перечисления с любым другим объектом. Но оба эти объекты будут равны только в том случае, если они ссылаются на одну и ту же константу из одного и того же перечисления. Простое совпадение порядковых значений не вынудит метод equals()
возвратить логическое значение true
, если две константы относятся к разным перечислениям.
При сравнении констант перечислений, можно использовать оператор "==
" - он будет работать так же, как и метод equals()
.
public class CoffeeSizeEquals {
public static void main(String[] args) {
CoffeeSize bigCup = CoffeeSize.BIG;
CoffeeSize hugeCup = CoffeeSize.HUGE;
CoffeeSize anotherBigCup = CoffeeSize.BIG;
System.out.println("bigCup.equals(hugeCup): " + bigCup.equals(hugeCup));
System.out.println("bigCup.equals(anotherBigCup): " + bigCup.equals(anotherBigCup));
System.out.println("bigCup == anotherBigCup: " + (bigCup == anotherBigCup));
}
}
4. Возможности перечисления
Создать экземпляр перечисления с помощью оператора new нельзя, но в остальном перечисление обладает всеми возможностями, которые имеются у других классов. А именно - в перечисления можно добавлять конструкторы, переменные и методы. Конструкторы перечисления являются private
по умолчанию.
Допустим мы хотим задать размер нашей чашки кофе в миллилитрах. Для этого введем переменную ml
в перечисление и геттер метод getMl()
. Добавим конструктор, на вход которого будем задавать значение для миллилитров.
Обратите внимание, что при объявлении конструктора не указан модификатор доступа - он private
по умолчанию. Уже говорилось, что нельзя создавать объекты перечисления используя оператор new
. Как же тогда вызвать наш конструктор? Для вызова конструктора перечисления после указания константы ставятся круглые скобки, в которых передается нужное значение.
public enum CoffeeSize2 {
// 100, 150 и 200 передаются в конструктор
BIG(100), HUGE(150), OVERWHELMING(200);
private int ml;
CoffeeSize2(int ml) {
this.ml = ml;
}
public int getMl() {
return ml;
}
}
Методы для перечисления вызываются так же, как и для обычного объекта. В следующем классе мы перебираем все константы нашего перечисления и для каждого вызываем метод getMl()
:
public class CoffeeSizeMlExample {
public static void main(String[] args) {
for (CoffeeSize2 coffeeSize : CoffeeSize2.values()) {
System.out.println(coffeeSize + " " + coffeeSize.getMl());
}
}
}
Конструкторы в перечислении могут быть перегружены, как показано в следующем примере. Для вызова конструктора без параметров просто не пишите скобки после константы:
public enum CoffeeSize3 {
BIG(100), HUGE, OVERWHELMING(200);
private int ml;
CoffeeSize3(int ml) {
this.ml = ml;
}
CoffeeSize3() {
this.ml = -1;
}
public int getMl() {
return ml;
}
}
5. Объявление перечислений
Перечисления могут быть объявлены: отдельным классом или как член класса. Но НЕ могут быть объявлены внутри метода.
В этом пример перечисление CoffeeSize
объявлено внутри класса Coffee3
:
public class Coffee3 {
enum CoffeeSize { BIG, HUGE, OVERWHELMING }
CoffeeSize size;
}
Для обращения к такому перечислению необходимо использовать имя внешнего класс:
public class CoffeeTest2 {
public static void main(String[] args) {
Coffee3 drink = new Coffee3();
drink.size = Coffee3.CoffeeSize.BIG; // имя внешнего класса необходимо
}
}
public class CoffeeTest3 {
public static void main(String[] args) {
// Неправильно! Нельзя объявлять перечисления внутри метода!
/*enum CoffeeSize {BIG, HUGE, OVERWHELMING}
Coffee drink = new Coffee();
drink.size = CoffeeSize.BIG;*/
}
}
6. Переопределение методов
Для перечислений можно переопределять методы, но это не совсем обычное переопределение.
Добавим в наше перечисление метод getLid()
, который возвращает код крышки для чашки кофе. Для всех констант подходит код B
, который возвращает этот метод, кроме константы OVERWHELMING
. Для OVERWHELMING
чашки нужен код A
. Переопределим метод getLid()
для этой константы. Как это делается? После объявления константы открываем фигурные скобки, в которых и переопределяем этот метод. Если необходимо переопределить несколько методов, это делается в этих же фигурных скобках.
public enum CoffeeSize4 {
BIG(100),
HUGE(150),
OVERWHELMING(200) {
@Override
public String getLidCode() {
return "A";
}
};
private int ml;
CoffeeSize4(int ml) {
this.ml = ml;
}
public int getMl() {
return ml;
}
public String getLidCode() {
return "B";
}
}
public class CoffeeSizeExample7 {
public static void main(String[] args) {
for (CoffeeSize4 coffeeSize : CoffeeSize4.values()) {
System.out.println(coffeeSize + " " + coffeeSize.getLidCode());
}
}
}
Результат выполнения кода:
BIG B
HUGE B
OVERWHELMING A
7. Перечисления и интерфейсы
Перечисления не могут наследовать другие классы, но могут реализовывать интерфейсы. Например, следующее перечисление реализует интерфейс Runnable:
public enum Currency implements Runnable {
PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
private int value;
Currency(int value) {
this.value = value;
}
@Override
public void run() {
System.out.println("Перечисления в Java могут реализовывать интерфейсы");
}
}
Курс 'Java для начинающих' на Udemy
Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.