Podczas programowania często spotykamy się z koniecznością ograniczenia zbioru prawidłowych wartości dla określonego typu danych. Na przykład dzień tygodnia może mieć 7 różnych wartości, miesiąc roku może mieć 12, a pora roku może mieć 4. Aby rozwiązać takie problemy, wiele języków programowania z typem statycznym udostępnia specjalny typ danych - wyliczenie ( Elementy wyliczeniowe są instancjami
Elementy
enum
). Wyliczenie nie pojawiło się od razu w Javie. enum
Począwszy od wersji 1.5 wprowadzono konstrukcję języka specjalistycznego . Do tego momentu programiści używali innych metod implementacji wyliczeń.
konstrukcja wyliczeniowa
Zacznijmy od przykładu. Opiszmyenum
typ danych do przechowywania sezonu za pomocą:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Cóż, prosty przykład jego użycia:
Season season = Season.SPRING;
if (season == Season.SPRING) season = Season.SUMMER;
System.out.println(season);
W wyniku czego na konsoli zostanie wydrukowana wartość SUMMER . Myślę, że przykład jest oczywisty i nie wymaga objaśnień.
Enum jest klasą
Deklarującenum
, domyślnie tworzymy klasę pochodną java.lang.Enum
. Konwencjonalnie konstrukcja enum Season { ... }
jest równoważna class Season extends java.lang.Enum { ... }
. I chociaż kompilator nie pozwala nam jawnie dziedziczyć po java.lang.Enum
nas, nadal łatwo jest sprawdzić, czy enum
jest dziedziczony za pomocą reflection
:
System.out.println(Season.class.getSuperclass());
Na konsoli wyświetli się:
class java.lang.Enum
Rzeczywiste dziedziczenie wykonuje za nas automatycznie kompilator Javy. Następnie zgódźmy się wywołać klasę stworzoną przez kompilator w celu implementacji wyliczenia jako -class enum
, a możliwe wartości typu wyliczeniowego jako enum
elementy -a.
Elementy wyliczeniowe są instancjami enum
klasy -, które są dostępne statycznie
Elementy enum Season (WINTER, SPRING и т.д.)
są statycznie dostępnymi instancjami enum
klasy - Season
. Ich statyczna dostępność pozwala na dokonywanie porównań za pomocą referencyjnego operatora porównania ==
. Przykład:
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
Nazwa i numer seryjny elementu wyliczeniowego
Jak wspomniano wcześniej, każdaenum
-class dziedziczy java.lang.Enum
, która zawiera szereg metod przydatnych dla wszystkich wyliczeń. Przykład:
Season season = Season.WINTER;
System.out.println("season.name()=" + season.name() + " season.toString()=" + season.toString() + " season.ordinal()=" + season.ordinal());
Dane wyjściowe będą następujące:
season.name()=WINTER season.toString()=WINTER season.ordinal()=0
Metody name()
i toString()
są pokazane tutaj ordinal()
. Semantyka metod jest oczywista. Należy zaznaczyć, że metody te enum
są dziedziczone z klasy java.lang.Enum
. Pobieranie elementu enum
na podstawie jego nazwy w postaci ciągu znaków. Dość często pojawia się zadanie pobrania elementu enum
na podstawie jego reprezentacji w postaci ciągu znaków. W tym celu w każdej enum
klasie kompilator automatycznie tworzy specjalną metodę statyczną: public static EnumClass valueOf(String name)
, która zwraca element wyliczeniowy EnumClass
o nazwie równej name
. Przykład użycia:
String name = "WINTER";
Season season = Season.valueOf(name);
W wyniku wykonania kodu zmienna sezon będzie równa Season.WINTER
. Należy pamiętać, że jeśli element nie zostanie znaleziony, zostanie zgłoszony wyjątek IllegalArgumentException , a jeśli jest name
równy null
, zostanie zgłoszony wyjątek NullPointerException . Swoją drogą, często się o tym zapomina. Z jakiegoś powodu wielu jest głęboko przekonanych, że jeśli funkcja przyjmuje jeden argument i pod pewnymi warunkami zgłasza wyjątek IllegalArgumentException , to przekazując go tam , null
z pewnością zostanie zgłoszony również wyjątek IllegalArgumentException . Ale to nie ma znaczenia. Kontynuujmy. Pobieranie wszystkich elementów wyliczenia Czasami trzeba uzyskać listę wszystkich elementów enum
klasy - w czasie wykonywania. W tym celu enum
kompilator tworzy metodę w każdej -klasie public static EnumClass[] values()
. Przykład użycia:
System.out.println(Arrays.toString(Season.values()));
Otrzymujemy dane wyjściowe:
[WINTER, SPRING, SUMMER, AUTUMN]
Należy zauważyć, że w klasie nie zdefiniowano ani metody valueOf()
, ani metody . Zamiast tego są one automatycznie dodawane przez kompilator podczas kompilacji klasy -. Dodawanie własnych metod do klasy -Masz możliwość dodania własnych metod zarówno do klasy -jak i jej elementów: To samo, ale z polimorfizmem: Ostatni przykład demonstruje użycie dziedziczenia w . Więcej na ten temat później. Dziedziczenie w Javie pozwala na implementację hierarchii klas, której obiekty tworzone są w jednej instancji i są dostępne statycznie. W tym przypadku elementy mogą zawierać własne konstruktory. Podajmy przykład: Tutaj deklarujemy wyliczenie z trzema elementami i . Kompilator utworzy następujące klasy i obiekty: values()
java.lang.Enum
enum
enum
enum
enum
enum
enum
enum
Type
INT
INTEGER
STRING
Type
- klasa wywodząca się zjava.lang.Enum
INT
— przedmiot I klasy wywodzący się zType
INTEGER
— przedmiot II klasy wywodzący się zType
STRING
— przedmiot 3. klasy wywodzący się zType
Object parse(String)
i konstruktora Type(..., boolean)
. Jednocześnie obiekty klas INT
i istnieją w jednym egzemplarzu i są dostępne statycznie INTEGER
. STRING
Możesz to zweryfikować:
System.out.println(Type.class);
System.out.println(Type.INT.getClass() + " " + Type.INT.getClass().getSuperclass());
System.out.println(Type.INTEGER.getClass() + " " + Type.INTEGER.getClass().getSuperclass());
System.out.println(Type.STRING.getClass() + " " + Type.STRING.getClass().getSuperclass());
Otrzymujemy następujące dane wyjściowe:
class Type
class Type$1 class Type
class Type$2 class Type
class Type$3 class Type
Można zauważyć, że kompilator utworzył klasę Type
i 3 nested
klasy wywodzące się z Type
.
Zdekompilowana klasa wyliczeniowa z dziedziczeniem
Na potwierdzenie powyższego prezentujemy również wynik dekompilacji wyliczeniaType
z powyższego przykładu:
Wyliczenia i polimorfizm parametryczny
Czytelnik może się zastanawiać: „ Dlaczego powyższe wyliczenie typów nie używa typów ogólnych? ” Faktem jest, że w Javie używanie nazw generycznych jestenum
zabronione. Zatem poniższy przykład nie zostanie skompilowany:
enum Type<T> {}
Dalsze badanie
Aby lepiej zrozumieć działanie wyliczeń w Javie, polecam zapoznać się z kodem źródłowym klasyjava.lang.Enum
, a także skorzystać z dekompilatora Jad w celu przestudiowania wygenerowanego kodu. Co więcej, przestudiowanie kodu źródłowego biblioteki Java jest absolutnie konieczne, aby zrozumieć, jak wiele mechanizmów działa w Javie i jest przydatne jako punkt odniesienia w projektowaniu obiektowym. Link do oryginalnego źródła: http://alexander.lds.lg.ua/
GO TO FULL VERSION