CodeGym /Java блог /Случаен /Enum. Практически примери. Добавяне на конструктори и мет...
John Squirrels
Ниво
San Francisco

Enum. Практически примери. Добавяне на конструктори и методи

Публикувано в групата
здрасти Днес ще говорим за един от специалните типове данни на Java: Enum(съкратено от „изброяване“). Какво го прави специален? Нека си представим Howво ни трябва, за да внедрим „месеци“ в една програма. Enum.  Практически примери.  Добавяне на конструктори и методи – 1 Не изглежда проблемно, нали? Просто трябва да определим Howви свойства има всеки месец. Може би първо се нуждаем от името на месеца и броя на дните в него. Решението изглежда доста просто:

public class Month {

   private String name;
   private int daysCount;

   public Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getDaysCount() {
       return daysCount;
   }

   public void setDaysCount(int daysCount) {
       this.daysCount = daysCount;
   }

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Целият шабанг! Имаме Monthклас, задължителните полета, getter/setter и toString(). Освен ако, разбира се, не трябва да добавим equals()иhashCode()за постигане на пълно щастие :) Но тук имаме концептуален проблем. Както вероятно си спомняте, едно от основните предимства на ООП е, че улеснява моделирането на обекти от реалния свят. Стол, кола, планета - всички тези концепции от обикновения живот лесно се представят в програма с помощта на абстракция. Проблемът е, че някои обекти от реалния свят имат строго ограничен диапазон от стойности. Има само 4 сезона в годината. Има само 8 ноти в една октава. Календарът има само 12 месеца. И Дани Оушън от 11 на Оушън има само 11 приятели (въпреки че това няма meaning :)) Това, което има meaning е, че един обикновен Java клас не е в състояние да моделира тези обекти и да наложи естествените им ограничения. НашитеMonthима всички задължителни полета. Но ако друг програмист го използва, никой не може да го спре да създава напълно безумни обекти:

public class Main {

   Month month1 = new Month("lolkek", 322);
   Month month2 = new Month("yahoooooooooooo", 12345);

}
Ако това се появи в нашия code, няма да е лесно да открием виновника! От една страна, програмистът, който създава обектите, може да осъзнае, че класът Monthозначава "месец в годината" и да не пише такива глупости. От друга страна, програмистът се възползва само от способностите, предоставени от дизайнера на класа. Възможно ли е да се задават произволни имена и номера на дните? Точно това получихме. Какво тогава да правим в тази ситуация? Честно казано, преди да бъде пусната Java 1.5, програмистите трябваше да бъдат креативни :) В онези дни те създаваха структури като тази:

public class Month {

   private String name;
   private int daysCount;

   private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public static Month JANUARY = new Month("January", 31);
   public static Month FEBRUARY = new Month("February", 28);
   public static Month MARCH = new Month("March", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Тук намалихме броя на месеците от дванадесет на три, за да направим примера по-кратък. Такива дизайни направиха възможно решаването на проблема. Възможността за създаване на обекти беше ограничена до частен конструктор:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Програмистите, използващи класа, не могат просто да създават Monthобекти. Те трябваше да използват окончателните статични обекти, предоставени от разработчика на класа. Например така:

public class Main {

   public static void main(String[] args) {

       Month january = Month.JANUARY;
       System.out.println(january);
   }

}
Но разработчиците на Java обърнаха внимание на съществуващия проблем. Разбира се, страхотно е, че програмистите успяха да измислят решение, използвайки инструментите, налични в езика, но не изглежда много лесно! Беше необходимо очевидно решение, дори за новаци. И така Enumсе появи в Java. По принцип Enumе Java клас, който предоставя ограничен набор от обектни стойности. Ето How изглежда:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
В дефиницията посочихме, че това Enumе Java клас, но наистина ли е вярно? Да, и дори можем да го проверим. Например, опитайте да накарате нашия Monthenum да наследи няHowъв друг клас:

public abstract class AbstractMonth {
}

// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
защо става така Когато пишем:

public enum Month
компилаторът преобразува този оператор в следния code:

public Class Month extends Enum
Както вече знаете, Java не поддържа множествено наследяване. Следователно не можем да наследим AbstractMonth. EnumКак може да се използва тази нова конструкция ? И How се различава от старата конструкция с static finalполета? Е, като пример, старата конструкция не ни позволяваше да използваме собствен набор от стойности в switchизявления. Представете си, че искаме да създадем програма, която да ни напомня за празниците, празнувани всеки месец:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Както можете да видите, компилаторът извежда грешка тук. Но след като enumсе появи в Java 1.5, всичко стана много по-просто:

public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {
          
           case JANUARY:
               System.out.println("New Year's Day is January 1st!");
               break;
           case FEBRUARY:
               System.out.println("Valentine's Day is February 14th!");
               break;
           case MARCH:
               System.out.println("Saint Patrick's Day is March 17th!");
               break;
       }
   }
}


public class Main {

   public static void main(String[] args) {

       HolidayReminder reminder = new HolidayReminder();
       reminder.printHolidays(Month.JANUARY);

   }

}
Конзолен изход:

New Year's Day is January 1st!
Имайте предвид, че достъпът до Enumобекти остава статичен, точно Howто беше преди Java 1.5. Не е необходимо да създаваме Monthобект за достъп до месеците. Когато работите с enum, е много важно да не забравяте, че това Enumе пълноценен клас. Това означава, че при необходимост можете да дефинирате конструктори и методи в него. Например в предишния codeов фрагмент ние просто посочихме стойностите: ЯНУАРИ, ФЕВРУАРИ, МАРТ. Въпреки това можем да разширим нашия Monthenum по следния начин:

public enum Month {

   JANUARY("January", 31),
   FEBRUARY("February", 28),
   MARCH("March", 31),
   APRIL("April", 30),
   MAY("May", 31),
   JUNE("June", 30),
   JULY("July", 31),
   AUGUST("August", 31),
   SEPTEMBER("September", 30),
   OCTOBER("October", 31),
   NOVEMBER("November", 30),
   DECEMBER("December", 31);

   private String name;
   private int daysCount;

   Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public static Month[] getWinterMonths() {

       return new Month[]{DECEMBER, JANUARY, FEBRUARY};
   }

   public static Month[] getSummerMonths() {

       return new Month[]{JUNE, JULY, AUGUST};
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getDaysCount() {
       return daysCount;
   }

   public void setDaysCount(int daysCount) {
       this.daysCount = daysCount;
   }

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Тук дадохме нашите enum2 полета (името на месеца и броя на дните), конструктор, който използва тези полета, getter/setter, метода toString()и 2 статични метода. Както можете да видите, нямаше проблеми с това. Отново, Enumнаистина е пълноценен клас:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

       System.out.println(Arrays.toString(Month.getSummerMonths()));

   }

}
Конзолен изход:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
И накрая, искам да препоръчам една изключително полезна книга за Java, а именно „Ефективна Java“ от Джошуа Блок . Enum.  Практически примери.  Добавяне на конструктори и методи – 3Authorът е един от създателите на Java, така че определено можете да се доверите на съветите му How правилно и компетентно да използвате инструментите на езика :) По отношение на нашия урок ви препоръчвам да обърнете специално внимание на главата на книгата за Enum. Приятно четене! :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION