Szukaj…


Wprowadzenie

Wyliczenia Java (zadeklarowane za pomocą słowa kluczowego enum ) to skrócona składnia dla znacznych ilości stałych jednej klasy.

Składnia

  • [public / protected / private] enum Enum_name {// Zadeklaruj nowe wyliczenie.
  • ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Deklaruj stałe wyliczeniowe. Musi to być pierwsza linia wewnątrz wyliczenia i powinna być oddzielona przecinkami, z końcem średnika.
  • ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Deklaruj stałe wyliczeniowe z parametrami. Typy parametrów muszą być zgodne z konstruktorem.
  • ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Deklaruj stałe wyliczeniowe za pomocą przesłoniętych metod. Należy to zrobić, jeśli wyliczenie zawiera metody abstrakcyjne; wszystkie takie metody muszą zostać wdrożone.
  • ENUM_CONSTANT.name () // Zwraca ciąg znaków o nazwie stałej wyliczeniowej.
  • ENUM_CONSTANT.ordinal () // Zwraca liczbę porządkową tej stałej wyliczenia, jej pozycję w deklaracji wyliczenia, gdzie stałej początkowej jest przypisana liczba zerowa.
  • Enum_name.values () // Zwraca nową tablicę (typu Enum_name []) zawierającą każdą stałą tego wyliczenia przy każdym wywołaniu.
  • Enum_name.valueOf ("ENUM_CONSTANT") // Odwrotność ENUM_CONSTANT.name () - zwraca stałą wyliczenia o podanej nazwie.
  • Enum.valueOf (Enum_name.class, „ENUM_CONSTANT”) // Synonim poprzedniego: Odwrotność ENUM_CONSTANT.name () - zwraca stałą enum o podanej nazwie.

Uwagi

Ograniczenia

Wyliczenia zawsze rozszerzają java.lang.Enum , więc wyliczenie nie może rozszerzyć klasy. Mogą jednak implementować wiele interfejsów.

Porady & Triki

Ze względu na ich wyspecjalizowaną reprezentację istnieją bardziej wydajne mapy i zestawy , których można używać z wyliczeniami jako kluczami. Będą one często działać szybciej niż ich niespecjalistyczne odpowiedniki.

Deklarowanie i używanie podstawowego wyliczenia

Wyliczenie można uznać za cukier składniowy dla zapieczętowanej klasy, która jest tworzona tylko kilka razy w czasie kompilacji w celu zdefiniowania zestawu stałych.

Prosty wyliczenie do wyszczególnienia różnych pór roku zostanie zadeklarowane w następujący sposób:

public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

Chociaż stałe wyliczeniowe niekoniecznie muszą być pisane wielkimi literami, zgodnie z konwencją Java nazwy stałych są całkowicie pisane wielkimi literami, a słowa oddzielane są podkreślnikami.


Możesz zadeklarować Enum we własnym pliku:

/**
 * This enum is declared in the Season.java file.
*/
public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

Ale możesz też zadeklarować to w innej klasie:

 public class Day {

    private Season season;

    public String getSeason() {
        return season.name();
    }

    public void setSeason(String season) {
        this.season = Season.valueOf(season);
    }

    /**
     * This enum is declared inside the Day.java file and 
     * cannot be accessed outside because it's declared as private.
     */
    private enum Season {
        WINTER,
        SPRING,
        SUMMER,
        FALL
    }

}

Wreszcie nie można zadeklarować Enum wewnątrz treści metody lub konstruktora:

public class Day {

    /**
     * Constructor
    */
    public Day() {
        // Illegal. Compilation error
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }
    }

    public void aSimpleMethod() {
        // Legal. You can declare a primitive (or an Object) inside a method. Compile!
        int primitiveInt = 42;

        // Illegal. Compilation error.
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }

        Season season = Season.SPRING;
    }
    
}

Zduplikowane stałe wyliczeniowe są niedozwolone:

public enum Season {
    WINTER,
    WINTER, //Compile Time Error : Duplicate Constants
    SPRING,
    SUMMER,
    FALL
} 

Każda stała wyliczania jest domyślnie public , static i final . Ponieważ każda stała jest static , można uzyskać do nich bezpośredni dostęp za pomocą nazwy wyliczenia.

Stałe enum można przekazać jako parametry metody:

public static void display(Season s) {
    System.out.println(s.name());  // name() is a built-in method that gets the exact name of the enum constant
}

display(Season.WINTER);  // Prints out "WINTER"

Możesz uzyskać tablicę stałych wyliczania za pomocą metody values() . Gwarantujemy, że wartości będą w kolejności deklaracji w zwróconej tablicy:

Season[] seasons = Season.values();

Uwaga: ta metoda przydziela nową tablicę wartości przy każdym wywołaniu.


Aby iterować po stałych enum:

public static void enumIterate() {
    for (Season s : Season.values()) {
        System.out.println(s.name());
    }
}

Można użyć wyliczeń w instrukcji switch :

public static void enumSwitchExample(Season s) {
    switch(s) {
        case WINTER:
            System.out.println("It's pretty cold");
            break;
        case SPRING:
            System.out.println("It's warming up");
            break;
        case SUMMER:
            System.out.println("It's pretty hot");
            break;
        case FALL:
            System.out.println("It's cooling down");
            break;
    }
}

Możesz także porównać stałe wyliczeniowe za pomocą == :

Season.FALL == Season.WINTER    // false
Season.SPRING == Season.SPRING  // true

Innym sposobem na porównanie stałych wyliczania jest użycie equals() jak poniżej, co jest uważane za złą praktykę, ponieważ łatwo można wpaść w pułapki w następujący sposób:

Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error

Ponadto, chociaż zestawu instancji w enum nie można zmienić w czasie wykonywania, same instancje nie są z natury niezmienne, ponieważ jak każda inna klasa, enum może zawierać zmienne pola, jak pokazano poniżej.

public enum MutableExample {
    A,
    B;

    private int count = 0;

    public void increment() {
        count++;
    }

    public void print() {
        System.out.println("The count of " + name() + " is " + count);
    }
}

// Usage:
MutableExample.A.print();       // Outputs 0
MutableExample.A.increment();
MutableExample.A.print();       // Outputs 1 -- we've changed a field   
MutableExample.B.print();       // Outputs 0 -- another instance remains unchanged

Jednak dobrą praktyką jest uczynienie instancji enum niezmiennymi, tzn. Gdy albo nie mają one żadnych dodatkowych pól, albo wszystkie takie pola są oznaczone jako final i same są niezmienne. Zapewni to, że przez całe życie aplikacji enum nie wycieknie żadnej pamięci i że będzie bezpiecznie używać swoich instancji we wszystkich wątkach.


Wyliczenia domyślnie implementują Serializable i Comparable ponieważ klasa Enum :

public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable

Wyliczenia z konstruktorami

enum nie może mieć publicznego konstruktora; jednak prywatne konstruktory są dopuszczalne (konstruktory dla wyliczeń są domyślnie pakietowo prywatne ):

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25); // usual names for US coins
    // note that the above parentheses and the constructor arguments match
    private int value;

    Coin(int value) { 
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

Zaleca się zachowanie poufności wszystkich pól i zapewnienie metod pobierających, ponieważ liczba wyliczeń jest ograniczona.


Gdyby zamiast tego zaimplementować Enum jako class , wyglądałoby to tak:

public class Coin<T extends Coin<T>> implements Comparable<T>, Serializable{
    public static final Coin PENNY = new Coin(1);
    public static final Coin NICKEL = new Coin(5);
    public static final Coin DIME = new Coin(10);
    public static final Coin QUARTER = new Coin(25);

    private int value;

    private Coin(int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

Stałe wyliczeniowe są technicznie mutowalne, więc można ustawić seter w celu zmiany wewnętrznej struktury stałej wyliczeniowej. Jest to jednak uważane za bardzo złą praktykę i należy tego unikać.

Najlepszą praktyką jest uczynienie pól Enum niezmiennymi, przy czym final :

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){ 
        this.value = value;
    }

    ...

}

Możesz zdefiniować wiele konstruktorów w tym samym wyliczeniu. Gdy to zrobisz, argumenty przekazane w deklaracji wyliczeniowej decydują, który konstruktor jest nazywany:

public enum Coin {
    PENNY(1, true), NICKEL(5, false), DIME(10), QUARTER(25);

    private final int value;
    private final boolean isCopperColored;

    Coin(int value){
        this(value, false);
    }

    Coin(int value, boolean isCopperColored){ 
        this.value = value;
        this.isCopperColored = isCopperColored;
    }

    ...

}

Uwaga: Wszystkie nieprecyzyjne pola wyliczeniowe powinny implementować Serializable ponieważ robi to klasa Enum .

Korzystanie z metod i bloków statycznych

Wyliczenie może zawierać metodę, tak jak każda klasa. Aby zobaczyć, jak to działa, zadeklarujemy wyliczenie w następujący sposób:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
}

Spójrzmy na metodę, która zwraca wyliczenie w przeciwnym kierunku:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction getOpposite(){
        switch (this){
            case NORTH:
                return SOUTH;               
            case SOUTH:
                return NORTH;                
            case WEST:
                return EAST; 
            case EAST:
                return WEST;  
            default: //This will never happen
                return null;
        }
    }
}

Można to jeszcze ulepszyć, stosując pola i statyczne bloki inicjujące:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
    
    private Direction opposite;
    
    public Direction getOpposite(){
        return opposite;
    }
    
    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        WEST.opposite = EAST;
        EAST.opposite = WEST;
    }
}

W tym przykładzie przeciwny kierunek jest przechowywany w polu prywatnej instancji opposite , który jest statycznie inicjowany przy pierwszym użyciu Direction . W tym konkretnym przypadku (ponieważ NORTH odwołuje się do SOUTH i odwrotnie), nie możemy tutaj używać Enums z konstruktorami (Constructors NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST) byłyby bardziej eleganckie i pozwoliłyby opposite do zostaną uznane za final , ale będą się odnosić i dlatego nie są dozwolone).

Implementuje interfejs

Jest to enum które jest również funkcją wywoływalną, która testuje dane wejściowe String pod kątem wstępnie skompilowanych wzorców wyrażeń regularnych.

import java.util.function.Predicate;
import java.util.regex.Pattern;

enum RegEx implements Predicate<String> {
    UPPER("[A-Z]+"), LOWER("[a-z]+"), NUMERIC("[+-]?[0-9]+");

    private final Pattern pattern;

    private RegEx(final String pattern) {
        this.pattern = Pattern.compile(pattern);
    }

    @Override 
    public boolean test(final String input) {
        return this.pattern.matcher(input).matches();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(RegEx.UPPER.test("ABC"));
        System.out.println(RegEx.LOWER.test("abc"));
        System.out.println(RegEx.NUMERIC.test("+111"));
    }
}

Każdy członek wyliczenia może również implementować metodę:

import java.util.function.Predicate;

enum Acceptor implements Predicate<String> {
    NULL {
        @Override
        public boolean test(String s) { return s == null; }
    },
    EMPTY {
        @Override
        public boolean test(String s) { return s.equals(""); }
    },
    NULL_OR_EMPTY {
        @Override
        public boolean test(String s) { return NULL.test(s) || EMPTY.test(s); }
    };
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Acceptor.NULL.test(null));  // true
        System.out.println(Acceptor.EMPTY.test(""));   // true
        System.out.println(Acceptor.NULL_OR_EMPTY.test(" ")); // false
    }
}

Wzór Enum polimorfizmu

Gdy metoda musi zaakceptować „rozszerzalny” zestaw wartości enum , programista może zastosować polimorfizm jak w normalnej class , tworząc interfejs, który będzie używany wszędzie tam, gdzie będzie używany enum :

public interface ExtensibleEnum {
    String name();
}

W ten sposób dowolne enum oznaczone (implementujące) interfejs może być użyte jako parametr, umożliwiając programiście tworzenie zmiennej ilości enum które będą akceptowane przez metodę. Może to być przydatne na przykład w interfejsach API, w których występuje domyślny (niemodyfikowalny) enum a użytkownik tych interfejsów API chce „rozszerzyć” enum o więcej wartości.

Zestaw domyślnych wartości wyliczania można zdefiniować w następujący sposób:

public enum DefaultValues implements ExtensibleEnum {
    VALUE_ONE, VALUE_TWO;
}

Następnie można zdefiniować dodatkowe wartości w następujący sposób:

public enum ExtendedValues implements ExtensibleEnum {
    VALUE_THREE, VALUE_FOUR;
}

Próbka, która pokazuje, jak używać teksty stałe - uwaga jak printEnum() przyjmuje wartości z obu enum typów:

private void printEnum(ExtensibleEnum val) {
    System.out.println(val.name());
}  

printEnum(DefaultValues.VALUE_ONE);    // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO);    // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR);  // VALUE_FOUR

Uwaga: Ten wzorzec nie uniemożliwia ponownego zdefiniowania wartości wyliczenia, które są już zdefiniowane w jednym wyliczeniu, w innym wyliczeniu. Te wartości wyliczeniowe byłyby wtedy różnymi przypadkami. Ponadto nie jest możliwe użycie włączania-wyliczania, ponieważ wszystko, co mamy, to interfejs, a nie prawdziwe enum .

Wyliczenia metodami abstrakcyjnymi

Wyliczenia mogą definiować metody abstrakcyjne, które każdy członek enum musi wdrożyć.

enum Action {
    DODGE {
        public boolean execute(Player player) {
            return player.isAttacking();
        }
    },
    ATTACK {
        public boolean execute(Player player) {
            return player.hasWeapon();
        }
    },
    JUMP {
        public boolean execute(Player player) {
            return player.getCoordinates().equals(new Coordinates(0, 0));
        }
    };

    public abstract boolean execute(Player player);
}

Pozwala to każdemu członkowi enum zdefiniować własne zachowanie dla danej operacji, bez konieczności włączania typów w metodzie w definicji najwyższego poziomu.

Zauważ, że ten wzorzec jest krótką formą tego, co zwykle osiąga się za pomocą polimorfizmu i / lub implementacji interfejsów.

Dokumentowanie wyliczeń

Nie zawsze nazwa enum jest wystarczająco jasna, aby ją zrozumieć. Aby udokumentować enum , użyj standardowego javadoc:

/**
 * United States coins
 */
public enum Coins {
    
    /**
     * One-cent coin, commonly known as a penny, 
     * is a unit of currency equaling one-hundredth 
     * of a United States dollar
     */
    PENNY(1),

    /**
     * A nickel is a five-cent coin equaling 
     * five-hundredth of a United States dollar
     */        
    NICKEL(5),

    /**
     * The dime is a ten-cent coin refers to 
     * one tenth of a United States dollar
     */        
    DIME(10),

    /**
     * The quarter is a US coin worth 25 cents, 
     * one-fourth of a United States dollar
     */        
    QUARTER(25);

    private int value;

    Coins(int value){ 
        this.value = value;
    }

    public int getValue(){
        return value;
    }
}

Uzyskiwanie wartości wyliczenia

Każda klasa enum zawiera niejawną metodę statyczną o nazwie values() . Ta metoda zwraca tablicę zawierającą wszystkie wartości tego wyliczenia. Możesz użyć tej metody do iteracji po wartościach. Należy jednak pamiętać, że ta metoda zwraca nową tablicę przy każdym wywołaniu.

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
    
    /**
    * Print out all the values in this enum.
    */
    public static void printAllDays() {
        for(Day day : Day.values()) {
            System.out.println(day.name());
        }
    }
}

Jeśli potrzebujesz Set , możesz także użyć EnumSet.allOf(Day.class) .

Wylicz jako parametr typu ograniczonego

Pisząc klasę ze standardami w Javie, można upewnić się, że parametr type jest wyliczeniem. Ponieważ wszystkie Enum rozszerzają klasę Enum , można zastosować następującą składnię.

public class Holder<T extends Enum<T>> {
    public final T value;

    public Holder(T init) {
        this.value = init;
    }
}

W tym przykładzie typ T musi być wyliczeniem.

Uzyskaj stałą wyliczania według nazwy

Powiedzmy, że mamy enum DayOfWeek :

enum DayOfWeek {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

Wyliczenie jest kompilowane za pomocą wbudowanej metody static valueOf() , której można użyć do wyszukiwania stałej według jej nazwy:

String dayName = DayOfWeek.SUNDAY.name();
assert dayName.equals("SUNDAY");

DayOfWeek day = DayOfWeek.valueOf(dayName);
assert day == DayOfWeek.SUNDAY;

Jest to również możliwe przy użyciu dynamicznego typu wyliczenia:

Class<DayOfWeek> enumType = DayOfWeek.class;
DayOfWeek day = Enum.valueOf(enumType, "SUNDAY");
assert day == DayOfWeek.SUNDAY;

Obie metody valueOf() IllegalArgumentException jeśli określony wyliczenie nie ma stałej o pasującej nazwie.

Biblioteka Guava udostępnia metodę pomocniczą Enums.getIfPresent() która zwraca Enums.getIfPresent() Guava Optional celu wyeliminowania jawnej obsługi wyjątków:

DayOfWeek defaultDay = DayOfWeek.SUNDAY;
DayOfWeek day = Enums.valueOf(DayOfWeek.class, "INVALID").or(defaultDay);
assert day == DayOfWeek.SUNDAY;

Zaimplementuj wzór Singleton z wyliczeniem pojedynczego elementu

Stałe wyliczania są tworzone, gdy odniesienie do wyliczenia następuje po raz pierwszy. Dlatego pozwala to na implementację wzorca projektowego oprogramowania Singleton z wyliczeniem jednoelementowym.

public enum Attendant {

    INSTANCE;

    private Attendant() {
        // perform some initialization routine
    }

    public void sayHello() {
        System.out.println("Hello!");
    }
}


public class Main {

    public static void main(String... args) {
        Attendant.INSTANCE.sayHello();// instantiated at this point
    }
}

Według książki „Effective Java” Joshua Blocha, enum jednoelementowy jest najlepszym sposobem na wdrożenie singletonu. Takie podejście ma następujące zalety:

  • bezpieczeństwo wątku
  • gwarancja pojedynczej instancji
  • serializacja od razu po wyjęciu z pudełka

I jak pokazano w sekcji implementującej interfejs, ten singleton może również implementować jeden lub więcej interfejsów.

Wylicz z właściwościami (pola)

W przypadku, gdy chcemy użyć enum z większą ilością informacji, a nie tylko jako stałych wartości, i chcemy móc porównać dwa wyliczenia.

Rozważ następujący przykład:

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){
        this.value = value;
    }

    public boolean isGreaterThan(Coin other){
        return this.value > other.value;
    }

}

Tutaj zdefiniowaliśmy Enum zwane Coin które reprezentuje jego wartość. Metodą isGreaterThan możemy porównać dwa enum :

Coin penny = Coin.PENNY;
Coin dime = Coin.DIME;

System.out.println(penny.isGreaterThan(dime)); // prints: false
System.out.println(dime.isGreaterThan(penny)); // prints: true

Konwertuj wyliczenie na ciąg

Czasami chcesz przekonwertować wyliczenie na ciąg, istnieją dwa sposoby, aby to zrobić.

Załóżmy, że mamy:

public enum Fruit {
    APPLE, ORANGE, STRAWBERRY, BANANA, LEMON, GRAPE_FRUIT;
}

Jak więc przekonwertować coś takiego jak Fruit.APPLE na "APPLE" ?


Konwertuj za pomocą name()

name() to wewnętrzna metoda w enum która zwraca String reprezentujący wyliczenie, zwracany String reprezentuje dokładnie, jak zdefiniowano wartość wyliczenia.

Na przykład:

System.out.println(Fruit.BANANA.name());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"

Konwertuj za pomocą toString()

toString() jest domyślnie nadpisane, aby mieć takie samo zachowanie jak name()

Jednak toString() jest prawdopodobnie nadpisywane przez programistów, aby wydrukować bardziej przyjazny dla użytkownika String

Nie używaj toString() jeśli chcesz sprawdzić kod, name() jest do tego bardziej stabilny. Używaj toString() wtedy, gdy zamierzasz wypisać wartość do logów, standardowego wyjścia lub czegoś takiego

Domyślnie:

System.out.println(Fruit.BANANA.toString());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"

Przykład zastąpienia

System.out.println(Fruit.BANANA.toString());      // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"

Enum stałe ciało właściwe

W enum możliwe jest zdefiniowanie konkretnego zachowania dla określonej stałej enum która zastępuje domyślne zachowanie enum , ta technika jest znana jako stałe ciało właściwe .

Załóżmy, że trzej studenci fortepianu - John, Ben i Luke - są zdefiniowani w enum nazwie PianoClass w następujący sposób:

    enum PianoClass {
    JOHN, BEN, LUKE;
        public String getSex() {
            return "Male";
        }
        public String getLevel() {
            return "Beginner";
        }
    }

I pewnego dnia przyjeżdżają dwaj inni uczniowie - Rita i Tom - z płcią (kobieta) i poziomem (średniozaawansowanym), które nie pasują do poprzednich:

    enum PianoClass2 {
    JOHN, BEN, LUKE, RITA, TOM;
        public String getSex() {
            return "Male"; // issue, Rita is a female
        }
        public String getLevel() {
            return "Beginner"; // issue, Tom is an intermediate student
        }
    }

tak więc dodanie nowych uczniów do stałej deklaracji w następujący sposób nie jest poprawne:

PianoClass2 tom = PianoClass2.TOM;
PianoClass2 rita = PianoClass2.RITA;
System.out.println(tom.getLevel()); // prints Beginner -> wrong Tom's not a beginner
System.out.println(rita.getSex()); // prints Male -> wrong Rita's not a male

Możliwe jest zdefiniowanie konkretnego zachowania dla każdej stałej, Rity i Toma, która zastępuje domyślne zachowanie PianoClass2 w następujący sposób:

enum PianoClass3 {
    JOHN, BEN, LUKE,
    RITA {
        @Override
        public String getSex() {
            return "Female";
        }
    },
    TOM {
        @Override
        public String getLevel() {
            return "Intermediate";
        }
    };
    public String getSex() {
        return "Male";
    }
    public String getLevel() {
        return "Beginner";
    }
}

a teraz poziom Toma i płeć Rity są takie, jakie powinny być:

PianoClass3 tom = PianoClass3.TOM;
PianoClass3 rita = PianoClass3.RITA;
System.out.println(tom.getLevel()); // prints Intermediate
System.out.println(rita.getSex()); // prints Female

Innym sposobem zdefiniowania treści specyficznych dla treści jest użycie konstruktora, na przykład:

enum Friend {
    MAT("Male"),
    JOHN("Male"),
    JANE("Female");
    
    private String gender;

    Friend(String gender) {
        this.gender = gender;
    }

    public String getGender() {
        return this.gender;
    }
}

i użycie:

Friend mat = Friend.MAT;
Friend john = Friend.JOHN;
Friend jane = Friend.JANE;
System.out.println(mat.getGender());     // Male
System.out.println(john.getGender());    // Male
System.out.println(jane.getGender());    // Female

Wyliczanie instancji zerowej

enum Util {
    /* No instances */;

    public static int clamp(int min, int max, int i) {
        return Math.min(Math.max(i, min), max);
    }

    // other utility methods...
}

Tak jak enum może być użyte dla singletonów (klasy instancji 1), tak samo może być użyte dla klas narzędziowych (klasy instancji 0). Upewnij się, że zakończysz (pustą) listę stałych wyliczeniowych za pomocą ; .

Zobacz pytanie Wyliczenie instancji zerowej vs. prywatne konstruktory, aby zapobiec tworzeniu instancji w dyskusji na temat zalet i wad w porównaniu z prywatnymi konstruktorami.

Wyliczenia z polami statycznymi

Jeśli twoja klasa enum musi mieć pola statyczne, pamiętaj, że są tworzone po samych wartościach enum. Oznacza to, że następujący kod spowoduje NullPointerException :

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers = new HashMap<>();

    private Example(int value) {
        integers.put(this.name(), value);
    }
}

Możliwy sposób to naprawić:

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
}

Nie inicjuj pola statycznego:

enum Example {
    ONE(1), TWO(2);

    // after initialisisation integers is null!!
    static Map<String, Integer> integers = null;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
    // !!this may lead to null poiner exception!!
    public int getValue(){
        return (Example.integers.get(this.name()));
    }
}

inicjalizacja:

  • utwórz wartości wyliczeniowe
    • jako wywołany efekt uboczny putValue (), który inicjuje liczby całkowite
  • wartości statyczne są ustawione
    • liczby całkowite = null; // jest wykonywane po wyliczeniu, więc zawartość liczb całkowitych jest tracona

Porównaj i zawiera wartości Enum

Wyliczenia zawierają tylko stałe i można je bezpośrednio porównać z == . Potrzebne jest tylko sprawdzenie referencji, nie trzeba używać metody .equals . Ponadto, jeśli .equals użyte niepoprawnie, może wywołać NullPointerException podczas gdy nie jest tak w przypadku sprawdzania == .

enum Day {
    GOOD, AVERAGE, WORST;
}

public class Test {

    public static void main(String[] args) {
        Day day = null;

        if (day.equals(Day.GOOD)) {//NullPointerException!
            System.out.println("Good Day!");
        }

        if (day == Day.GOOD) {//Always use == to compare enum
            System.out.println("Good Day!");
        }

    }
}

Aby pogrupować, uzupełnić, EnumSet wartości wyliczeniowe, mamy klasę EnumSet która zawiera różne metody.

  • EnumSet#range : Aby uzyskać podzbiór wyliczenia przez zakres zdefiniowany przez dwa punkty końcowe

  • EnumSet#of : Zbiór określonych wyliczeń bez żadnego zakresu. Stwardnienie przeciążony of metod istnieją.

  • EnumSet#complementOf : Zestaw wyliczenia, który jest uzupełnieniem wartości wyliczenia podanych w parametrze metody

    enum Page {
       A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
    }
    
    public class Test {
    
      public static void main(String[] args) {
          EnumSet<Page> range = EnumSet.range(Page.A1, Page.A5);
    
          if (range.contains(Page.A4)) {
              System.out.println("Range contains A4");
          }
    
          EnumSet<Page> of = EnumSet.of(Page.A1, Page.A5, Page.A3);
    
          if (of.contains(Page.A1)) {
              System.out.println("Of contains A1");
          }
      }
    }
    


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow