Suche…


Einführung

Java-Enums (deklariert mit dem Schlüsselwort enum ) sind eine Abkürzungssyntax für beträchtliche Mengen von Konstanten einer einzelnen Klasse.

Syntax

  • [public / protected / private] enum Enum_name {// Neues Enum deklarieren.
  • ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Deklariere die Enumenkonstanten. Dies muss die erste Zeile innerhalb der Enumeration sein und sollte durch Kommas getrennt werden, am Ende ein Semikolon.
  • ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Deklarieren Sie Enumerationskonstanten mit Parametern. Die Parametertypen müssen zum Konstruktor passen.
  • ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Deklarieren Sie Enumenkonstanten mit überschriebenen Methoden. Dies muss geschehen, wenn die Aufzählung abstrakte Methoden enthält. Alle diese Methoden müssen implementiert werden.
  • ENUM_CONSTANT.name () // Gibt einen String mit dem Namen der Enumenkonstante zurück.
  • ENUM_CONSTANT.ordinal () // Gibt die Ordnungszahl dieser Enumerationskonstante zurück, ihre Position in der Enumendeklaration, wobei der Anfangskonstante eine Ordnungszahl von Null zugewiesen wird.
  • Enum_name.values ​​() // Gibt ein neues Array (vom Typ Enum_name []) zurück, das bei jedem Aufruf jede Konstante dieser Enumeration enthält.
  • Enum_name.valueOf ("ENUM_CONSTANT") // Die Umkehrung von ENUM_CONSTANT.name () - gibt die Enumenkonstante mit dem angegebenen Namen zurück.
  • Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Ein Synonym des vorherigen: Die Umkehrung von ENUM_CONSTANT.name () - gibt die Enumenkonstante mit dem angegebenen Namen zurück.

Bemerkungen

Beschränkungen

Enumerationen erweitern immer java.lang.Enum , daher ist es für eine Enumeration nicht möglich, eine Klasse zu erweitern. Sie können jedoch viele Schnittstellen implementieren.

Tipps

Aufgrund ihrer speziellen Darstellung gibt es effizientere Karten und Sets , die mit Enumerationen als Schlüssel verwendet werden können. Diese laufen oft schneller als ihre nicht spezialisierten Kollegen.

Deklarieren und Verwenden einer grundlegenden Aufzählung

Enum kann als Syntaxzucker für eine versiegelte Klasse betrachtet werden, die nur zum Zeitpunkt der Kompilierung bekannt ist, um eine Menge von Konstanten zu definieren.

Eine einfache Aufzählung der verschiedenen Jahreszeiten würde wie folgt erklärt:

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

Während die Enumerationskonstanten nicht unbedingt in Großbuchstaben angegeben sein müssen, ist es die Java-Konvention, dass Konstantennamen vollständig aus Großbuchstaben bestehen und die Wörter durch Unterstriche getrennt sind.


Sie können ein Enum in einer eigenen Datei deklarieren:

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

Sie können es aber auch in einer anderen Klasse deklarieren:

 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
    }

}

Schließlich können Sie kein Enum innerhalb eines Methodentexts oder Konstruktors deklarieren:

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;
    }
    
}

Doppelte Enumerationskonstanten sind nicht zulässig:

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

Jede Konstante von enum ist standardmäßig public , static und final . Da jede Konstante static , kann auf sie direkt über den Aufzählungsnamen zugegriffen werden.

Enumenkonstanten können als Methodenparameter übergeben werden:

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"

Sie können ein Array der Enumenkonstanten mit der Methode values() abrufen. Die Werte befinden sich garantiert in der Reihenfolge der Deklaration im zurückgegebenen Array:

Season[] seasons = Season.values();

Hinweis: Diese Methode ordnet bei jedem Aufruf ein neues Array von Werten zu.


Um die Enumenkonstanten zu durchlaufen:

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

Sie können enums in einer switch Anweisung verwenden:

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;
    }
}

Sie können Enumerationskonstanten auch mit == :

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

Eine andere Möglichkeit, die Enumenkonstanten zu vergleichen, ist die Verwendung von equals() wie unten, was als schlechte Praxis betrachtet wird, da Sie wie folgt leicht in Fallstricke fallen können:

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

Obwohl die Menge der Instanzen in der enum nicht zur Laufzeit geändert werden kann, sind die Instanzen selbst nicht inhärent unveränderlich, da eine enum wie jede andere Klasse veränderliche Felder enthalten kann, wie unten gezeigt wird.

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

Es enum sich jedoch, enum Instanzen unveränderlich zu machen, dh, wenn sie entweder keine zusätzlichen Felder haben oder alle diese Felder als final und selbst unveränderlich sind. Dadurch wird sichergestellt, dass ein enum über die gesamte Lebensdauer der Anwendung keinen Speicher enum und dass die Instanzen sicher für alle Threads verwendet werden können.


Aufzählungen implementieren implizit Serializable und Comparable , weil die Enum - Klasse tut:

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

Enums mit Konstruktoren

Eine enum kann keinen öffentlichen Konstruktor haben. Private Konstruktoren sind jedoch zulässig (Konstruktoren für Enumerationen sind standardmäßig private Pakete ):

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

Es wird empfohlen, alle Felder privat zu halten und Getter-Methoden bereitzustellen, da es eine begrenzte Anzahl von Instanzen für eine Aufzählung gibt.


Wenn Sie stattdessen ein Enum als class implementieren würden, würde es so aussehen:

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

Enumerationskonstanten sind technisch veränderbar, daher könnte ein Setter hinzugefügt werden, um die interne Struktur einer Enumerationskonstante zu ändern. Dies wird jedoch als sehr schlechte Praxis angesehen und sollte vermieden werden.

Es empfiehlt sich, Enum-Felder unveränderlich zu machen, mit final :

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

    private final int value;

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

    ...

}

Sie können mehrere Konstruktoren in derselben Enumeration definieren. Wenn Sie dies tun, entscheiden die Argumente, die Sie in Ihrer Enumendeklaration übergeben, welcher Konstruktor aufgerufen wird:

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;
    }

    ...

}

Hinweis: Alle nicht primitiven Enum-Felder sollten Serializable implementieren, da die Enum Klasse dies tut.

Verwendung von Methoden und statischen Blöcken

Eine Enumeration kann wie jede Klasse eine Methode enthalten. Um zu sehen, wie das funktioniert, erklären wir eine Enumeration wie folgt:

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

Wir haben eine Methode, die die Enumeration in die entgegengesetzte Richtung zurückgibt:

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;
        }
    }
}

Dies kann durch die Verwendung von Feldern und statischen Initialisierungsblöcken weiter verbessert werden:

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;
    }
}

In diesem Beispiel wird die entgegengesetzte Richtung in einem privaten Feld gespeichert Instanz opposite , der statisch das erste Mal , wenn eine Initialisierung Direction verwendet wird. In diesem speziellen Fall (weil NORTH auf SOUTH verweist und umgekehrt), können wir hier keine Enums mit Konstruktoren verwenden (Konstruktoren NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST) wären eleganter und würden das opposite zulassen deklariert wird final , würde aber selbstbezogen sein und daher nicht erlaubt).

Implementiert die Schnittstelle

Dies ist eine enum , die auch eine aufrufbare Funktion ist, die String Eingaben anhand vorkompilierter regulärer Ausdrucksmuster testet.

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"));
    }
}

Jedes Mitglied der Aufzählung kann auch die Methode implementieren:

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
    }
}

Enum Polymorphism Pattern

Wenn ein Verfahren benötigen einen „dehnbar“ Satz zu akzeptieren enum - Werte kann der Programmierer Polymorphismus wie auf einer normalen Anwendung class durch eine Schnittstelle zu schaffen , die anywere verwendet werden , wo die enum s verwendet werden soll:

public interface ExtensibleEnum {
    String name();
}

Auf diese Weise kann jedes mit der Schnittstelle versehene enum als Parameter verwendet werden, wodurch der Programmierer eine variable Menge von enum erstellen kann, die von der Methode akzeptiert werden. Dies kann beispielsweise in APIs nützlich sein, in denen es eine standardmäßige (nicht veränderbare) enum und der Benutzer dieser APIs die enum mit weiteren Werten "erweitern" möchte.

Ein Satz von Standardaufzählungswerten kann wie folgt definiert werden:

public enum DefaultValues implements ExtensibleEnum {
    VALUE_ONE, VALUE_TWO;
}

Zusätzliche Werte können dann wie folgt definiert werden:

public enum ExtendedValues implements ExtensibleEnum {
    VALUE_THREE, VALUE_FOUR;
}

Ein Beispiel, das zeigt, wie die Aufzählungen verwendet werden - beachten Sie, wie printEnum() Werte von beiden enum akzeptiert:

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

Hinweis: Dieses Muster hindert Sie nicht daran, Aufzählungswerte, die bereits in einer Aufzählung definiert sind, in einer anderen Aufzählung neu zu definieren. Diese Aufzählungswerte wären dann unterschiedliche Instanzen. Es ist auch nicht möglich, die Aufschalt-Aufzählung zu verwenden, da wir nur die Schnittstelle haben, nicht die eigentliche enum .

Aufzählungen mit abstrakten Methoden

Aufzählungen können abstrakte Methoden definieren, die jedes enum Mitglied zu implementieren ist nicht erforderlich.

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);
}

Dies ermöglicht jedem Enumerationsmitglied, sein eigenes Verhalten für eine bestimmte Operation zu definieren, ohne Typen in einer Methode in der Top-Level-Definition aktivieren zu müssen.

Beachten Sie, dass dieses Muster eine Kurzform dessen ist, was normalerweise durch Polymorphie und / oder Implementierung von Schnittstellen erreicht wird.

Dokumentation von Aufzählungen

Nicht immer ist der Name der enum klar genug, um verstanden zu werden. Um eine enum zu dokumentieren, verwenden Sie Standard-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;
    }
}

Die Werte einer Aufzählung erhalten

Jede Aufzählungsklasse enthält eine implizite statische Methode mit dem Namen values() . Diese Methode gibt ein Array zurück, das alle Werte dieser Enumeration enthält. Mit dieser Methode können Sie die Werte durchlaufen. Beachten Sie jedoch, dass diese Methode bei jedem Aufruf ein neues Array zurückgibt.

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());
        }
    }
}

Wenn Sie ein Set benötigen, können Sie auch EnumSet.allOf(Day.class) .

Aufzählung als beschränkter Typparameter

Beim Schreiben einer Klasse mit Generics in Java kann sichergestellt werden, dass der Typparameter eine Enumeration ist. Da alle Enumerationen die Enum Klasse erweitern, kann die folgende Syntax verwendet werden.

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

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

In diesem Beispiel ist der Typ T muss eine Enumeration sein.

Erhalte die Konstante nach Namen

Sagen wir, wir haben eine Aufzählung DayOfWeek :

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

Eine Enumeration wird mit einer integrierten statischen valueOf() Methode erstellt, mit der eine Konstante anhand ihres Namens valueOf() werden kann:

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

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

Dies ist auch mit einem dynamischen Aufzählungstyp möglich:

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

Beide valueOf() -Methoden IllegalArgumentException eine IllegalArgumentException wenn das angegebene Enum keine Konstante mit einem übereinstimmenden Namen hat.

Die Guava-Bibliothek stellt eine Enums.getIfPresent() , die ein Guava- Optional zurückgibt, um die explizite Ausnahmebehandlung zu beseitigen:

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

Implementieren Sie das Singleton-Muster mit einer Einzelelement-Enumeration

Aufzählungskonstanten werden instanziiert, wenn zum ersten Mal auf eine Aufzählung verwiesen wird. Daher ist es möglich, das Singleton- Softwaredesignmuster mit einer Einzelelement-Enumeration zu implementieren.

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
    }
}

Laut "Effective Java" von Joshua Bloch ist eine Einzelelement-Enumeration der beste Weg, um ein Singleton zu implementieren. Dieser Ansatz hat folgende Vorteile:

  • Fadensicherheit
  • Garantie für einzelne Instanziierung
  • Serienmäßige Serialisierung

Und wie in dem Abschnitt implements interface gezeigt , kann dieses Singleton auch eine oder mehrere Schnittstellen implementieren.

Aufzählung mit Eigenschaften (Feldern)

Für den Fall, dass wir enum mit mehr Informationen und nicht nur als konstanten Werten verwenden möchten, und wir möchten zwei enums vergleichen können.

Betrachten Sie das folgende Beispiel:

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;
    }

}

Hier haben wir ein Enum namens Coin das seinen Wert darstellt. Mit dem Verfahren isGreaterThan können wir zwei vergleichen enum s:

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

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

Konvertieren Sie Enum in String

Manchmal möchten Sie Ihr Enum in einen String konvertieren. Dafür gibt es zwei Möglichkeiten.

Angenommen, wir haben:

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

Wie konvertieren wir so etwas wie Fruit.APPLE in "APPLE" ?


Konvertieren mit name()

name() ist eine interne Methode in enum , die die String Darstellung der Enumeration zurückgibt. Die zurückgegebene String repräsentiert genau wie der enum-Wert definiert wurde.

Zum Beispiel:

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

Konvertieren mit toString()

toString() wird standardmäßig überschrieben, um dasselbe Verhalten wie name()

toString() wird jedoch wahrscheinlich von Entwicklern überschrieben, um einen benutzerfreundlicheren String drucken

Verwenden Sie toString() wenn Sie Ihren Code einchecken möchten. name() ist dafür wesentlich stabiler. Verwenden Sie toString() wenn Sie den Wert in Logs oder stdout oder etwas ausgeben möchten

Standardmäßig:

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

Beispiel dafür, überschrieben zu werden

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

Bestimmen Sie den spezifischen Körper

In einem enum ist es möglich , ein bestimmtes Verhalten für eine bestimmte Konstante des definieren enum , die das Standardverhalten des überschreibt enum wird diese Technik , bekannt als konstanter spezifischen Körper.

Angenommen, drei Klavierschüler - John, Ben und Luke - werden in einem enum namens PianoClass wie folgt definiert:

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

Und eines Tages kommen zwei andere Schüler - Rita und Tom - mit einem Geschlecht (weiblich) und einem Niveau (Mittelstufe) an, die nicht mit den vorherigen übereinstimmen:

    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
        }
    }

Daher ist es nicht korrekt, die neuen Schüler wie folgt der ständigen Deklaration hinzuzufügen:

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

Für jede der Konstanten Rita und Tom kann ein bestimmtes Verhalten definiert werden, das das Standardverhalten von PianoClass2 wie folgt überschreibt:

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";
    }
}

und jetzt sind Toms Niveau und Rita Geschlecht so, wie sie sein sollten:

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

Eine andere Möglichkeit, einen inhaltsspezifischen Körper zu definieren, ist beispielsweise der Konstruktor:

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

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

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

und Verwendung:

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

Null-Instanz-Aufzählung

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...
}

Genauso wie enum für Singletons (1 Instanzklassen) verwendet werden kann, kann es für Dienstprogrammklassen (0 Instanzklassen) verwendet werden. Stellen Sie sicher, dass Sie die (leere) Liste der Enumenkonstanten mit einem ; beenden ; .

Siehe die Frage Zero-Instanz-Aufzählung vs. private Konstruktoren, um die Instantiierung für eine Diskussion über Pro und Con gegenüber privaten Konstruktoren zu verhindern.

Aufzählungen mit statischen Feldern

Wenn für Ihre Enum-Klasse statische Felder erforderlich sind, denken Sie daran, dass sie nach den Enum-Werten selbst erstellt werden. Das heißt, der folgende Code führt zu einer NullPointerException :

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

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

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

Ein möglicher Weg, dies zu beheben:

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);
    }
}

Initialisieren Sie das statische Feld nicht:

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()));
    }
}

Initialisierung:

  • Erstellen Sie die Aufzählungswerte
    • Als Nebeneffekt wird putValue () aufgerufen, der Ganzzahlen initialisiert
  • Die statischen Werte werden eingestellt
    • ganze Zahlen = null; // wird nach der Aufzählung ausgeführt, damit der Inhalt von Ganzzahlen verloren geht

Vergleichen und Enthält für Aufzählungswerte

Enums enthält nur Konstanten und kann direkt mit == verglichen werden. Es ist also nur eine Referenzprüfung erforderlich, keine .equals Methode zu verwenden. Darüber hinaus kann es bei .equals Verwendung von .equals zu einer NullPointerException während dies bei == check nicht der Fall ist.

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!");
        }

    }
}

Um die EnumSet zu gruppieren, zu ergänzen, reichen wir die EnumSet Klasse, die verschiedene Methoden enthält.

  • EnumSet#range : Um eine Untermenge der Aufzählung nach einem durch zwei Endpunkte definierten EnumSet#range zu erhalten

  • EnumSet#of : Eine Reihe bestimmter Enumerationen ohne Bereich. Mehrere überlastet of Methoden gibt es.

  • EnumSet#complementOf : Eine Aufzählung, die die im Methodenparameter angegebenen Aufzählungswerte ergänzt

    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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow