Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5
Java ist auch eine Insel

Java ist auch eine Insel
5., akt. und erw. Auflage
1454 S., mit CD, 49,90 Euro
Galileo Computing
ISBN 3-89842-747-1
gp Kapitel 6 Eigene Klassen schreiben
  gp 6.1 Eigene Klassen definieren
    gp 6.1.1 Methodenaufrufe und Nebeneffekte
    gp 6.1.2 Argumentübergabe mit Referenzen
    gp 6.1.3 Die this-Referenz
    gp 6.1.4 Überdeckte Objektvariablen nutzen
  gp 6.2 Assoziationen zwischen Objekten
    gp 6.2.1 Gegenseitige Abhängigkeiten von Klassen
  gp 6.3 Privatsphäre und Sichtbarkeit
    gp 6.3.1 Wieso nicht freie Methoden und Variablen für alle?
    gp 6.3.2 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht
    gp 6.3.3 Zugriffsmethoden für Attribute definieren
  gp 6.4 Statische Methoden und statische Attribute
    gp 6.4.1 Warum statische Eigenschaften sinnvoll sind
    gp 6.4.2 Statische Eigenschaften mit static
    gp 6.4.3 Statische Eigenschaften über Referenzen nutzen?
    gp 6.4.4 Warum die Groß- und Kleinschreibung wichtig ist
    gp 6.4.5 Statische Eigenschaften und Objekteigenschaften
    gp 6.4.6 Statische Variablen zum Datenaustausch
    gp 6.4.7 Statische Blöcke als Klasseninitialisierer
  gp 6.5 Konstanten und Aufzählungen
    gp 6.5.1 Konstanten über öffentliche statische final-Variablen
    gp 6.5.2 Problem mit finalen Klassenvariablen
    gp 6.5.3 Typsicherere Konstanten
    gp 6.5.4 Aufzählungen mit enum in Java 5
    gp 6.5.5 enum-Konstanten in switch
  gp 6.6 Objekte anlegen und zerstören
    gp 6.6.1 Konstruktoren schreiben
    gp 6.6.2 Einen anderen Konstruktor der gleichen Klasse aufrufen
    gp 6.6.3 Initialisierung der Objekt- und Klassenvariablen
    gp 6.6.4 Finale Werte im Konstruktor und in statischen Blöcken setzen
    gp 6.6.5 Exemplarinitialisierer (Instanzinitialisierer)
    gp 6.6.6 Zerstörung eines Objekts durch den Müllaufsammler
    gp 6.6.7 Implizit erzeugte String-Objekte
    gp 6.6.8 Private Konstruktoren, Utility-Klassen, Singleton und Fabriken
  gp 6.7 Vererbung
    gp 6.7.1 Vererbung in Java
    gp 6.7.2 Einfach- und Mehrfachvererbung
    gp 6.7.3 Gebäude modelliert
    gp 6.7.4 Konstruktoren in der Vererbung
    gp 6.7.5 Sichtbarkeit protected
    gp 6.7.6 Das Substitutionsprinzip
    gp 6.7.7 Automatische und explizite Typanpassung
    gp 6.7.8 Typen testen mit dem binären Operator instanceof
    gp 6.7.9 Array-Typen und Kovarianz
    gp 6.7.10 Methoden überschreiben
    gp 6.7.11 Mit super eine Methode der Oberklasse aufrufen
    gp 6.7.12 Kovariante Rückgabetypen
    gp 6.7.13 Finale Klassen
    gp 6.7.14 Nicht überschreibbare Funktionen
    gp 6.7.15 Zusammenfassung zur Sichtbarkeit
    gp 6.7.16 Sichtbarkeit in der UML
    gp 6.7.17 Zusammenfassung: Konstruktoren und Methoden
  gp 6.8 Object ist die Mutter aller Oberklassen
    gp 6.8.1 Klassenobjekte
    gp 6.8.2 Objektidentifikation mit toString()
    gp 6.8.3 Objektgleichheit mit equals() und Identität
    gp 6.8.4 Klonen eines Objekts mit clone()
    gp 6.8.5 Hashcodes
    gp 6.8.6 Aufräumen mit finalize()
    gp 6.8.7 Synchronisation
  gp 6.9 Die Oberklasse gibt Funktionalität vor
    gp 6.9.1 Dynamisches Binden als Beispiel für Polymorphie
    gp 6.9.2 Keine Polymorphie bei privaten, statischen und finalen Methoden
    gp 6.9.3 Polymorphie bei Konstruktoraufrufen
  gp 6.10 Abstrakte Klassen und abstrakte Methoden
    gp 6.10.1 Abstrakte Klassen
    gp 6.10.2 Abstrakte Methoden
  gp 6.11 Schnittstellen
    gp 6.11.1 Ein Polymorphie-Beispiel mit Schnittstellen
    gp 6.11.2 Die Mehrfachvererbung bei Schnittstellen
    gp 6.11.3 Erweitern von Interfaces – Subinterfaces
    gp 6.11.4 Vererbte Konstanten bei Schnittstellen
    gp 6.11.5 Vordefinierte Methoden einer Schnittstelle
    gp 6.11.6 Abstrakte Klassen und Schnittstellen im Vergleich
    gp 6.11.7 CharSequence als Beispiel einer Schnittstelle
    gp 6.11.8 Die Schnittstelle Iterable
  gp 6.12 Innere Klassen
    gp 6.12.1 Statische innere Klassen und Schnittstellen
    gp 6.12.2 Mitglieds- oder Elementklassen
    gp 6.12.3 Lokale Klassen
    gp 6.12.4 Anonyme innere Klassen
    gp 6.12.5 this und Vererbung
    gp 6.12.6 Implementierung einer verketteten Liste
    gp 6.12.7 Funktionszeiger
  gp 6.13 Generische Datentypen
    gp 6.13.1 Einfache Klassenschablonen
    gp 6.13.2 Einfache Methodenschablonen
    gp 6.13.3 Umsetzen der Generics, Typlöschung und Raw-Types
    gp 6.13.4 Einschränken der Typen
    gp 6.13.5 Generics und Vererbung, Invarianz
    gp 6.13.6 Wildcards
  gp 6.14 Die Spezial-Oberklasse Enum
    gp 6.14.1 Methoden auf Enum-Objekten
    gp 6.14.2 enum mit eigenen Konstruktoren und Methoden
  gp 6.15 Dokumentationskommentare mit javaDoc
    gp 6.15.1 Einen Dokumentationskommentar setzen
    gp 6.15.2 Mit javadoc eine Dokumentation erstellen
    gp 6.15.3 HTML-Tags in Dokumentationskommentaren
    gp 6.15.4 Generierte Dateien
    gp 6.15.5 Weitere Dokumentationskommentare
    gp 6.15.6 javaDoc und Doclets
    gp 6.15.7 Veraltete (deprecated) Klassen, Konstruktoren und Methoden


Galileo Computing

6.14 Die Spezial-Oberklasse Enudowntop

Jedes Aufzählungs-Objekt erbt von der Spezialklasse Enum. Nehmen wir erneut die Musikstile:

enum Stil { ROCKPOPTECHNO }

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 sint i )
  {
    super( si );
  }

Galileo Computing

6.14.1 Methoden auf Enum-Objekten  downtop

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 Zähler gefragt werden.


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

gp  final 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.
gp  final String name() Liefert den Namen der Konstanten. Da die Methode – wie viele anderen der Klasse – final ist, lässt sich der Name nicht ändern.
gp  String toString() Liefert den Namen der Konstanten. Die Methode ruft standardisiert name() auf, weil sie aber nicht final ist, kann sie überschrieben werden.
gp  final int compareTo( E o ) Da die Enum-Klasse die Schnittstelle Comparable implementiert, gibt es auch die Funktion compareTo(). Sie vergleicht anhand der Ordinalzahlen. Vergleiche sind nur innerhalb eines Enum-Typs erlaubt.
gp  static <T extends Enum<T>> T valueOf( Class<T> enumType, String s ) 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.
gp  final Class<E> getDeclaringClass() Liefert das Class-Objekt zu diesem Enum.

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 ) {
    return1;
  }
}
Damit liefert gibOrdinal("POP") == 1 und gibOrdinal("CLASSIC") == –1.

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 { ROCKPOPTECHNO }
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, und das sind Singletons. 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, wofür der Vergleich mit == richtig ist. Ein equals() ist nicht nötig. Die Oberklasse Enum überschreibt equals() mit der Logik wie in Object – also den Referenzvergeleich –, um sie final zu markieren. Die Methode clone() ist final protected und kann also weder überschrieben noch von außen aufgerufen werden, so dass es Kopien der Enum-Objekte geben kann, die die Identität gefährden könnten. Nichts desto trotz darf clone() aber die this-Referenz liefern.


Galileo Computing

6.14.2 enum mit eigenen Konstruktoren und Methoden  toptop

Da eine emum-Klasse die Klassendefinition erweitert, kann sie zusätzlich Attribute und Methoden bekommen.

Listing 6.82   Country.java

import java.util.Locale;
public enum Country
{
  GERMANY( Locale.GERMANY )UK( Locale.UK )CHINA( Locale.CHINA );
  private Locale country;
  private Country( Locale country )
  {
    this.country = country;
  }
  public String getISO3Country()
  {
    return country.getISO3Country();
  }
}

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 country. Zusätzlich definiert das Beispiel eine Methode getISO3Country(), die auf den Enum-Objekten aufgerufen werden kann.

System.out.println( Country.CHINA.getISO3Country() ); // CHN

Da switch auf enum erlaubt ist, können wir schreiben:

Listing 6.83   CountryEnumDemo.java, Ausschnitt

Country meinLand = Country.GERMANY;
switch ( meinLand )
{
  case GERMANY:
    System.out.println( "Aha. Ein Krauti" );         // Aha. Ein Krauti
    System.out.println( meinLand.getISO3Country() ); // DEU
    break;
  default:      System.out.println( "Anderes Land" );
}

Enum mit überschriebenen Methoden

Definieren wir für Monate Aufzählungen in der Enum Month und bieten eine Methode getDays() für die Anzahl Tage im Monat an, dann hätten wir ein Problem mit dem Februar, weil die Anzahl der Tage bei einem Schaltjahr nicht die gleiche ist. In getDays() würden wir eine Berechnung abhängig vom Jahr benötigen. Im ersten Schritt fügen wir der Aufzählung eine Funktion getDays(int) hinzu, die die Jahreszahl akzeptiert. Die Methode ist zunächst genauso ohne Parameter implementiert wie getDays(). Java erlaubt uns aber, hinter den Konstantennamen eine Art innere anonyme Klasse zu hängen, die dann Methoden überschreiben kann.

Listing 6.84   Month.java

public enum Month
{
  JAN(31)FEB(28)
  {
    @Override public int getDays( int y )
    {
      return (y & 3) == 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;
  private Month( int days )
  {
    this.days = days;
  }
  public int getDays()
  {
    return days;
  }
  public int getDays( int year )
  {
    return days;
  }
}

In der Definition vom Februar überschreiben wir das Verhalten von getDays(int), sodass korrekt ausgegeben wird:

System.out.println( Month.FEB.getDays(2000) );    // 29
System.out.println( Month.FEB.getDays(2001) );    // 28

In der Klassendatei bildet der Eclipse-Compiler das wie folgt ab: Es gibt einen Konstruktor mit drei Parametern. Parametern der Enum-Namen, der Ordinalzahl und der Zahl der Tage.

Month( String sint iint j )
{
  super( si );
  days = j;
}

Für alle Monate bis auf den Februar kommt dieser Konstruktor zum Zuge. Für den Februar gibt es eine innere anonyme Klasse, die getDays() überschreibt, um das Jahr mit in die Berechung einzubeziehen. Die übergebene 28 würde eigentlich im Konstruktor nicht mehr gebraucht werden.

public static final Month JAN = new Month( "JAN"031 );
public static final Month FEB = new Month( "FEB"128 ) {
  private static final _cls1 ENUM$VALUES[];
  public int getDays( int y ) { return (y & 3) != 0 ? 28 : 29; }
};
public static final Month MAR = new Month( "MAR"231 );
...
 << zurück




Copyright © Galileo Press GmbH 2005
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de