Привет! Представь, что тебе поставили задачу: создать класс, реализующий дни недели. Как использовать класс Enum - 1На первый взгляд, ничего сложного в этом нет, и твой код будет выглядеть примерно так:
public class DayOfWeek {

   private String title;

   public DayOfWeek(String title) {
       this.title = title;
   }

   public static void main(String[] args) {
       DayOfWeek dayOfWeek = new DayOfWeek("Суббота");
       System.out.println(dayOfWeek);
   }

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\'' +
               '}';
   }
}
И вроде бы все хорошо, но есть одна проблема: в конструктор класса DayOfWeek можно передать любой текст. Таким образом, кто-то сможет создать день недели «Лягушка», «Облачко» или «azaza322». Это явно не то поведение, которое мы ожидаем, ведь реальных дней недели существует всего 7, и у каждого из них есть название. Поэтому наша задача — как-то ограничить круг возможных значений для класса «день недели». До появления Java 1.5 разработчики были вынуждены самостоятельно придумывать решение этой проблемы, поскольку готового решения в самом языке не существовало. В те времена, если ситуация требовала ограниченного числа значений, делали так:
public class DayOfWeek {

   private String title;

   private DayOfWeek(String title) {
       this.title = title;
   }

   public static DayOfWeek SUNDAY = new DayOfWeek("Воскресенье");
   public static DayOfWeek MONDAY = new DayOfWeek("Понедельник");
   public static DayOfWeek TUESDAY = new DayOfWeek("Вторник");
   public static DayOfWeek WEDNESDAY = new DayOfWeek("Среда");
   public static DayOfWeek THURSDAY = new DayOfWeek("Четверг");
   public static DayOfWeek FRIDAY = new DayOfWeek("Пятница");
   public static DayOfWeek SATURDAY = new DayOfWeek("Суббота");

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\'' +
               '}';
   }
}
На что тут стоит обратить внимание:
  • Приватный конструктор. Если конструктор помечен модификатором private, объект класса нельзя создать с помощью этого конструктора. А поскольку в этом классе конструктор всего один, объект DayOfWeek нельзя создать вообще.

    public class Main {
    
       		public static void main(String[] args) {
    
           			DayOfWeek sunday = new DayOfWeek();//ошибка!
       		}
    }
  • При этом в классе содержалось нужное количество public static объектов, которые были инициализированы нужным нам образом (названия дней правильные).

    Это позволяло использовать объекты в других классах.

    public class Man {
    
       		public static void main(String[] args) {
    
           			DayOfWeek sunday = DayOfWeek.SUNDAY;
    
           			System.out.println(sunday);
      		 }
    }

    Вывод:

    DayOfWeek{title='Воскресенье'}

Такой подход во многом позволял решить задачу. В нашем распоряжении были 7 дней недели, и при этом никто не мог создать новые. Это решение предложил Джошуа Блох в книге «Effective Java». Книга, кстати, очень крутая и обязательна к прочтению для любого Java-разработчика.
Как использовать класс Enum - 2
С выходом Java 1.5 в языке появилось готовое решение для таких ситуаций — перечисление (Enum). Enum — тоже класс. Но он специально «заточен» на решение задач, похожих на нашу: создание некоторого ограниченного круга значений. Поскольку у создателей Java уже были готовые примеры (скажем, язык С, в котором Enum уже существовал), они смогли создать оптимальный вариант. Итак, что же из себя представляет Enum в Java? Давай посмотрим на примере того же DayOfWeek:
public enum DayOfWeek {

   SUNDAY,
   MONDAY,
   TUESDAY,
   WEDNESDAY,
   THURSDAY,
   FRIDAY,
   SATURDAY
}
Выглядит уже намного проще :) Внутри нашего Enum находятся 7 констант со статическим доступом. Мы уже можем его использовать для реализации логики в программе. Например, напишем программу, которая будет определять, нужно ли школьнику сегодня идти на учебу. У нашего школьника будет свой режим дня, обозначенный классом ScholarSchedule:
public class ScholarSchedule {

   private DayOfWeek dayOfWeek;
   //...другие поля


   public DayOfWeek getDayOfWeek() {
       return dayOfWeek;
   }

   public void setDayOfWeek(DayOfWeek dayOfWeek) {
       this.dayOfWeek = dayOfWeek;
   }
}
Переменная dayOfWeek в режиме дня определяет, какой сегодня день. А вот класс нашего школьника:
public class Scholar {

   private ScholarSchedule schedule;
   private boolean goToSchool;

   public void wakeUp() {

       if (this.schedule.getDayOfWeek() == DayOfWeek.SUNDAY) {
           System.out.println("Ура, можно поспать еще!");
       } else {
           System.out.println("Блин, опять в школу:(");
       }
   }
}
В методе wakeUp() при помощи Enum определяем дальнейшие действия школьника. Мы даже не описывали подробно, что значит каждая переменная в DayOfWeek, да это и не нужно: механизм дней недели и так очевиден, и если мы будем его использовать в текущем виде, любому разработчику будет понятно, что происходит в твоем коде. Еще один пример удобства Enum: его константы можно использовать с оператором switch. Например, мы пишем программу для строгой диеты, в которой блюда расписаны по дням:
public class VeryStrictDiet {

   public void takeLunch(DayOfWeek dayOfWeek) {

       switch (dayOfWeek) {

           case SUNDAY:
               System.out.println("Воскресный обед! Сегодня можно даже немного сладкого");
           case MONDAY:
               System.out.println("Обед для понедельника: куриная лапша!");
           case TUESDAY:
               System.out.println("Вторник, сегодня суп из сельдерея :(");
               //...и так далее до конца
       }
   }
}
Это одно из преимуществ Enum перед старым решением, которое применялось до Java 1.5: старое решение нельзя было использовать со switch. Что еще нужно знать об Enum? Enum — это настоящий класс со всеми вытекающими из этого возможностями. Например, если текущей реализации дней недели тебе недостаточно, ты можешь добавить в DayOfWeek переменные, конструкторы и методы:
public enum DayOfWeek {

   SUNDAY ("Воскресенье"),
   MONDAY ("Понедельник"),
   TUESDAY ("Вторник"),
   WEDNESDAY ("Среда"),
   THURSDAY ("Четверг"),
   FRIDAY ("Пятница"),
   SATURDAY ("Суббота");

   private String title;

   DayOfWeek(String title) {
       this.title = title;
   }

   public String getTitle() {
       return title;
   }

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\'' +
               '}';
   }
}
Теперь у констант нашего Enum есть поле title, геттер и переопределенный метод toString. По сравнению с обычными классами, на Enum наложили одно серьезное ограничение — от него невозможно наследоваться. Кроме того, у перечислений есть характерные только для них методы:
  • values(): возвращает массив из всех хранящихся в Enum значений:

    public static void main(String[] args) {
       		System.out.println(Arrays.toString(DayOfWeek.values()));
    }

    Вывод:

    [DayOfWeek{title='Воскресенье'}, DayOfWeek{title='Понедельник'}, DayOfWeek{title='Вторник'}, DayOfWeek{title='Среда'}, DayOfWeek{title='Четверг'}, DayOfWeek{title='Пятница'}, DayOfWeek{title='Суббота'}]

  • ordinal(): возвращает порядковый номер константы. Отсчет начинается с нуля:

    public static void main(String[] args) {
    
       		int sundayIndex = DayOfWeek.SUNDAY.ordinal();
       		System.out.println(sundayIndex);
    }

    Вывод:

    0

  • valueOf(): возвращает объект Enum, соответствующий переданному имени:

    public static void main(String[] args) {
       DayOfWeek sunday = DayOfWeek.valueOf("SUNDAY");
       System.out.println(sunday);
    }

    Вывод:

    DayOfWeek{title='Воскресенье'}

Обрати внимание: мы указываем названия элементов Enum прописными буквами, поскольку это константы, а для них предусмотрена именно такая запись, а не camelCase. English version of this post: Java Enum class on CodeGym