1. История на enumвъзникването

Днес ще изследваме друг вид тип данни в Java: enum. Името enumидва от думата изброяване . Какъв е този тип данни и за Howво е?

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

Например един DayOfTheWeekтип може да приема само стойностите MONDAY, TUESDAY, WEDNESDAY, ... Има общо 7 стойности. Или един Monthтип може да приема само стойностите JANUARY, FEBRUARY, MARCH, ... Има общо 12 стойности.

Разбира се, можете да използвате числа ( intтипа): 1— понеделник, 2— вторник и т.н. Но някой може случайно да присвои невалидни стойности като 8or 0на вашата променлива.

Лесно може да имате ситуация, в която един програмист смята, че дните от седмицата (or месеците от годината) са номерирани, започвайки от нула, докато други очакват тяхното номериране да започва от едно и т.н.

Ето защо Java въведе enumтип данни, който се състои от краен набор от стойности .


2. Деклариране на тип

Декларирането на нов enumтип данни изглежда така:

enum TypeName
{
   VALUE1,
   VALUE2,
   VALUE3
}

Къде TypeNameе името на новия тип (клас), а възможните стойности са разделени със запетаи и опаковани във фигурни скоби: Value1, Value2, Value3.

Като пример, нека създадем наш собствен DayOfTheWeek enum:

Код Забележка
enum Day
{
   MONDAY,
   TUESDAY,
   WEDNESDAY,
   THURSDAY,
   FRIDAY,
   SATURDAY,
   SUNDAY
}
Нов Dayтип

понеделник
вторник
сряда
четвъртък
петък
събота
неделя

Ето How присвоявате стойност на променлива от нашия нов тип:

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. Преобразуване в клас

Всъщност тук няма нищо магическо. Компилаторът просто ни даде малко синтактична захар. По време на компилация Dayenum се преобразува в обикновен клас:

Код, опростена version Забележка
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клас

Списък със статични константи







Масив с всички стойности на Dayenum


Променлива, която съхранява стойността на конкретен Dayобект

Класът е частен, което означава, че обекти от Dayкласа могат да бъдат създадени само вътре в класа. Методът трябва да бъде извикан на обект. Връща стойността на обекта — полето. Методът връща статичен масив с всички стойности на класаconstructorDayDay



ordinalDay

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. Ще разгледаме How работят конструкторите малко по-късно.

Надяваме се, че вече е ясно защо присвояваме стойност на променлива по този начин:

Day day = Day.MONDAY;

MONDAYе просто статично поле (константа) в Dayкласа. Когато осъществявате достъп до статични методи и полета извън класа, трябва да посочите името на класа преди името на полето or метода.



5. Повече методи на anenum

Всеки enumклас има няколко интересни функции.

Преобразуване към и от низ

За да конвертирате enum обект в низ, трябва да извикате неговия toString()метод.

String str = Day.MONDAY.toString();

За да конвертирате в другата посока (от низ към Dayобект), можете да използвате статичния valueOf()метод:

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

Това е супер удобно и ще бъде полезно в много случаи.

Преобразуване в число и обратно

Вече знаете How да конвертирате 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обекта с различен address. Съществува само един екземпляр от всяка стойност на enum. И това означава, че сравняването на променливи enum с помощта на == винаги ще работи.



6. Добавяне на ваши собствени методи къмenum

Тъй като един enumсе превръща в обикновен клас по време на компorране, можете да декларирате методи в него. Тези методи просто се добавят към класа, който компилаторът генерира. Да предположим например, че искаме Day enumда върнем списък от стойности на enum, а не масив.

Тогава можем да добавим следния code:

Код Забележка
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()метода.
Върнете списъка.

Сега този метод може да бъде извикан в code:

Код Забележка
List<Day> list = Day.asList();
Променливата listще съхранява списък с всички стойности на Day enum.