6.14 Die Spezial-Oberklasse Enum
 
Jedes Aufzählungs-Objekt erbt von der Spezialklasse Enum. Nehmen wir erneut die Musikstile:
enum Stil { ROCK, POP, TECHNO }
Der Compiler übersetzt dies in eine Klasse die in etwa beginnt mit:
class Stil extends Enum
{
public static final Stil ROCK = new Stil( "ROCK", 0 );
public static final Stil POP = new Stil( "POP", 1 );
public static final Stil TECHNO = new Stil( "TECHNO", 2 );
Stil( String s, int i )
{
super( s, i );
}
6.14.1 Methoden auf Enum-Objekten
 
Von der Oberklasse Enum erbt jede Aufzählung einen geschützten parametrisierten Konstruktor, der den Namen der Konstante sowie einen assoziierten Zähler erwartet. So wird aus jedem Element der Aufzählung ein Objekt vom Basistyp Enum, welches einen Namen und eine ID, die so genannte Ordinalzahl speichert. Natürlich kann es auch nach seinem Namen und nach seinem Zähler gefragt werden.
class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable
|
|
int ordinal()
Liefert die zur Konstante zugehörige ID. Im Allgemeinen ist diese Ordinalzahl nicht wichtig, aber besondere Datenstrukturen wie EnumSet oder EnumMap nutzen diese eindeutige ID. Die Reihenfolge der Zahlen ist durch die Reihenfolge der Definition gegeben. |
|
String name()
Liefert den Namen der Konstanten. toString() ruft lediglich name() auf. |
|
static <T extends Enum<T>> T valueOf( Class<T> enumType, String s )
Die Funktion ermöglicht das Suchen von Enum-Objekten zu einem Konstantennamen und einer Enum-Klasse. Sie liefert das enum-Objekt für die gegebene Zeichenfolge oder löst eine IllegalArgumentException aus, wenn dem String kein enum-Objekt zuzuordnen ist. |
Beispiel Eine Funktion, die die Ordinalzahl gibt, oder -1, wenn es die Konstante nicht gibt.
static int gibOrdinal( String name )
{
|
try {
return Stil.valueOf( name ).ordinal();
}
catch ( IllegalArgumentException e ) {
return -1;
}
}
Damit liefert gibOrdinal("POP") == 1 und gibOrdinal("CLASSIC") == -1.
|
Da die Enum-Klasse die Schnittstelle Comparable implementiert, gibt es auch die Funktion compareTo().
|
int compareTo( E o )
Vergleicht anhand der Ordinalzahlen. Nur Vergleiche innerhalb eines Enum-Typs sind erlaubt. |
Alle Konstanten der Klasse aufzählen
Eine besondere statische Funktion auf jeder Enum-Klasse ist values(). Sie liefert ein Feld von Enum-Objekten. Nützlich ist das für das erweiterte for, welches alle Konstanten aufzählen soll. Eine Alternative mit dem gleichen Ergebnis ist die Class-Methode getEnumConstants().
enum Stil { ROCK, POP, TECHNO }
for ( Stil e : Stil.values() )
// oder Stil.class.getEnumConstants()
System.out.println( "Name=" + e.name() );
Liefert Zeilen mit Name=ROCK, Name=POP, Name=TECHNO.
Auch toString() ist so implementiert, dass nur der Name ausgegeben wird. Das Ergebnis ist also mit name() identisch. Daher liefert
System.out.println( Stil.ROCK ); // auch "ROCK"
Vergleiche mit ==
Wie die Umsetzung der Enum-Typen zeigt, wird für jede Konstante ein Objekt konstruiert. Der Zugriff auf dieses Objekt ist wie ein Zugriff auf eine statische Variable. Der Vergleich zweier Konstanten läuft somit auf den Vergleich von statischen Referenzvariablen hinaus und dafür ist der Vergleich mit == richtig. Ein equals() ist denkbar, aber unnötig, denn zum einen implementiert eine konkrete Enum-Klasse gar kein equals(), sondern erbt es von Object und da werden sowie nur Referenzen verglichen und zum anderen lässt sich auch keine Kopie der Enum-Klassen machen, so dass die Identität gefährdet ist. Die Methode clone() ist nur protected und kann nicht aufgerufen werden.
6.14.2 enum mit eigenen Konstruktoren und Methoden
 
Da eine emum-Klasse die Klassendefinition erweitert, kann sie zusätzlich Attribute und Methoden bekommen.
enum Länder
{
deutschland( Locale.GERMANY ), england( Locale.UK ), china( Locale.CHINA );
private Locale land;
Länder( Locale land )
{
this.land = land;
}
}
Bei der Deklaration der Konstanten wird in runden Klammern ein Argument für den Konstruktor aufgerufen. Der speichert das zugehörige Locale-Objekt in der internen Variablen land. Da switch auf enum erlaubt ist, können wir schreiben:
Länder meinLand = Länder.deutschland;
switch ( meinLand )
{
case Länder.deutschland: System.out.println( "Aha. Ein Krauti" );
}
Zusätzlich lassen sich auch Methoden definieren, die auf den Enum-Objekten aufgerufen werden können. Betrachten wir dazu eine Klasse, die Monate repräsentiert. Jeder Monat hat eine bestimmte Anzahl von Tagen, die sich mit getDays() erfragen lassen sollte.
enum Month
{
JAN(31), FEB(28), MAR(31), APR(30), MAY(31), JUN(30),
JUL(31), AUG(31), SEP(30), OCT(31), NOV(30), DEC(31);
private int days;
Month( int days )
{
this.days = days;
}
int getDays()
{
return days;
}
}
Der Ausdruck Month.MAY.getDays() liefert wie gewünscht 31. Allerdings macht der Februar noch Kummer, denn die Anzahl der Tage ist bei einem Schaltjahr anders. Benötigt wäre in getDays() eine Berechung, abhängig vom Jahr. Im ersten Schritt fügen wir der Aufzählung eine Funktion getDays(int) hinzu, die die Jahreszahl akzeptiert. Die Methode ist erst einmal genauso implementiert wie auch getDays() ohne Parameter. Java erlaubt uns aber, hinter dem Konstantennamen eine Art innere anonyme Klasse zu hängen, die dann Methoden überschreiben kann.
enum Month
{
JAN(31), FEB(28)
{
int getDays( int y )
{
return y % 4 == 0 ? 29: 28;
}
},
MAR(31), APR(30), MAY(31), JUN(30),
JUL(31), AUG(31), SEP(30), OCT(31), NOV(30), DEC(31);
private int days;
Month( int days )
{
this.days = days;
}
int getDays()
{
return days;
}
int getDays( int year )
{
return days;
}
}
In der Definition vom Februar überschreien wir das Verhalten von getDays(int), so dass korrekt ausgegeben wird:
System.out.println( Month.FEB.getDays(2000) ); // 29
System.out.println( Month.FEB.getDays(2001) ); // 28
In der Klassendatei steht Ungewöhnliches. Einen wirklichen Konstruktor Month(int) gibt es nicht! Er weicht einem
Month( String s, int i, int j )
{
super( s, i );
days = j;
}
und Definitionen der Art
public static final Month JAN = new Month( "JAN", 0, 31 );
public static final Month FEB = new Month_2B_1( "FEB", 1, 28 );
Für den Februar gibt es tatsächlich eine innere anonyme Klasse.
|