JavaRush /Blog Java /Random-PL /Wyliczenie w Javie. Praktyczne przykłady. Dodawanie konst...

Wyliczenie w Javie. Praktyczne przykłady. Dodawanie konstruktorów i metod

Opublikowano w grupie Random-PL
Cześć! Dzisiaj porozmawiamy o specjalnym typie danych w Javie - Enum(skrót od wyliczenia). Jaka jest ich cecha? Wyobraźmy sobie, że musimy wdrożyć w programie miesiące. Wyliczenie.  Praktyczne przykłady.  Dodawanie konstruktorów i metod - 1Wydawałoby się, w czym jest problem? Musisz tylko określić, jakie właściwości ma dany miesiąc. Być może potrzebujemy przede wszystkim nazwy miesiąca i liczby w nim dni. Rozwiązanie problemu wygląda dość prosto:
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 +
               '}';
   }
}
Pełny zestaw, proszę! Mamy klasę Month, niezbędne pola, gettery-settery, toString(). Chyba, że equals()​​trzeba hashCode()to dodać do pełni szczęścia :) Mamy jednak problem koncepcyjny. Jak być może pamiętasz, jedną z głównych zalet OOP jest to, że ułatwia modelowanie obiektów ze świata rzeczywistego. Krzesło, samochód, planeta – wszystkie te koncepcje z życia codziennego można łatwo przedstawić w programie za pomocą abstrakcji. Problem w tym, że niektóre byty w świecie rzeczywistym mają ściśle ograniczony zakres znaczeń. W roku są tylko 4 pory roku. W muzyce jest tylko 7 nut. W kalendarzu jest tylko 12 miesięcy. Ocean ma tylko 11 przyjaciół (chociaż jest to dyskusyjne :)) Innymi słowy, zwykła klasa Java nie jest w stanie modelować tych bytów i szanować ich naturalnych ograniczeń. Nasza klasa Monthposiada wszystkie niezbędne pola. Ale jeśli użyje go inny programista, nikt mu nie przeszkodzi w stworzeniu zupełnie szalonych obiektów:
public class Main {

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

}
Jeśli pojawi się to w programie, znalezienie winowajcy nie będzie łatwe! Z jednej strony programista tworzący obiekty mógł zrozumieć, że klasa Monthoznacza „miesiąc w roku” i nie pisać takich bzdur. Z drugiej strony po prostu korzystał z możliwości, jakie zapewnił mu projektant klas. Czy mogę przypisać dowolne imiona i liczbę dni? On to wyznaczył. Co zrobić w takiej sytuacji? Przed wydaniem wersji 1.5 języka Java programiści musieli, szczerze mówiąc, wyjść z tego :) W tamtych czasach stworzyli następujące konstrukcje:
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("Январь", 31);
   public static Month FEBRUARY = new Month("Февраль", 28);
   public static Month MARCH = new Month("Март", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Tutaj uprościliśmy liczbę miesięcy do trzech zamiast dwunastu, aby przykład był krótszy. Takie projekty umożliwiły rozwiązanie problemu. Możliwości tworzonych obiektów zostały ograniczone przez prywatnego konstruktora:
private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Programiści korzystający z tej klasy nie mogli po prostu tworzyć plików Month. Byli zmuszeni użyć tych końcowych obiektów statycznych, które dostarczył twórca klasy. Wyglądało to mniej więcej tak:
public class Main {

   public static void main(String[] args) {

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

}
Jednak programiści Java zauważyli istniejący problem. Oczywiście wspaniale, że programistom udało się wymyślić rozwiązanie korzystając z narzędzi dostępnych w tym języku, jednak nie wygląda to na takie proste! Potrzebne było rozwiązanie oczywiste, dostępne nawet dla początkujących. W ten sposób pojawił się w Javie Enum. Zasadniczo Enumjest to klasa Java udostępniająca ograniczony zestaw obiektów wartości. Oto jak to wygląda:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}
W definicji wskazaliśmy, że Enumjest to klasa Java, ale czy to rzeczywiście prawda? Tak i możemy to nawet sprawdzić. Spróbuj na przykład odziedziczyć naszą enum Monthz innej klasy:
public abstract class AbstractMonth {
}

//ошибка! No extends clause allowed to enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
Dlaczego to się dzieje? Kiedy piszemy do programu:
public enum Month
Kompilator konwertuje to polecenie na kod taki jak ten:
public Class Month extends Enum
Jak już wiesz, dziedziczenie wielokrotne nie jest dozwolone w Javie. Dlatego AbstractMonthnie mogliśmy dziedziczyć. Jak można Enumwykorzystać ten nowy projekt? A czym różni się od starego projektu z static finalpolami? Cóż, na przykład stary projekt nie pozwalał nam na użycie własnego zestawu wartości w switchwyrażeniach. Wyobraźmy sobie, że chcemy stworzyć program, który przypomni nam, jakie święta obchodzone są w tym miesiącu:
public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           //błąd!
           case JANUARY:
       }
   }
}
Tutaj, jak widać, kompilator zgłasza błąd. Ale po pojawieniu się Java 1.5 enumwszystko stało się znacznie prostsze:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           case JANUARY:
               System.out.println("7 января будет Рождество!");
               break;
           case FEBRUARY:
               System.out.println("В феврале празднуется День Защитника Отечества - 23 февраля!");
               break;
           case MARCH:
               System.out.println("В марте отмечается Всемирный Женский День - 8 марта!");
               break;
       }
   }
}



public class Main {

   public static void main(String[] args) {

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

   }

}
Wyjście konsoli:

7 января будет Рождество!
Uwaga: dostęp do obiektów Enumpozostaje statyczny, tak jak przed wersją Java 1.5. Nie musimy tworzyć obiektu, Monthaby uzyskać dostęp do miesięcy. Pracując z wyliczeniami, bardzo ważne jest, aby nie zapominać, że Enumjest to pełnoprawna klasa. Oznacza to, że w razie potrzeby można w nim zdefiniować konstruktory i metody. Przykładowo w poprzednim fragmencie kodu po prostu podaliśmy wartości STYCZEŃ, LUTY, MARZEC. Możemy jednak rozszerzyć nasze enum Monthw ten sposób:
public enum Month {

   JANUARY("Январь", 31),
   FEBRUARY("Февраль", 28),
   MARCH("Март", 31),
   APRIL("Апрель", 30),
   MAY("Май", 31),
   JUNE("Июнь", 30),
   JULY("Июль", 31),
   AUGUST("Август", 31),
   SEPTEMBER("Сентябрь", 30),
   OCTOBER("Октябрь", 31),
   NOVEMBER("Ноябрь", 30),
   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 +
               '}';
   }
}
Tutaj dodaliśmy do naszego 2 pola enum- nazwę miesiąca i liczbę dni, konstruktor korzystający z tych pól, gettery-settery, metodę toString(), a także 2 metody statyczne. Jak widać, nie było z tym żadnych problemów: jak powiedzieliśmy wcześniej, enumjest to pełnoprawna klasa:
import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

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

   }

}
Wyjście konsoli:

[Month{name='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
Na koniec chcę Ci polecić jedną niezwykle przydatną książkę o Javie, a mianowicie „Efektywna Java” Joshuy Blocha . Wyliczenie.  Praktyczne przykłady.  Dodawanie konstruktorów i metod - 3Autor jest jednym z twórców Javy, dlatego z całą pewnością można zaufać jego radom dotyczącym prawidłowego i kompetentnego posługiwania się narzędziami językowymi :) W nawiązaniu do naszego wykładu radzę zwrócić szczególną uwagę na rozdział książki poświęcony enum. Życzymy produktywnej lektury! :)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION