1. Передісторія появи enum

Сьогодні ми вивчимо ще один різновид типів даних у Java — enum. Назва enum походить від слова Enumeration — перелічування. Що ж це за тип даних і для чого він потрібен?

Часом у програміста виникає потреба в такому типі даних, значення якого обмежуються невеликим фіксованим списком.

Наприклад, тип ДеньТижня може набувати тільки значень ПОНЕДІЛОК, ВІВТОРОК, СЕРЕДА, ... — лише 7 значень. Або тип Місяць — він може набувати тільки значень СІЧЕНЬ, ЛЮТИЙ, БЕРЕЗЕНЬ, ... — лише 12 значень.

Можна, звичайно, використовувати числа (тип int): 1 — понеділок, 2 — вівторок і т. ін. Але хтось випадково може присвоїти такій змінній значення 8, або, скажімо, значення 0.

Може легко виникнути ситуація, коли один програміст вважає, що дні тижня (або місяці) нумеруються з нуля, інший — що з одиниці і т. д.

Тому в Java створили тип даних, який складається з обмеженого набору значеньenum.


2. Оголошення типу

Оголошення нового типу даних enum має такий вигляд:

enum Ім'яТипу
{
   ЗНАЧЕННЯ1,
   ЗНАЧЕННЯ2,
   ЗНАЧЕННЯ3
}

де Ім'яТипу — це ім'я нового типу (класу), а в дужках указано перелік можливих значень, розділених комами: Значення1, Значення2, Значення3.

Спробуймо для прикладу створити свій перелік enum для типу ДеньТижня:

Код Примітка
enum Day
{
   MONDAY,
   TUESDAY,
   WEDNESDAY,
   THURSDAY,
   FRIDAY,
   SATURDAY,
   SUNDAY
}
Новий тип Day

Понеділок
Вівторок
Середа
Четвер
П'ятниця
Субота
Неділя

Присвоювати значення змінним цього типу можна в такий спосіб:

Day day = Day.MONDAY;

Приклад:

Код Примітка
Day day = Day.FRIDAY;
System.out.println(day);
На екран буде виведено:
FRIDAY


3. Методи класу enum

Тип enum має кілька вбудованих методів, два з яких дуже цікаві:

Статичний метод values() повертає масив усіх значень переліку enum:

Код Примітка
Day[] days = Day.values();

for (Day day: days)
   System.out.println(day);







System.out.println(days[2]);
У змінній days зберігається масив значень типу Day (7 значень)

Виводимо вміст масиву на екран:
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

WEDNESDAY

Метод ordinal() повертає порядковий номер константи. Викликати його потрібно не для класу enum, а для значення enum:

Код Виведення на екран
System.out.println(Day.MONDAY.ordinal());
System.out.println(Day.FRIDAY.ordinal());
System.out.println(Day.SUNDAY.ordinal());
0
4
6


4. Перетворення на клас

Насправді магії тут немає — компілятор просто підсипав нам трохи синтаксичного цукру. Під час компіляції клас enum Day буде перетворено на звичайний клас:

Код, спрощена версія Примітка
public class Day
{
   public static final Day MONDAY = new Day(0);
   public static final Day TUESDAY = new Day(1);
   public static final Day WEDNESDAY = new Day(2);
   public static final Day THURSDAY = new Day(3);
   public static final Day FRIDAY = new Day(4);
   public static final Day SATURDAY = new Day(5);
   public static final Day SUNDAY = new Day(6);

    private static final Day[] array = {MONDAY, TUESDAY,
      WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

   private final int value;

   private Day (int value)
   {
      this.value = value;
   }

   public int ordinal()
   {
      return this.value;
   }

   public static Day[] values()
   {
      return array;
   }
}
Клас Day

Список статичних констант-значень







Масив з усіма значеннями типу Day


Змінна зі значенням певного об'єкта Day

private конструктор класу Day — об'єкти класу Day можна створювати тільки всередині класу Day.



Метод ordinal потрібно викликати для об'єкта Day.

Він повертає значення об'єкта — value.


Метод повертає статичний масив з усіма значеннями класу Day

Якщо видалити з класу Day усі статичні методи та змінні, отримаємо таку картину:

Код Примітка
public class Day
{
  private int value;

  private Day (int value)
  {
    this.value = value;
  }

  public int ordinal()
  {
    return this.value;
  }
}


Змінна value зберігає значення об'єкта Day

Об'єкти Day можна створювати тільки всередині класу Day — конструктор private.



Метод ordinal() повертає значення value об'єкта Day.

Тобто нічого страшного тут не відбувається. Компілятор створює клас Day, потім додає в нього константи, які були значеннями в enum, додає відсутні методи й робить конструктор класу private. Як працюють конструктори, ми розглянемо трохи згодом.

Тепер, сподіваємося, вам зрозуміло, чому ми присвоюємо значення змінній у такий спосіб:

Day day = Day.MONDAY;

MONDAY — це просто статичне поле (константа) класу Day. А під час звернення до статичних методів і полів поза межами класу перед іменем поля або методу потрібно вказувати ім'я класу.



5. Ще про методи класу enum

Усі enum-класи мають іще кілька цікавих особливостей.

Перетворення на рядок і зворотне перетворення

Щоб перетворити об'єкт типу enum на рядок, для цього об'єкта потрібно викликати метод toString().

String str = Day.MONDAY.toString();

Для зворотного перетворення (рядка на об'єкт Day) можна скористатися статичним методом valueOf():

Day day = Day.valueOf("MONDAY");

Дуже зручно й корисно в багатьох випадках.

Перетворення на число і зворотне перетворення

Як перетворити об'єкт типу enum на число, ви вже знаєте: для цього потрібно викликати метод ordinal():

int index = Day.MONDAY.ordinal();

Для зворотного перетворення (числа на об'єкт Day) потрібно скористатися дещо довшою конструкцією:

Day day = Day.values()[2];

Приклади:

Код Примітка
Day day = Day.MONDAY;
int index = day.ordinal();
Day newDay = Day.values()[index+2];
Понеділок
Отримуємо індекс понеділка (0)
День тижня через 2 дні після понеділка

Важливий момент: оскільки значення типу enum — це фіксований набір констант, їх можна порівнювати за допомогою оператора ==. Тому що не можуть існувати два однакових об'єкти MONDAY з різними посиланнями. Кожен об'єкт-значення типу enum існує тільки в одному примірнику. Тому порівняння змінних типу enum за допомогою оператора == завжди діятиме.



6. Додавання в enum власних методів

Оскільки під час компіляції enum перетворюється на звичайний клас, у ньому можна оголошувати методи: ці методи просто буде додано в клас, який згенерує компілятор. Наприклад, ми хочемо, щоб наш перелік Enum Day повертав не масив значень, а список.

Тоді в нього можна додати такий код:

Код Примітка
enum Day
{
   MONDAY,
   TUESDAY,
   WEDNESDAY,
   THURSDAY,
   FRIDAY,
   SATURDAY,
   SUNDAY;

   public static List<Day> asList()
   {
      ArrayList<Day> list = new ArrayList<Day>();

      Collections.addAll(list, values());

      return list;
   }

}








Після списку значень потрібно поставити крапку з комою.



Створюємо об'єкт ArrayList.

Додаємо в нього значення з масиву: його повертає метод values().
Повертаємо список.

Тепер цей метод можна викликати в коді:

Код Примітка
List<Day> list = Day.asList();
У змінній list буде збережено список усіх значень переліку enum Day.