Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Download: - ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /Java-Insel | vor >>
Java ist auch eine Insel von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel 7., aktualisierte Auflage geb., mit DVD (November 2007) 1.492 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1146-8 |
| 6 Eigene Klassen schreiben
|  | 6.1 Eigene Klassen mit Eigenschaften deklarieren
|  |  | 6.1.1 Attribute deklarieren
|  |  | 6.1.2 Methoden deklarieren
|  |  | 6.1.3 Die this-Referenz
|  | 6.2 Privatsphäre und Sichtbarkeit
|  |  | 6.2.1 Für die Öffentlichkeit: public
|  |  | 6.2.2 Paketsichtbar
|  |  | 6.2.3 Kein Public Viewing – Passwörter sind privat
|  |  | 6.2.4 Wieso nicht freie Methoden und Variablen für alle?
|  |  | 6.2.5 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht
|  |  | 6.2.6 Zugriffsmethoden für Attribute deklarieren
|  |  | 6.2.7 Setter und Getter nach der JavaBeans-Spezifikation
|  | 6.3 Statische Methoden und statische Attribute
|  |  | 6.3.1 Warum statische Eigenschaften sinnvoll sind
|  |  | 6.3.2 Statische Eigenschaften mit static
|  |  | 6.3.3 Statische Eigenschaften über Referenzen nutzen?
|  |  | 6.3.4 Warum die Groß- und Kleinschreibung wichtig ist
|  |  | 6.3.5 Statische Eigenschaften und Objekteigenschaften
|  |  | 6.3.6 Statische Variablen zum Datenaustausch
|  |  | 6.3.7 Statische Blöcke als Klasseninitialisierer
|  | 6.4 Konstanten und Aufzählungen
|  |  | 6.4.1 Konstanten über öffentliche statische finale Variablen
|  |  | 6.4.2 Eincompilierte Belegungen der Klassenvariablen
|  |  | 6.4.3 Typ(un)sicherere Aufzählungen
|  |  | 6.4.4 Aufzählungen mit enum
|  | 6.5 Objekte anlegen und zerstören
|  |  | 6.5.1 Konstruktoren schreiben
|  |  | 6.5.2 Der Standard-Konstruktor
|  |  | 6.5.3 Parametrisierte und überladene Konstruktoren
|  |  | 6.5.4 Konstruktor nimmt ein Objekt vom eigenen Typ an (Copy-Konstruktor)
|  |  | 6.5.5 Einen anderen Konstruktor der gleichen Klasse aufrufen
|  |  | 6.5.6 Initialisierung der Objekt- und Klassenvariablen
|  |  | 6.5.7 Finale Werte im Konstruktor und in statischen Blöcken setzen
|  |  | 6.5.8 Exemplarinitialisierer (Instanzinitialisierer)
|  |  | 6.5.9 Ihr fehlt uns nicht – der Garbage-Collector
|  |  | 6.5.10 Implizit erzeugte String-Objekte
|  |  | 6.5.11 Private Konstruktoren, Utility-Klassen, Singleton, Fabriken
|  | 6.6 Assoziationen zwischen Objekten
|  |  | 6.6.1 Unidirektionale 1:1-Beziehung
|  |  | 6.6.2 Bidirektionale 1:1-Beziehungen
|  |  | 6.6.3 Unidirektionale 1:n-Beziehung
|  | 6.7 Vererbung
|  |  | 6.7.1 Vererbung in Java
|  |  | 6.7.2 Spielobjekte modelliert
|  |  | 6.7.3 Einfach- und Mehrfachvererbung
|  |  | 6.7.4 Sichtbarkeit protected
|  |  | 6.7.5 Konstruktoren in der Vererbung und super
|  |  | 6.7.6 Automatische und explizite Typanpassung
|  |  | 6.7.7 Das Substitutionsprinzip
|  |  | 6.7.8 Typen mit dem binären Operator instanceof testen
|  |  | 6.7.9 Methoden überschreiben
|  |  | 6.7.10 Mit super an die Eltern
|  |  | 6.7.11 Kovariante Rückgabetypen
|  |  | 6.7.12 Array-Typen und Kovarianz
|  |  | 6.7.13 Zusammenfassung zur Sichtbarkeit
|  | 6.8 Dynamisches Binden
|  |  | 6.8.1 Unpolymorph bei privaten, statischen und finalen Methoden
|  |  | 6.8.2 Polymorphie bei Konstruktoraufrufen
|  |  | 6.8.3 Finale Klassen
|  |  | 6.8.4 Nicht überschreibbare (finale) Methoden
|  | 6.9 Abstrakte Klassen und abstrakte Methoden
|  |  | 6.9.1 Abstrakte Klassen
|  |  | 6.9.2 Abstrakte Methoden
|  | 6.10 Schnittstellen
|  |  | 6.10.1 Deklarieren von Schnittstellen
|  |  | 6.10.2 Implementieren von Schnittstellen
|  |  | 6.10.3 Markierungsschnittstellen
|  |  | 6.10.4 Ein Polymorphie-Beispiel mit Schnittstellen
|  |  | 6.10.5 Die Mehrfachvererbung bei Schnittstellen
|  |  | 6.10.6 Keine Kollisionsgefahr bei Mehrfachvererbung
|  |  | 6.10.7 Erweitern von Interfaces – Subinterfaces
|  |  | 6.10.8 Vererbte Konstanten bei Schnittstellen
|  |  | 6.10.9 Schnittstellenmethoden, die nicht implementiert werden müssen
|  |  | 6.10.10 Abstrakte Klassen und Schnittstellen im Vergleich
|  | 6.11 Geschachtelte (innere) Klassen, Schnittstellen, Aufzählungen
|  |  | 6.11.1 Statische innere Klassen und Schnittstellen
|  |  | 6.11.2 Mitglieds- oder Elementklassen
|  |  | 6.11.3 Lokale Klassen
|  |  | 6.11.4 Anonyme innere Klassen
|  |  | 6.11.5 this und Vererbung
|  | 6.12 Generische Datentypen
|  |  | 6.12.1 Einfache Klassenschablonen
|  |  | 6.12.2 Einfache Methodenschablonen
|  |  | 6.12.3 Umsetzen der Generics, Typlöschung und Raw-Types
|  |  | 6.12.4 Einschränken der Typen
|  |  | 6.12.5 Generics und Vererbung, Invarianz
|  |  | 6.12.6 Wildcards
|  | 6.13 Die Spezial-Oberklasse Enum
|  |  | 6.13.1 Methoden auf Enum-Objekten
|  |  | 6.13.2 enum mit eigenen Konstruktoren und Methoden
|  | 6.14 Dokumentationskommentare mit JavaDoc
|  |  | 6.14.1 Einen Dokumentationskommentar setzen
|  |  | 6.14.2 Mit javadoc eine Dokumentation erstellen
|  |  | 6.14.3 HTML-Tags in Dokumentationskommentaren
|  |  | 6.14.4 Generierte Dateien
|  |  | 6.14.5 Dokumentationskommentare im Überblick
|  |  | 6.14.6 JavaDoc und Doclets
|  |  | 6.14.7 Veraltete (deprecated) Klassen, Konstruktoren und Methoden
## 6.9 Abstrakte Klassen und abstrakte Methoden Nicht immer soll eine Klasse sofort ausprogrammiert werden. Dies ist der Fall, 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). ### 6.9.1 Abstrakte Klassen Bisher haben wir Vererbung eingesetzt, und jede Klasse konnte Objekte bilden. Das ist allerdings nicht immer sinnvoll, nämlich genau dann, wenn eine Klasse nur 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 6.75 com/tutego/insel/game/vh/GameObject.java, GameObject
    abstract class GameObject
    {
      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. Hier klicken, um das Bild zu vergrößern Abbildung 6.3 In der UML werden abstrakte Klassennamen kursiv gesetzt. Die abstrakten Klassen werden normal in der Vererbung eingesetzt. Eine Klasse kann die abstrakte Klasse erweitern und auch selbst wieder abstrakt sein. Problemlos lässt sich wieder Folgendes schreiben:
    GameObject   go1 = new Room();
    GameObject   go2 = new Player();
    GameObject[] gos = new GameObject[]{ new Player(), new Room() };
Hinweis 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.
### 6.9.2 Abstrakte Methoden 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 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, was sie nutzen können. #### Mit Spielobjekten muss sich spielen lassen Damit sich mit den Spielobjekten wie Tür, Schlüssel, Raum, Spieler wirklich spielen lässt, sollen die Objekte aufeinander angewendet werden können. Ziel unseres Programms ist es, Sätze abzubilden, die aus Subjekt, Verb, 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 Funktion, die ein anderes Spielobjekt nehmen und testen, dass sie aufeinander angewendet werden können. Ein Schlüssel öffnet insofern eine Tür, aber keine Musik. Ist die Anwendung möglich, kann die Methode weitere Aktionen ausführen, etwa Zustände setzen. Ob eine Operation möglich war oder nicht, soll eine Rückgabe aussagen. Eine Java-Funktion 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 weiterhin 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 6.76 com/tutego/insel/game/vi/GameObject.java, GameObject
    abstract class GameObject
    {
      abstract boolean useOn( GameObject object );
    }
Die Klasse GameObject deklariert eine abstrakte Methode, und da sie immer ohne Implementierung ist, steht ein Semikolon statt des Funktions-Rumpfes. Ist mindestens eine Methode abstrakt, so ist es automatisch die ganze Klasse. Deshalb müssen wir das Schlüsselwort ab-stract ausdrücklich vor den Klassennamen schreiben. Vergessen wir das Schlüsselwort ab-stract 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. Hier klicken, um das Bild zu vergrößern Abbildung 6.4 Auch abstrakte Methoden werden in UML kursiv gesetzt. #### Vererben von abstrakten Methoden Wenn wir von einer Klasse abstrakte Methoden erben, so haben wir zwei Möglichkeiten:
1. | 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.
2. | 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 6.77 com/tutego/insel/game/vi/Door.java, Door
    public class Door extends GameObject
    {
      int     id;
      boolean isOpen;

      @Override 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 6.78 com/tutego/insel/game/vi/Key.java, Key
    public class Key extends GameObject
    {
      int id;

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

        return false;
      }
    }
Die Realisierung ist 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 gehen zwei Schlüssel eine Tür an. 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 Funktionen sind nicht symmetrisch ausgelegt. Listing 6.79 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( "done=%b%n", key1.useOn(door) );
    System.out.printf( "done=%b, isOpen=%b%n", key2.useOn(door), door.isOpen );
    System.out.printf( "done=%b%n", door.useOn(key1) );
Die Ausgaben sind:
    done=false
    done=true, isOpen=true
    done=false
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 + 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.
Name |
E-Mail |
Ihr Kommentar |
<< zurück | <top> | vor >>

Copyright © Galileo Press 2008
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de