Cześć! Dzisiaj porozmawiamy o jednym ze specjalnych typów danych w Javie:
Nie wydaje się problematyczne, prawda? Musimy tylko określić, jakie właściwości ma dany miesiąc. Być może najpierw potrzebujemy nazwy miesiąca i liczby dni w nim zawartych. Rozwiązanie wygląda dość prosto:
Autor jest jednym z twórców Javy, więc zdecydowanie możesz zaufać jego radom, jak poprawnie i kompetentnie korzystać z narzędzi języka :) W odniesieniu do naszej lekcji, polecam zwrócić szczególną uwagę na rozdział książki pt
Enum(skrót od „enumeration”). Co czyni go wyjątkowym? Wyobraźmy sobie, czego potrzebujemy, aby zaimplementować „miesiące” w programie.
Nie wydaje się problematyczne, prawda? Musimy tylko określić, jakie właściwości ma dany miesiąc. Być może najpierw potrzebujemy nazwy miesiąca i liczby dni w nim zawartych. Rozwiązanie 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 +
'}';
}
}
Cały szaban! Mamy Monthklasę, wymagane pola, pobierające/ustawiające i toString(). O ile oczywiście nie musimy dodać equals()ihashCode()osiągnąć pełnię szczęścia :) Ale tutaj mamy problem pojęciowy. Jak zapewne pamiętasz, jedną z głównych zalet OOP jest to, że ułatwia modelowanie obiektów z rzeczywistego świata. Krzesło, samochód, planeta — wszystkie te pojęcia ze zwykłego życia można łatwo przedstawić w programie za pomocą abstrakcji. Problem polega na tym, że niektóre byty w świecie rzeczywistym mają ściśle ograniczony zakres wartości. W roku są tylko 4 pory roku. W oktawie jest tylko 8 nut. Kalendarz ma tylko 12 miesięcy. A Danny Ocean z Ocean's 11 ma tylko 11 przyjaciół (choć to nie ma znaczenia :)) Liczy się to, że zwykła klasa Javy nie jest w stanie modelować tych bytów i narzucać ich naturalnych ograniczeń. NaszMonthclass ma wszystkie wymagane pola. Ale jeśli użyje go inny programista, nikt nie może go powstrzymać przed tworzeniem całkowicie szalonych obiektów:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
Jeśli pojawi się to w naszym kodzie, nie będzie łatwo znaleźć winowajcę! Z jednej strony programista tworzący obiekty mógłby sobie uświadomić, że Monthklasa oznacza „miesiąc w roku” i nie pisać takich bzdur. Z drugiej strony programista korzysta tylko z możliwości, które zapewnia projektant klasy. Czy można nadawać dowolne nazwy i numery dni? Dokładnie to mamy. Co w takim razie powinniśmy zrobić w tej sytuacji? Szczerze mówiąc, zanim wypuszczono Javę 1.5, programiści musieli wykazać się kreatywnością :) W tamtych czasach tworzyli takie struktury:
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 +
'}';
}
}
Tutaj skróciliśmy liczbę miesięcy z dwunastu do trzech, aby skrócić przykład. Takie projekty umożliwiły rozwiązanie problemu. Możliwość tworzenia obiektów została ograniczona do 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ć Monthobiektów. Musieli użyć ostatecznych obiektów statycznych dostarczonych przez twórcę klasy. Na przykład tak:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
Jednak programiści Java zwrócili uwagę na istniejący problem. Oczywiście to wspaniale, że programiści byli w stanie wymyślić rozwiązanie przy użyciu narzędzi dostępnych w języku, ale nie wygląda to na takie proste! Potrzebne było oczywiste rozwiązanie, nawet dla nowicjuszy. I tak Enumpojawił się w Javie. Zasadniczo Enumjest to klasa Java, która zapewnia ograniczony zestaw wartości obiektów. Oto jak to wygląda:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
W definicji wskazaliśmy, że Enumjest to klasa Java, ale czy to naprawdę prawda? Tak, a nawet możemy to zweryfikować. Na przykład spróbuj sprawić, by nasze Monthwyliczenie odziedziczyło inną klasę:
public abstract class AbstractMonth {
}
// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
Dlaczego tak się dzieje? Kiedy piszemy:
public enum Month
kompilator konwertuje tę instrukcję na następujący kod:
public Class Month extends Enum
Jak już wiesz, Java nie obsługuje wielokrotnego dziedziczenia. Dlatego nie możemy dziedziczyć AbstractMonth. EnumJak można wykorzystać ten nowy konstrukt, ,? I czym różni się od starego konstruktu z static finalpolami? Cóż, na przykład stara konstrukcja nie pozwalała nam używać własnego zestawu wartości w switchinstrukcjach. Wyobraź sobie, że chcemy stworzyć program, który będzie nam przypominał o świętach obchodzonych w każdym miesiącu:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
// Error!
case JANUARY:
}
}
}
Jak widać, kompilator wyrzuca tutaj błąd. Ale kiedy enumpojawił się w Javie 1.5, wszystko 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("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);
}
}
Wyjście konsoli:
New Year's Day is January 1st!
Należy zauważyć, że dostęp do Enumobiektów pozostał statyczny, tak jak przed Javą 1.5. Nie musimy tworzyć Monthobiektu, aby uzyskać dostęp do miesięcy. Podczas pracy 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. Na przykład w poprzednim fragmencie kodu po prostu określiliśmy wartości: JANUARY, FEBRUARY, MARCH. Możemy jednak rozszerzyć nasze Monthwyliczenie w następujący sposób:
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 +
'}';
}
}
Tutaj podaliśmy nasze enum2 pola (nazwę miesiąca i liczbę dni), konstruktor korzystający z tych pól, getter/settery, metodę toString()i 2 metody statyczne. Jak widać, nie było z tym żadnych problemów. Ponownie, Enumnaprawdę jest pełnoprawną klasą:
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='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Na koniec chcę polecić niezwykle przydatną książkę o Javie, a mianowicie „Efektywna Java” autorstwa Joshua Blocha .
Autor jest jednym z twórców Javy, więc zdecydowanie możesz zaufać jego radom, jak poprawnie i kompetentnie korzystać z narzędzi języka :) W odniesieniu do naszej lekcji, polecam zwrócić szczególną uwagę na rozdział książki pt Enum. Miłej lektury! :)
GO TO FULL VERSION