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

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Exceptions
7 Äußere.innere Klassen
8 Besondere Klassen der Java SE
9 Generics<T>
10 Architektur, Design und angewandte Objektorientierung
11 Die Klassenbibliothek
12 Einführung in die nebenläufige Programmierung
13 Einführung in Datenstrukturen und Algorithmen
14 Einführung in grafische Oberflächen
15 Einführung in Dateien und Datenströme
16 Einführung in die <XML>-Verarbeitung mit Java
17 Einführung ins Datenbankmanagement mit JDBC
18 Bits und Bytes und Mathematisches
19 Die Werkzeuge des JDK
A Die Klassenbibliothek
Stichwort

Download:
- Aufgaben, ca. 1,1 MB
- Programme, ca. 12,8 MB

Buch bestellen
Ihre Meinung?

Spacer
Java ist auch eine Insel von Christian Ullenboom
Das umfassende Handbuch
Buch: Java ist auch eine Insel

Java ist auch eine Insel
Galileo Computing
1308 S., 10., aktualisierte Auflage, geb., mit DVD
ca. 49,90 Euro, ISBN 978-3-8362-1802-3
Pfeil 5 Eigene Klassen schreiben
Pfeil 5.1 Eigene Klassen mit Eigenschaften deklarieren
Pfeil 5.1.1 Attribute deklarieren
Pfeil 5.1.2 Methoden deklarieren
Pfeil 5.1.3 Die this-Referenz
Pfeil 5.2 Privatsphäre und Sichtbarkeit
Pfeil 5.2.1 Für die Öffentlichkeit: public
Pfeil 5.2.2 Kein Public Viewing – Passwörter sind privat
Pfeil 5.2.3 Wieso nicht freie Methoden und Variablen für alle?
Pfeil 5.2.4 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht *
Pfeil 5.2.5 Zugriffsmethoden für Attribute deklarieren
Pfeil 5.2.6 Setter und Getter nach der JavaBeans-Spezifikation
Pfeil 5.2.7 Paketsichtbar
Pfeil 5.2.8 Zusammenfassung zur Sichtbarkeit
Pfeil 5.3 Statische Methoden und statische Attribute
Pfeil 5.3.1 Warum statische Eigenschaften sinnvoll sind
Pfeil 5.3.2 Statische Eigenschaften mit static
Pfeil 5.3.3 Statische Eigenschaften über Referenzen nutzen? *
Pfeil 5.3.4 Warum die Groß- und Kleinschreibung wichtig ist *
Pfeil 5.3.5 Statische Variablen zum Datenaustausch *
Pfeil 5.3.6 Statische Eigenschaften und Objekteigenschaften *
Pfeil 5.4 Konstanten und Aufzählungen
Pfeil 5.4.1 Konstanten über öffentliche statische finale Variablen
Pfeil 5.4.2 Typ(un)sichere Aufzählungen *
Pfeil 5.4.3 Aufzählungen mit enum
Pfeil 5.5 Objekte anlegen und zerstören
Pfeil 5.5.1 Konstruktoren schreiben
Pfeil 5.5.2 Der vorgegebene Konstruktor (default constructor)
Pfeil 5.5.3 Parametrisierte und überladene Konstruktoren
Pfeil 5.5.4 Copy-Konstruktor
Pfeil 5.5.5 Einen anderen Konstruktor der gleichen Klasse mit this() aufrufen
Pfeil 5.5.6 Ihr fehlt uns nicht – der Garbage-Collector
Pfeil 5.5.7 Private Konstruktoren, Utility-Klassen, Singleton, Fabriken
Pfeil 5.6 Klassen- und Objektinitialisierung *
Pfeil 5.6.1 Initialisierung von Objektvariablen
Pfeil 5.6.2 Statische Blöcke als Klasseninitialisierer
Pfeil 5.6.3 Initialisierung von Klassenvariablen
Pfeil 5.6.4 Eincompilierte Belegungen der Klassenvariablen
Pfeil 5.6.5 Exemplarinitialisierer (Instanzinitialisierer)
Pfeil 5.6.6 Finale Werte im Konstruktor und in statischen Blöcken setzen
Pfeil 5.7 Assoziationen zwischen Objekten
Pfeil 5.7.1 Unidirektionale 1:1-Beziehung
Pfeil 5.7.2 Bidirektionale 1:1-Beziehungen
Pfeil 5.7.3 Unidirektionale 1:n-Beziehung
Pfeil 5.8 Vererbung
Pfeil 5.8.1 Vererbung in Java
Pfeil 5.8.2 Spielobjekte modellieren
Pfeil 5.8.3 Die implizite Basisklasse java.lang.Object
Pfeil 5.8.4 Einfach- und Mehrfachvererbung *
Pfeil 5.8.5 Die Sichtbarkeit protected
Pfeil 5.8.6 Konstruktoren in der Vererbung und super()
Pfeil 5.9 Typen in Hierarchien
Pfeil 5.9.1 Automatische und explizite Typanpassung
Pfeil 5.9.2 Das Substitutionsprinzip
Pfeil 5.9.3 Typen mit dem instanceof-Operator testen
Pfeil 5.10 Methoden überschreiben
Pfeil 5.10.1 Methoden in Unterklassen mit neuem Verhalten ausstatten
Pfeil 5.10.2 Mit super an die Eltern
Pfeil 5.10.3 Finale Klassen und finale Methoden
Pfeil 5.10.4 Kovariante Rückgabetypen
Pfeil 5.10.5 Array-Typen und Kovarianz *
Pfeil 5.11 Drum prüfe, wer sich ewig dynamisch bindet
Pfeil 5.11.1 Gebunden an toString()
Pfeil 5.11.2 Implementierung von System.out.println(Object)
Pfeil 5.11.3 Nicht dynamisch gebunden bei privaten, statischen und finalen Methoden
Pfeil 5.11.4 Dynamisch gebunden auch bei Konstruktoraufrufen *
Pfeil 5.11.5 Eine letzte Spielerei mit Javas dynamischer Bindung und überschatteten Attributen *
Pfeil 5.12 Abstrakte Klassen und abstrakte Methoden
Pfeil 5.12.1 Abstrakte Klassen
Pfeil 5.12.2 Abstrakte Methoden
Pfeil 5.13 Schnittstellen
Pfeil 5.13.1 Schnittstellen deklarieren
Pfeil 5.13.2 Implementieren von Schnittstellen
Pfeil 5.13.3 Markierungsschnittstellen *
Pfeil 5.13.4 Ein Polymorphie-Beispiel mit Schnittstellen
Pfeil 5.13.5 Die Mehrfachvererbung bei Schnittstellen *
Pfeil 5.13.6 Keine Kollisionsgefahr bei Mehrfachvererbung *
Pfeil 5.13.7 Erweitern von Interfaces – Subinterfaces
Pfeil 5.13.8 Konstantendeklarationen bei Schnittstellen
Pfeil 5.13.9 Initialisierung von Schnittstellenkonstanten *
Pfeil 5.13.10 Abstrakte Klassen und Schnittstellen im Vergleich
Pfeil 5.14 Zum Weiterlesen

Rheinwerk Computing - Zum Seitenanfang

5.12 Abstrakte Klassen und abstrakte MethodenZur nächsten Überschrift

Nicht immer soll eine Klasse sofort ausprogrammiert werden, zum Beispiel dann nicht, wenn die Oberklasse lediglich Methoden für die Unterklassen vorgeben möchte, aber nicht weiß, wie sie diese implementieren soll. In Java gibt es dazu zwei Konzepte: abstrakte Klassen und Schnittstellen (engl. interfaces).


Rheinwerk Computing - Zum Seitenanfang

5.12.1 Abstrakte KlassenZur nächsten ÜberschriftZur vorigen Überschrift

Bisher haben wir Vererbung eingesetzt, und jede Klasse konnte Objekte bilden. Das Bilden von Exemplaren ist allerdings nicht immer sinnvoll, zum Beispiel soll es untersagt werden, wenn eine Klasse nur als Oberklasse in einer Vererbungshierarchie existieren soll. Sie kann dann als Modellierungsklasse eine Ist-eine-Art-von-Beziehung ausdrücken und Signaturen für die Unterklassen vorgeben. Eine Oberklasse besitzt dabei Vorgaben für die Unterklasse. Das heißt, alle Unterklassen erben die Methoden. Ein Exemplar der Oberklasse selbst muss nicht existieren.

Um dies in Java auszudrücken, setzen wir den Modifizierer abstract an die Typdeklaration der Oberklasse. Von dieser Klasse können dann keine Exemplare gebildet werden, und der Versuch einer Objekterzeugung führt zu einem Compilerfehler. Ansonsten verhalten sich die abstrakten Klassen wie normale, enthalten die gleichen Eigenschaften und können auch selbst von anderen Klassen erben. Abstrakte Klassen sind das Gegenteil von konkreten Klassen.

Wir wollen die Klasse GameObject als Oberklasse für die Spielgegenstände abstrakt machen, da Exemplare davon nicht existieren müssen:

Listing 5.87: com/tutego/insel/game/vh/GameObject.java, GameObject

public abstract class GameObject
{
public String name;
}

Mit dieser abstrakten Klasse GameObject drücken wir aus, dass es eine allgemeine Klasse ist, zu der keine konkreten Objekte existieren. Es gibt in der realen Welt schließlich keine allgemeinen und unspezifizierten Spielgegenstände, sondern nur spezielle Unterarten, zum Beispiel Spieler, Schlüssel, Räume und so weiter. Es ergibt also keinen Sinn, ein Exemplar der Klasse GameObject zu bilden. Die Klasse soll nur in der Hierarchie auftauchen, um alle Spielobjekte zum Typ GameObject zu machen und ihnen einige Eigenschaften zu geben. Dies zeigt, dass Oberklassen allgemeiner gehalten sind und Unterklassen weiter spezialisieren.

Abbildung

Abbildung 5.28: In der UML werden die Namen abstrakter Klassen kursiv gesetzt.

Tipp

Abstrakte Klassen lassen sich auch nutzen, um zu verhindern, dass ein Exemplar der Klasse gebildet werden kann. Der Modifizierer abstract sollte aber dazu nicht eingesetzt werden. Besser ist es, die Sichtbarkeit des Konstruktors auf private oder protected zu setzen.

Basistyp abstrakte Klasse

Die abstrakten Klassen werden normalerweise in der Vererbung eingesetzt. Eine Klasse kann die abstrakte Klasse erweitern und dabei auch selbst wieder abstrakt sein. Auch gilt die Ist-eine-Art-von-Beziehung weiterhin, sodass sich schließlich Folgendes schreiben lässt:

Listing 5.88: com/tutego/insel/game/vh/Declarations.java, main()

GameObject   go1 = new Room();
GameObject
go2 = new Player();
GameObject[]
gos = { new Player(), new Room() };
Hinweis

Die Deklaration GameObject[] gos = { new Player(), new Room() } ist die Kurzform für GameObject[] gos = new GameObject[]{ new Player(), new Room() }. Wenn im Programmcode new GameObject[]{...} steht, kennzeichnet das nur den Typ des Feldes. Das ist unabhängig davon, ob die Klasse GameObject abstrakt ist oder nicht.


Rheinwerk Computing - Zum Seitenanfang

5.12.2 Abstrakte MethodenZur nächsten ÜberschriftZur vorigen Überschrift

Der Modifizierer abstract vor dem Schlüsselwort class leitet die Deklaration einer abstrakten Klasse ein. Eine Klasse kann ebenso abstrakt sein wie eine Methode. Eine abstrakte Methode gibt lediglich die Signatur vor, und eine Unterklasse implementiert irgendwann diese Methode. Die Klasse ist somit für den Kopf der Methode zuständig, während die Implementierung an anderer Stelle erfolgt. Abstrakte Methoden drücken aus, dass die Oberklasse keine Ahnung von der Implementierung hat und dass sich die Unterklassen darum kümmern müssen.

Da eine abstrakte Klasse abstrakte Methoden enthalten kann, aber nicht enthalten muss, unterscheiden wir:

  • Reine (pure) abstrakte Klassen: Die abstrakte Klasse enthält ausschließlich abstrakte Methoden.
  • Partiell abstrakte Klassen: Die Klasse ist abstrakt, enthält aber auch konkrete Implementierungen, also nicht abstrakte Methoden. Das bietet den Unterklassen ein Gerüst, das sie nutzen können.
Definition

Hat eine pure abstrakte Klasse nur eine Methode, so sprechen wir von einer SAM (für Single Abstract Method).

Mit Spielobjekten muss sich spielen lassen

Damit wir mit den Spielobjekten wie Tür, Schlüssel, Raum und Spieler wirklich spielen können, sollen die Objekte aufeinander angewendet werden können. Das Ziel unseres Programms ist es, Sätze abzubilden, die aus Subjekt, Verb und Objekt bestehen:

  • Schlüssel öffnet Tür.
  • Spieler nimmt Bier.
  • Pinsel kitzelt Spieler.
  • Radio spielt Musik.

Die Programmversion soll etwas einfacher sein und statt unterschiedlicher Aktionen (öffnen, nehmen, ...) nur »nutzen« kennen.

Zur Umsetzung dieser Aufgabe bekommen die Spielklassen wie Schlüssel, Spieler, Pinsel, Radio eine spezielle Methode, die ein anderes Spielobjekt nimmt und testet, ob sie aufeinander angewendet werden können. Ein Schlüssel öffnet eine Tür, aber »öffnet« keine Musik. Demnach kann ein Musik-Objekt nicht auf einem Tür-Objekt angewendet werden, wohl aber ein Schlüssel-Objekt. Ist die Anwendung möglich, kann die Methode weitere Aktionen ausführen, etwa Zustände setzen. Denn wenn der Schlüssel auf der Tür gültig ist, ist die Tür danach offen. Ob eine Operation möglich war oder nicht, soll eine Rückgabe aussagen.

Eine Methode in GameObject könnte somit folgende Signatur besitzen:

boolean useOn( GameObject object )

Die Operation useOn() soll auf dem eigenen Objekt das an die Methode übergebene Objekt nutzen. Implementiert die Schlüssel-Klasse useOn(), so kann sie testen, ob das GameObject eine Tür ist, und außerdem kann sie prüfen, ob Schlüssel und Tür zusammenpassen. Wenn ja, kann der Schlüssel die Tür öffnen, und die Rückgabe ist true, sonst false.

Da jede Spielobjekt-Klasse die Operation useOn() implementieren muss, soll die Basisklasse sie abstrakt deklarieren, denn eine abstrakte Methode fordert von den Unterklassen eine Implementierung ein, sonst ließen sich keine Exemplare bilden:

Listing 5.89: com/tutego/insel/game/vi/GameObject.java, GameObject

public abstract class GameObject
{
public String name;
public abstract boolean useOn( GameObject object );
}

Die Klasse GameObject deklariert eine abstrakte Methode, und da sie immer ohne Implementierung ist, steht statt des Methodenrumpfs ein Semikolon. Ist mindestens eine Methode abstrakt, so ist es automatisch die ganze Klasse. Deshalb müssen wir das Schlüsselwort abstract ausdrücklich vor den Klassennamen schreiben. Vergessen wir das Schlüsselwort abstract bei einer solchen Klasse, erhalten wir einen Compilerfehler. Eine Klasse mit einer abstrakten Methode muss abstrakt sein, da sonst irgendjemand ein Exemplar konstruieren und genau diese Methode aufrufen könnte. Versuchen wir, ein Exemplar einer abstrakten Klasse zu erzeugen, so bekommen wir ebenfalls einen Compilerfehler. Natürlich kann eine abstrakte Klasse nicht-abstrakte Eigenschaften haben, so wie es GameObject mit dem Attribut name zeigt. Konkrete Methoden sind auch erlaubt, die brauchen wir jedoch hier nicht. Eine toString()-Methode wäre vielleicht noch interessant, sie könnte dann auf name zurückgreifen.

Vererben von abstrakten Methoden

Wenn wir von einer Klasse abstrakte Methoden erben, so haben wir zwei Möglichkeiten:

  • Wir überschreiben alle abstrakten Methoden und implementieren sie. Dann muss die Unterklasse nicht mehr abstrakt sein (wobei sie es auch weiterhin sein kann). Von der Unterklasse kann es ganz normale Exemplare geben.
  • Wir überschreiben die abstrakte Methode nicht, sodass sie normal vererbt wird. Das bedeutet: Eine abstrakte Methode bleibt in unserer Klasse, und die Klasse muss wiederum abstrakt sein.

Die Unterklasse Door soll die abstrakte Methode useOn() überschreiben, aber immer false zurückgeben, da sich eine Tür in unserem Szenario auf nichts anwenden lässt. Nach dem Implementieren der abstrakten Methode sind Exemplare von Türen möglich:

Listing 5.90: com/tutego/insel/game/vi/Door.java, Door

public class Door extends GameObject
{
int id;
boolean isOpen;

@Override public boolean useOn( GameObject object )
{
return false;
}
}

Eine Tür hat für den Schlüssel eine ID, denn nicht jeder Schlüssel passt auf jedes Schloss. Weiterhin hat die Tür einen Zustand: Sie kann offen oder geschlossen sein.

Die dritte Klasse Key speichert ebenfalls eine ID und implementiert useOn():

Listing 5.91: com/tutego/insel/game/vi/Key.java, Key

public class Key extends GameObject
{
int id;

public @Override boolean useOn( GameObject object )
{
if ( object instanceof Door )
if ( id == ((Door) object).id )
return ((Door) object).isOpen = true;

return false;

}
}

Die Realisierung ist etwas komplexer. Als Erstes prüft die Methode mit instanceof, ob der Schlüssel auf eine Tür angewendet wird. Wenn ja, muss die ID von Schlüssel und Tür stimmen. Ist auch dieser Vergleich wahr, kann isOpen wahr werden, und die Methode liefert true.

Im Testprogramm wollen wir zwei Schlüssel auf eine Tür anwenden. Nur der Schlüssel mit der passenden ID öffnet die Tür. Eine Tür kann nicht auf einen Schlüssel angewendet werden, denn die Implementierungen sind nicht symmetrisch ausgelegt:

Listing 5.92: com/tutego/insel/game/vi/Playground.java, main()

Door door = new Door();
door.id = 12;

Key key1 = new Key();
key1.id = 99;

Key key2 = new Key();
key2.id = 12;

System.out.printf( "erfolgreich=%b%n", key1.useOn(door) );
System.out.printf( "erfolgreich=%b, isOpen=%b%n", key2.useOn(door), door.isOpen );
System.out.printf( "erfolgreich=%b%n", door.useOn(key1) );

Die Ausgaben sind:

erfolgreich=false
erfolgreich=true, isOpen=true
erfolgreich=false

Abbildung
Implementiert eine Klasse nicht alle geerbten abstrakten Methoden, so muss die Klasse selbst wieder abstrakt sein. Ist unsere Unterklasse einer abstrakten Basisklasse nicht abstrakt, so bietet Eclipse mit Strg + 1 an, entweder die eigene Klasse abstrakt zu machen oder alle geerbten abstrakten Methoden mit einem Dummy-Rumpf zu implementieren.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Java SE Bibliotheken






 Java SE Bibliotheken


Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Einstieg in Eclipse






 Einstieg in
 Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in
 Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2011
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