Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien zum Buch
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichen und Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Schnittstellen, Aufzählungen, versiegelte Klassen, Records
9 Ausnahmen müssen sein
10 Geschachtelte Typen
11 Besondere Typen der Java SE
12 Generics<T>
13 Lambda-Ausdrücke und funktionale Programmierung
14 Architektur, Design und angewandte Objektorientierung
15 Java Platform Module System
16 Die Klassenbibliothek
17 Einführung in die nebenläufige Programmierung
18 Einführung in Datenstrukturen und Algorithmen
19 Einführung in grafische Oberflächen
20 Einführung in Dateien und Datenströme
21 Einführung ins Datenbankmanagement mit JDBC
22 Bits und Bytes, Mathematisches und Geld
23 Testen mit JUnit
24 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 6 Eigene Klassen schreiben
Pfeil 6.1 Eigene Klassen mit Eigenschaften deklarieren
Pfeil 6.1.1 Objektvariablen deklarieren
Pfeil 6.1.2 Methoden deklarieren
Pfeil 6.1.3 Verdeckte (shadowed) Variablen
Pfeil 6.1.4 Die this-Referenz
Pfeil 6.2 Privatsphäre und Sichtbarkeit
Pfeil 6.2.1 Für die Öffentlichkeit: public
Pfeil 6.2.2 Kein Public Viewing – Passwörter sind privat
Pfeil 6.2.3 Wieso nicht freie Methoden und Variablen für alle?
Pfeil 6.2.4 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht *
Pfeil 6.2.5 Zugriffsmethoden für Objektvariablen deklarieren
Pfeil 6.2.6 Setter und Getter nach der JavaBeans-Spezifikation
Pfeil 6.2.7 Paketsichtbar
Pfeil 6.2.8 Zusammenfassung zur Sichtbarkeit
Pfeil 6.3 Eine für alle – statische Methoden und Klassenvariablen
Pfeil 6.3.1 Warum statische Eigenschaften sinnvoll sind
Pfeil 6.3.2 Statische Eigenschaften mit static
Pfeil 6.3.3 Statische Eigenschaften über Referenzen nutzen? *
Pfeil 6.3.4 Warum die Groß- und Kleinschreibung wichtig ist *
Pfeil 6.3.5 Statische Variablen zum Datenaustausch *
Pfeil 6.3.6 Statische Eigenschaften und Objekteigenschaften *
Pfeil 6.4 Konstanten und Aufzählungen
Pfeil 6.4.1 Konstanten über statische finale Variablen
Pfeil 6.4.2 Typunsichere Aufzählungen
Pfeil 6.4.3 Aufzählungstypen: typsichere Aufzählungen mit enum
Pfeil 6.5 Objekte anlegen und zerstören
Pfeil 6.5.1 Konstruktoren schreiben
Pfeil 6.5.2 Verwandtschaft von Methode und Konstruktor
Pfeil 6.5.3 Der Standard-Konstruktor (default constructor)
Pfeil 6.5.4 Parametrisierte und überladene Konstruktoren
Pfeil 6.5.5 Copy-Konstruktor
Pfeil 6.5.6 Einen anderen Konstruktor der gleichen Klasse mit this(…) aufrufen
Pfeil 6.5.7 Immutable-Objekte und Wither-Methoden
Pfeil 6.5.8 Ihr fehlt uns nicht – der Garbage-Collector
Pfeil 6.6 Klassen- und Objektinitialisierung *
Pfeil 6.6.1 Initialisierung von Objektvariablen
Pfeil 6.6.2 Statische Blöcke als Klasseninitialisierer
Pfeil 6.6.3 Initialisierung von Klassenvariablen
Pfeil 6.6.4 Eincompilierte Belegungen der Klassenvariablen
Pfeil 6.6.5 Exemplarinitialisierer (Instanzinitialisierer)
Pfeil 6.6.6 Finale Werte im Konstruktor und in statischen Blöcken setzen
Pfeil 6.7 Zum Weiterlesen
 

Zum Seitenanfang

6.4    Konstanten und Aufzählungen Zur vorigen ÜberschriftZur nächsten Überschrift

In Programmen gibt es Variablen, die sich ändern (wie zum Beispiel ein Schleifenzähler), aber auch andere, die sich beim Ablauf eines Programms nicht ändern. Dazu gehören etwa die Startzeit der Tagesschau oder die Maße einer DIN-A4-Seite. Die Werte sollten nicht wiederholt im Quellcode stehen, sondern über ihre Namen angesprochen werden. Dazu werden Variablen deklariert, denen genau der konstante Wert zugewiesen wird; die Konstanten heißen dann symbolische Konstanten.

In Java gibt es zur Deklaration von Konstanten zwei Möglichkeiten:

  • Selbst definierte öffentliche statische finale Variablen.

  • Aufzählungen über ein enum (die intern aber auch nur öffentliche finale statische Werte sind)

 

Zum Seitenanfang

6.4.1    Konstanten über statische finale Variablen Zur vorigen ÜberschriftZur nächsten Überschrift

Erinnern wir uns noch einmal an die Klasse City und die statische Variable:

public class City {



private static int KANDY_HERSHEY_DISTANCE = 124;

...

}

Die Variable kann jeder ändern, der Zugriff auf die Klasse City hat.

Statische Variablen werden auch verwendet, um symbolische Konstanten zu deklarieren. Damit die Variablen unveränderlich bleiben, gesellt sich der Modifizierer final hinzu. Dem Compiler wird auf diese Weise mitgeteilt, dass dieser Variablen nur einmal ein Wert zugewiesen werden darf. Für Variablen bedeutet dies: Es sind Konstanten; jeder erneute Schreibzugriff wäre ein Fehler. In der Regel sind die Konstanten öffentlich, aber natürlich können sie auch privat sein, wenn sie nur die Klasse etwas angehen.

public class City {



private static final int KANDY_HERSHEY_DISTANCE = 124;

...

}

Jetzt kann die Variable KANDY_HERSHEY_DISTANCE nur noch gelesen, aber später nicht mehr modifiziert werden. Der Zugriff auf die statische finale Variable sieht genauso aus wie ein Zugriff auf andere statische Variablen.

[+]  Tipp

Stehen Zahlen wie 124 ohne offensichtliche Bedeutung im Quellcode, so werden sie magische Zahlen (engl. magic numbers) genannt. Es gilt, diese Werte in Konstanten zu fassen und sinnvoll zu benennen. Wenn wir also den Abstand zwischen den beiden Städten Kandy und Hershey im Code benötigen, schreiben wir nicht 124, sondern KANDY_HERSHEY_DISTANCE. Es ist üblich, die Namen von Konstanten durchgehend großzuschreiben, um ihre Bedeutung hervorzuheben.

 

Zum Seitenanfang

6.4.2    Typunsichere Aufzählungen Zur vorigen ÜberschriftZur nächsten Überschrift

Konstanten sind eine wertvolle Möglichkeit, den Quellcode aussagekräftiger und klarer zu gestalten, was wichtig ist, denn Quellcode wird öfter gelesen als geschrieben. Oftmals finden sich Konstanten für mathematische Konstanten oder Größenbeschränkungen.

Eine besondere Form bilden Konstanten, wenn sie als Elemente von Aufzählungen verwendet werden. Aufzählungen erinnern an abgeschlossene Mengen, so wie:

  • Tage der Woche (Montag, Dienstag …)

  • Monate eines Jahrs (Januar, Februar …)

  • Font-Stile (fett, kursiv …)

  • vordefinierte Linienmuster (durchgezogen, gestrichelt …)

Die Tage der Woche und auch die Monate des Jahres werden zum Beispiel von der Klasse java. util.Calendar über öffentliche statische int-Konstanten angeboten.

[zB]  Beispiel

Die Frau wird im Juni schwanger. Wann müssen Windeln gekauft werden?

int month = Calendar.JUNE;

int conception = (month + 9) % 12;

System.out.println( conception ); // 2

Soll eine Klasse CandyType zum Beispiel Konstanten für die Beschaffenheit einer Süßigkeit deklarieren, kann das so aussehen:

Listing 6.26     src/main/java/com/tutego/insel/game/c/v9/CandyType.java, Ausschnitt

public class CandyType {

private CandyType() { } // Privater Konstruktor



public static final int OTHER = 0;

public static final int CARAMELS = 1;

public static final int CHOCOLATE = CARAMELS + 1;

public static final int GUMMIES = CHOCOLATE * 2;

}

Für ihre Belegungen ist es günstig, die Konstanten relativ zum Vorgänger zu wählen, um das Einfügen in der Mitte zu vereinfachen. Das sehen wir bei den Variablen CHOCOLATE und GUMMIES.

Problem mit dem Datentyp int als Konstantentyp

Einfache Konstantentypen – wie bei uns int – bringen mehrere Nachteile mit sich. Nehmen wir an, die Klasse Candy würde den Typ der Süßigkeit als Ganzzahl speichern:

Listing 6.27     src/main/java/com/tutego/insel/game/c/v9/CandyType.java, Ausschnitt

public class Candy {

public int price;

public int candyType;

}

Der erste Nachteil ist, dass die Konstanten nicht unbedingt von jedem angewendet werden müssen und Entwickler die Werte eventuell direkt einsetzen.

Listing 6.28     src/main/java/com/tutego/insel/game/c/v9/Application.java, Ausschnitt

Candy candy = new Candy();

candy.candyType = CandyType.CARAMELS; // so sollte es sein

candy.candyType = 1; // schlecht, aber möglich

candy.candyType = Cursor.DEFAULT_CURSOR // grausam, aber gültig

+ GridBagConstraints.PAGE_END / Character.LETTER_NUMBER;

candy.price = CandyType.CARAMELS ^ CandyType.GUMMIES; // SCHLUCK!

Das nächste Problem ist, wenn sich später die Belegung einer Konstanten einmal ändert. Bei einer Konstanten wie Math.PI wird das nicht passieren, aber beim Süßigkeitentyp könnte das passieren, wenn später ein neues Naschwerk eingeschoben wird. Das könnte später die ganze Logik durcheinanderbringen, wenn zum Beispiel CARAMELS nicht mehr 1, sondern später 2 wird, aber compilierte Programme den Süßigkeitentyp noch mit 1 vergleichen.

[»]  Hinweis

Ganzzahlen haben aber durchaus ihren Vorteil, wenn es verknüpfte Aufzählungen gibt, also etwa eine Süßigkeit, die karamellig und schokoladig ist, so was soll’s geben. Das lässt sich durch CARAMELS + CHOCOLATE darstellen – was aber nur dann gut funktioniert, wenn jede Konstante ein Bit im Wort einnimmt, wenn also die Werte der Konstanten 1, 2, 4, 8, 16 … sind. Und genau so wurden die Werte auch vorbereitet.

Fassen wir zusammen: Konstanten sind nur Namen für Werte, und bei der Auswertung bleibt es bei dem Wert. Niemand kann verbieten, diese Werte direkt zu übermitteln. Mit Zeichenketten als Werte der Konstanten kommen wir der Lösung auch nicht näher.

Eine gute Möglichkeit, von Ganzzahlen oder Strings wegzukommen, besteht darin, Objekte einer Klasse als Konstanten einzusetzen. Hier muss nicht auf eigene Klassendeklarationen zurückgegriffen werden, sondern Java bietet ein eigenes Sprachmittel.

 

Zum Seitenanfang

6.4.3    Aufzählungstypen: typsichere Aufzählungen mit enum Zur vorigen ÜberschriftZur nächsten Überschrift

Damit Konstanten von Aufzählungen einen eigenen Typ bekommen und nicht mehr Ganzzahlen oder Strings sind, bietet Java ein Sprachkonstrukt über das Schlüsselwort enum. Die Schreibweise für Aufzählungen erinnert ein wenig an die Deklaration von Klassen und Variablen, nur dass das Schlüsselwort enum statt class gebraucht wird und dass die Variablen automatisch statisch und öffentlich sind und kein Typ angegeben ist. Java selbst deklariert schon viele Aufzählungstypen, etwa für Wochentage, doch wir wollen für den Typ von Süßigkeiten einen Aufzählungstyp CandyType einführen:

Listing 6.29     src/main/java/com/tutego/insel/game/c/va/CandyType.java, Ausschnitt

public enum CandyType {

CARAMELS, CHOCOLATE, GUMMIES, OTHER

}

Die Konstantennamen werden üblicherweise großgeschrieben – so wie auch statische Variablen, die als Konstanten benutzt werden, großgeschrieben werden.

Eine Aufzählung in UML wird über den Stereotyp ausgedrückt.

Abbildung 6.11     Eine Aufzählung in UML wird über den Stereotyp ausgedrückt.

Aufzählungen nutzen

Um zu verstehen, wie sich Aufzählungstypen nutzen lassen, ist es hilfreich, zu wissen, wie der Compiler sie umsetzt. Intern erstellt der Compiler eine normale Klasse, in unserem Fall CandyType. Alle Aufzählungselemente sind statische Variablen (Konstanten) vom Typ der Aufzählung:

public class CandyType {

public static final CandyType CARAMELS = new CandyType( ... );

public static final CandyType CHOCOLATE = new CandyType( ... );

...

}

Beim Laden der Klasse werden vier CandyType-Objekte erzeugt und die statischen Variablen CARAMELS, CHOCOLATE, GUMMIES, OTHER initialisiert. Jetzt ist es einfach, diese Aufzählungen zu nutzen, da sie wie jede andere statische Variable angesprochen werden:

CandyType amedei = CandyType.CHOCOLATE;

Hinter den Aufzählungen stehen Objekte, die sich – wie alle anderen – weiterverarbeiten lassen.

if ( amedei == CandyType.CHOCOLATE )

System.out.println( "Uff, das ist aber teuer" );

Auch implementieren die enum-Konstanten die toString()-Methode, die den Namen der Konstanten liefert.

[»]  Geschichte

Sun reservierte zu Beginn der Entwicklung von Java diverse Schlüsselwörter, aber enum war nicht seit Beginn dabei. Als dann in Java 5 plötzlich ein neues Schlüsselwort hinzukam, mussten Entwickler viel Quellcode anpassen und Variablennamen ändern, denn für den Variablentyp java.util.Enumeration war gern der Variablenname enum gewählt worden.

Aufzählungsvergleiche mit ==

Wie die Umsetzung der Aufzählungstypen zeigt, wird für jede Konstante ein Objekt konstruiert, und das sind sogenannte Singletons, also Objekte, die nur einmal erzeugt werden. Eigene neue Aufzählungsobjekte können wir nicht aufbauen, da die Klasse nur einen privaten Konstruktor deklariert. 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 == völlig korrekt ist. Ein equals(…) ist nicht nötig.

[zB]  Beispiel

Eine Methode soll entscheiden, ob eine Süßigkeit unbekannt (OTHER) ist:

public static boolean isUnknownCandyType( CandyType type ) {

return type == CandyType.OTHER;

}

enum-Konstanten in switch

enum-Konstanten sind in switch-Anweisungen möglich.[ 151 ](Das ist möglich, da sie intern über eine Ganzzahl als Identifizierer verfügen, den der Compiler für die Aufzählung einsetzt. Das ist ein ähnliches Konzept, wie es der Compiler auch bei switch auf Strings verfolgt. ) Initialisieren wir eine Variable vom Typ CandyType, und nutzen wir eine Fallunterscheidung mit der Aufzählung für einen Test auf zwei Süßigkeitstypen:

Listing 6.30     src/main/java/com/tutego/insel/game/c/va/Application.java, Ausschnitt

CandyType werther = CandyType.CARAMELS;

switch ( werther ) {

case CARAMELS: // nicht CandyType.CARAMELS!

case CHOCOLATE: System.out.println( "karamellig/schokoladig" );

}

Dass case CandyType.CARAMELS nicht möglich ist, erklärt sich dadurch, dass mit switch (werther) schon der Typ CandyType über die Variable werther bestimmt ist. Es ist nicht möglich, dass der Typ der switch-Variablen vom Typ der Variablen in case abweicht.

Referenzen vom Aufzählungstyp können null sein

Dass die Aufzählungen nur Objekte sind, hat eine wichtige Konsequenz. Blicken wir zunächst auf die Variablendeklaration type vom Aufzählungstyp, die mit einer Referenz initialisiert ist:

CandyType type = CandyType.CARAMELS;

Die Variable type speichert einen Verweis auf das CandyType.CARAMELS-Objekt. Das Unschöne an Referenzvariablen ist allerdings, dass sie auch mit null belegt werden können, was so gesehen kein Element der Aufzählung ist:

CandyType type = null;

Wenn solch eine null-Referenz in einem switch landet, gibt es eine NullPointerException, da versteckt im switch ein Zugriff auf die im Enum-Objekt gespeicherte Ordinalzahl stattfindet.

Methoden, die Elemente einer Aufzählung – also Objektverweise – entgegennehmen, sollten im Allgemeinen auf null testen und eine Ausnahme auslösen, um diesen fehlerhaften Teil anzuzeigen; das kann die gegebene Hilfsmethode Objects.requireNonNull(…) übernehmen:

Listing 6.31     src/main/java/com/tutego/insel/game/c/va/Candy.java, Ausschnitt

public class Candy {



private CandyType type;



public void setType( CandyType type ) {

this.type = Objects.requireNonNull( type, "CandyType can't be null" );

}



public CandyType getCandyType() {

return type;

}

}

Aufzählungstypen als geschachtelten Typ deklarieren *

Neue Aufzählungstypen können auch in andere Typdeklarationen hineingesetzt werden; wir sprechen von »geschachtelten« Typen. Mit anderen Worten: CandyType kann auch innerhalb einer anderen Klasse bzw. anderen Schnittstelle deklariert werden. Ist die geschachtelte Aufzählung öffentlich, kann jeder sie nutzen. Sie folgt aber den gleichen Sichtbarkeiten wie Klassen, da Aufzählungen ja nichts anderes als Klassen sind, die der Compiler generiert. Aufzählungen innerhalb von Typen sind immer implizit statisch, das Schlüsselwort static ist also nicht nötig.

[zB]  Beispiel

Ein in Candy geschachtelter Typ CandyType:

public class Candy {

public /* static */ enum CandyType {

CARAMELS, CHOCOLATE, GUMMIES, OTHER

}

}

Statische Importe von Aufzählungen *

Die enum-Konstanten sind statische Variablen und können auf unterschiedliche Weise angesprochen werden. Nehmen wir noch einmal CandyType in einer eigenen Compilationseinheit:

Listing 6.32     src/main/java/com/tutego/insel/game/enums/CandyType.java

package com.tutego.insel.game.enums;



public enum CandyType {

CARAMELS, CHOCOLATE, GUMMIES, OTHER

}

Die Aufzählung CandyType liegt im Paket com.tutego.insel.game.enums. Um auf eine Konstante wie CARAMELS zugreifen zu können, lassen sich unterschiedliche import-Varianten einsetzen:

Import-Deklaration

Zugriff

import com.tutego.insel.game.enums.CandyType

CandyType.CARAMELS

import com.tutego.insel.game.enums.*

CandyType.CARAMELS

import static com.tutego.insel.game.enums.CandyType.*

CARAMELS

Tabelle 6.5     »import«-Deklarationen und Zugriffsvarianten, Top-Level enum

Nehmen wir im Paket als zweites Beispiel eine geschachtelte Aufzählung der Klasse Candy hinzu:

Listing 6.33     src/main/java/com/tutego/insel/game/enums/CandyType.java

package com.tutego.insel.game.enums;



public class Candy {

public enum CandyType {

CARAMELS, CHOCOLATE, GUMMIES, OTHER

}

}

Import-Deklaration

Zugriff

import com.tutego.insel.game.enums.Candy

Candy.CandyType.CARAMELS

import com.tutego.insel.game.enums.Candy.CandyType

CandyType.CARAMELS

import static com.tutego.insel.game.enums.Candy.CandyType.*

CARAMELS

Tabelle 6.6     import-Deklarationen und Zugriffsvarianten, geschachtelte enum

Standardmethoden der Aufzählungstypen *

Die erzeugten Aufzählungsobjekte bekommen standardmäßig eine Reihe von zusätzlichen Eigenschaften. Sie überschreiben sinnvoll toString(), hashCode() und equals(…) aus Object und implementieren zusätzlich Serializable und Comparable,[ 152 ](Die Ordnung der Konstanten ist die Reihenfolge, in der sie geschrieben sind. ) aber nicht Cloneable, da Aufzählungsobjekte nicht geklont werden können. Die Methode toString() liefert den Namen der Konstanten, sodass CandyType.CARAMELS.toString().equals("CARAMELS") wahr ist. Zusätzlich erbt jedes Aufzählungsobjekt von der Spezialklasse EnumAbschnitt 8.2, »Aufzählungstypen«, zeigt detaillierter die Möglichkeiten.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Spring Boot 3 und Spring Framework 6

Spring Boot 3 und Spring Framework 6




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2024

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.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern