javaseiten.de   |   Version 0.6
 

1.11. Aufzählungstypen (enums)

1.11.1. Grundlagen

Ein Aufzählungstyp (engl. enumeration type) kann als eine bestimmte Art einer normalen Klasse angesehen werden und wird mit Hilfe des Schlüsselwortes enum deklariert.

KlassenModifiers_opt enum EnumName {
  ...
}

Der Körper des Aufzählungstyps kann Enum-Konstanten enthalten. Für eine Enum-Konstante gilt: Eine Enum-Konstante definiert eine Instanz eines Aufzählungstyps. Diese Aussage soll im Laufe des Abschnitts näher erläutert werden. Zunächst soll der anschließende Java-Quelltext angegeben werden, der den Aufzählungstyp EnumExample definiert. Zwischen den geschweiften Klammern sind die vier Enum-Konstanten A, B, C und D notiert, die im Quelltext durch Kommata voneinander getrennt sind.

Listing 1.44. EnumExample.java. Deklaration des Aufzählungstyps EnumExample. Der Körper des Typs enthält die Enum-Konstanten A, B, C und D.

/* EnumExample.java */

public enum EnumExample {
  A, B, C, D
}

Der Zugriff auf Enum-Konstanten kann mit Hilfe einer Punktnotation erfolgen. Nach dem folgenden Muster kann der Variablen obj eine Instanz eines Aufzählungstyps bezüglich einer Enum-Konstanten zugewiesen werden (siehe dazu auch Abschnitt 1.11.2).

EnumName obj = EnumName.EnumKonstanteName

Die Deklaration eines Aufzählungstyps kann auch in den Körper einer normalen Klasse eingebettet werden. Das anschließende Beispiel zeigt diese Möglichkeit. Darin wird der Aufzählungstyp Character deklariert. Dieser wird direkt von der äußeren Klasse EnumExample2 umgeben. Der Aufzählungstyp bzw. die deklarierten Enum-Konstanten werden innerhalb einer switch-Anweisung verwendet, um den Buchstaben A bis D entsprechende Vornamen zuzuordnen.

Listing 1.45. EnumExample2.java. Der Aufzählungstyp Character wird innerhalb eines Klassenkörpers eingebettet.

/* EnumExample2.java */

public class EnumExample2 {
  
  public enum Character {
    A, B, C, D
  }
  
  public static String word(Character c) {
    String str ="";
    switch (c) {
      case A: str = "Alida";
              break;
      case B: str = "Ben";
              break;
      case C: str = "Clara";
              break;
      case D: str = "Dennis";
              break;
    }
    return str;
  }
  
  public static void main(String[] args) {
    Character c1 = Character.A;
    System.out.println(word(c1));
    System.out.println(Character.D + ": " + word(Character.D));
  }
}

Wie der Aufruf von javac EnumExample2.java zeigt, wird für den Aufzählungstyp die separate Klassendatei EnumExample2$Character.class generiert. Das Beispielprogramm gibt "Alida" und "D: Dennis" auf dem Bildschirm aus. Dabei wird deutlich, dass Character.D innerhalb der runden Klammern von println zur Ausgabe der Namensbezeichnung der entsprechenden Enum-Konstanten führt.

1.11.2. Interne Realisierung von Aufzählungstypen

Ein Aufzählungstyp kann als "aufgesetzter Typ" gesehen werden, der einem gewissen Konzept unterliegt. Der Bytecode (siehe dazu Abschnitt 4) der mit javac erstellten Klassendatei EnumExample.class kann untersucht werden, um die eigentliche Realisierung eines Aufzählungstypen festzustellen. Es kann ein geeignetes Programm (Disassembler, Decompiler) verwendet werden, um z.B. die Anzahl der Felder und Methoden festzustellen, welche in der erzeugten Klassendatei vorhanden sind. Durch die Bytecodeanalyse können die folgenden Informationen gewonnen werden:

Klasse:      public final enum EnumExample
Superklasse: java/lang/Enum

Feld: public static final enum EnumExample A
Feld: public static final enum EnumExample B
Feld: public static final enum EnumExample C
Feld: public static final enum EnumExample D
Feld: private static final synthetic EnumExample[] $VALUES

Konstruktor: private EnumExample(java/lang/String,int) {
               super(java/lang/String,int);
             }

Statischer Initialisierer: A = new EnumExample("A", 0)
                           B = new EnumExample("B", 1)
                           C = new EnumExample("C", 2)
                           D = new EnumExample("D", 3)
                           $VALUES = (new EnumExample[] { A, B, C, D })

Methode: public static EnumExample[] values()
Methode: public static EnumExample valueOf(java/lang/String)

Die Untersuchung von EnumExample.class zeigt, wie der Compiler Listing 1.44 auswertet bzw. welche Bytecoderepräsentation ein Aufzählungstyp besitzt. Aufgrund der durch die Bytecodeanalyse erhaltenen Informationen können die folgenden Aussagen getroffen werden:

  • Der Aufzählungstyp besitzt den Klassenmodifier final und ist mit dem Property-Modifier enum versehen. In der Klassendatei wird ein Bit (ACC_ENUM) an entsprechender Stelle gesetzt, falls eine Klasse als Aufzählungstyp deklariert ist.

  • Die Deklaration eines Aufzählungstyps definiert eine Klasse, deren direkte Superklasse die Klasse Enum ist. Enum befindet sich im Paket java.lang und ist die Basisklasse aller Aufzählungstypen. Die Klasse Enum erweitert wiederum die Wurzelklasse Object. Eine direkte Ableitung von Enum mit Hilfe der extends-Klausel ist nicht möglich und würde zu einer entsprechenden Fehlermeldung des Compilers führen ("classes cannot directly extend java.lang.Enum").

  • Die aus Listing 1.44 erzeugte Klassendatei enthält Bytecode für fünf Felder. Für die Enum-Konstanten A, B, C und D wird durch den Compiler ein entsprechendes Feld generiert. Die vier Felder besitzen jeweils die Modifier public, static und final. Zusätzlich ist innerhalb der Klassendatei jeweils das Bit ACC_ENUM (Property-Flag) für diese Felder gesetzt. Das gesetzte Bit zeigt an, dass das Feld für das Speichern einer Instanz des Aufzählungstyps vorgesehen ist. Das Feld $VALUES wird durch den Compiler zusätzlich erzeugt und ist deshalb mit synthetic bzw. einem gesetzten Bit (ACC_SYNTHETIC) innerhalb der Klassendatei versehen. $VALUES wird zur Realisierung des Aufzählungstyps zusätzlich benötigt.

  • Der Java-Compiler fügt weiterhin einen Konstruktor in die .class-Datei ein. Er ist mit dem Modifier private deklariert und besitzt zwei Parameter mit den Typen String und int. Die Aufgabe des automatisch generierten Konstruktors ist es, den entsprechenden Konstruktor der direkten Superklasse Enum aufzurufen - dies geschieht mit dem Schlüsselwort super.

     API  1.5
    
    java.lang
    Class Enum<E extends Enum<E>>
    
    Konstruktor:
      Enum(String name, int ordinal)

    Der genannte Kontruktor der Klasse Enum kann nur "intern" aufgerufen werden (sole constructor). Der Aufruf des Konstruktors erfolgt im Zusammenhang mit der Realisierung von Aufzählungstypen. Er besitzt die beiden Parameter name und ordinal. Dem Konstruktor können Name (z.B. A) und Ordinalzahl (Ordnungszahl) der jeweiligen Enum-Konstanten übergeben werden. Die Ordnungzahl gibt dabei die Position der Enum-Kontanten innerhalb der Deklaration des Aufzählungstypen an. Im Beispiel hat die Enum-Konstante A die Ordnungszahl 0 und die Ordnungszahl 1 bezieht sich auf B (der Namensbezeichnung Enum folgt innerhalb de API-Dokumentation ein Zusatz innerhalb von spitzen Klammern, siehe dazu Abschnitt 3 über Generics).

  • Die Klassendatei EnumExample.class enthält weiterhin einen statischen Initialisierer. Darin werden die Enum-Konstanten A, B, C und D initialisiert. Die Initialisierung erfolgt mit Hilfe des Schlüsselwortes new und einem entsprechenden Konstruktoraufruf. Dem Konstruktor werden jeweils zwei Argumente übergeben. Das erste Argument ist vom Typ String und ist die Namensbezeichnung der Enum-Konstanten (z.B. "A"). Als zweiter Wert wird die jeweilige Ordnungszahl der Enum-Konstanten übergeben. $VALUE wird mit einem EnumExample-Array initialisiert. Die Elemente des Arrays sind innerhalb der geschweiften Klammern enthalten und sind im Beispiel die Enum-Konstanten A, B, C und D.

  • Durch Compilierung des Beispiels EnumExample.java werden in die erzeugte Klassendatei automatisch die zwei zusätzlichen Methoden values und valueOf geschrieben. Die statischen Methoden geben Werte vom Typ EnumExample[] bzw. EnumExample zurück. Sie sollen an späterer Stelle mit Hilfe von Listing 1.47 erläutert werden.

1.11.3. Enum-Konstanten mit Argumenten

Es besteht die Möglichkeit Enum-Konstanten mit Argumenten zu deklarieren. Der Aufzählungstyp aus Listing 1.44 soll erweitert werden, indem den darin enthaltenen Enum-Konstanten A, B, C und D jeweils zwei Argumente zugeordnet werden. Die Argumente einer Enum-Konstanten können innerhalb runder Klammern notiert werden.

EnumKonstanteName(ArgumentListe_opt)

Mehrere Argumente werden durch ein Komma voneinander getrennt. Eine mögliche Erweiterung von EnumExample.java könnte angegeben werden zu:

/* Test.java */

public enum Test {
  A(1, 2), B(3, 4), C(5, 6), D(7, 8);
     
  private Test(int value1, int value2) {
  }
}

Die Enum-Konstante A besitzt z.B. als Argumente die Zahlen 1 und 2. Das kurze Testprogramm enthält weiterhin einen Konstruktor, dessen Parameteranzahl mit der Anzahl der Argumente der Enum-Konstanten übereinstimmt. Die Konstruktordeklaration ist notwendig, da ansonsten bei der Compilierung des Quelltextes eine Fehlermeldung erfolgt. Der Java-Übersetzer javac erzeugt zu dem im Quelltext stehenden Konstruktor einen "passenden" Konstruktor innerhalb der zugehörigen Klassendatei. Der "Bytecode-Konstruktor" enthält insgesamt vier Parameter - zusätzlich einen Parameter vom Typ String und einen vom Typ int. Der zusätzliche int-Parameter ist für die Ordinalzahl vorgesehen (siehe dazu Abschnitt 1.11.2). Der in Test.java angegebene bzw. notwendige Konstruktor ist ein Resultat des "Konzepts Aufzählungstyp". Der Konstruktor kann genutzt werden, um die erhaltenen beiden Argumente in entsprechende Felder zu speichern. Das folgende Listing enthält zusätzlich noch die beiden Methoden getValue1 und getValue2, mit denen die Werte der Felder value1 und value2 abgefragt werden können. Für die Werte dieser beiden Felder gilt: Sie sind Argumentwerte der Enum-Konstanten. Z.B. könen die Werte der Felder 1, 2 oder 3, 4 sein, abhängig von der Enum-Konstanten A oder B.

Listing 1.46. EnumExample3.java. Deklaration des Aufzählungstyps EnumExample3. Die Enum-Konstanten A, B, C und D besitzen jeweils zwei Argumente.

/* EnumExample3.java */

public enum EnumExample3 {
  A(1, 2), B(3, 4), C(5, 6), D(7, 8);
  
  private final int value1;
  private final int value2;
    
  private EnumExample3(int value1, int value2) {
    this.value1 = value1;
    this.value2 = value2;
  }
  
  public int getValue1() {
    return value1;
  }
  
  public int getValue2() {
    return value2;
  }
}

1.11.4. Implizite Methoden values und valueOf

Ein Aufzählungstyp, z.B. mit dem Namen E, deklariert implizit zwei statische Methoden. Die beiden Methoden values und valueOf werden einem erstellten Aufzählungstypen automatisch hinzugefügt (der Compiler übersetzt den Quelltext des Typen in eine Klassendatei, wobei der erzeugten Klassendatei diese zusätzlichen Methoden hinzugefügt werden).

static E[] values();
static E valueOf(String name);

Die Methode values gibt ein Array zurück, dessen Elemente die Enum-Konstanten des Aufzählungstyps sind. Durch Aufruf der statischen Methode valueOf wird diejenige Enum-Konstante zurückgegeben, die mit dem Parameter name spezifiziert ist. Der anschließende Quelltext beinhaltet diese beiden speziellen Methoden. Das Beispiel verwendet die Aufzählungstypen aus Listing 1.44 und Listing 1.46.

Listing 1.47. EnumExample4.java. Verwendung der Methoden values und valueOf.

/* EnumExample4.java */

public class EnumExample4 {
  
  public static void main(String[] args) {
    EnumExample[] ee = EnumExample.values();
    for (int i = 0; i < ee.length; i++) {
      System.out.println(ee[i]);
    }
    
    EnumExample3[] ee2 = EnumExample3.values();
    for (int j = 0; j < ee2.length; j++) {
      System.out.println(ee2[j] + ": " + 
                         ee2[j].getValue1() + ", " + 
                         ee2[j].getValue2());
    }
    
    EnumExample3 ee3 = EnumExample3.valueOf("B");
    System.out.println(ee3.getValue1() + ", " + ee3.getValue2());
  }
}

Nach Ausführung des Programms kann die folgende Ausgabe festgestellt werden:

A
B
C
D
A: 1, 2
B: 3, 4
C: 5, 6
D: 7, 8
3, 4

Die ersten vier Zeilen ergeben sich in Bezug auf den Aufzählungstyp EnumExample und beinhalten die Namensbezeichnungen der darin deklarierten Enum-Konstanten. Die anschließenden Zeilen beinhalten Informationen des Aufzählungstyps EnumExample3. In der letzten Zeile stehen die beiden Argumentwerte der Enum-Konstanten B, die mit Hilfe des Methodenaufrufs valueOf("B") abgefragt werden konnten.

 

 

 

Diese Seite nutzt Google-Dienste - siehe dazu Datenschutz.

Copyright © 2006, 2007 Harald Roeder