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 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort
Download: - ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> / Java-Insel | vor >>
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel (8. Aufl.) 8., aktual. Auflage, geb., mit DVD 1.475 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1371-4 |
| 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 Kein Public Viewing – Passwörter sind privat
|  |  | 6.2.3 Wieso nicht freie Methoden und Variablen für alle?
|  |  | 6.2.4 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht
|  |  | 6.2.5 Zugriffsmethoden für Attribute deklarieren
|  |  | 6.2.6 Setter und Getter nach der JavaBeans-Spezifikation
|  |  | 6.2.7 Paketsichtbar
|  |  | 6.2.8 Zusammenfassung zur Sichtbarkeit
|  | 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 Variablen zum Datenaustausch
|  |  | 6.3.6 Statische Eigenschaften und Objekteigenschaften
|  | 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)sichere 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 Default-Konstruktor
|  |  | 6.5.3 Parametrisierte und überladene Konstruktoren
|  |  | 6.5.4 Copy-Konstruktor
|  |  | 6.5.5 Einen anderen Konstruktor der gleichen Klasse aufrufen
|  |  | 6.5.6 Ihr fehlt uns nicht – der Garbage-Collector
|  |  | 6.5.7 Private Konstruktoren, Utility-Klassen, Singleton, Fabriken
|  | 6.6 Klassen- und Objektinitialisierung
|  |  | 6.6.1 Initialisierung von Objektvariablen
|  |  | 6.6.2 Statische Blöcke als Klasseninitialisierer
|  |  | 6.6.3 Initialisierung von Klassenvariablen
|  |  | 6.6.4 Exemplarinitialisierer (Instanzinitialisierer)
|  |  | 6.6.5 Finale Werte im Konstruktor und in statischen Blöcken setzen
|  | 6.7 Assoziationen zwischen Objekten
|  |  | 6.7.1 Unidirektionale 1:1-Beziehung
|  |  | 6.7.2 Bidirektionale 1:1-Beziehungen
|  |  | 6.7.3 Unidirektionale 1:n-Beziehung
|  | 6.8 Vererbung
|  |  | 6.8.1 Vererbung in Java
|  |  | 6.8.2 Spielobjekte modelliert
|  |  | 6.8.3 Implizite Basisklasse java.lang.Object
|  |  | 6.8.4 Einfach- und Mehrfachvererbung
|  |  | 6.8.5 Sichtbarkeit protected
|  |  | 6.8.6 Konstruktoren in der Vererbung und super
|  | 6.9 Typen in Hierarchien
|  |  | 6.9.1 Automatische und explizite Typanpassung
|  |  | 6.9.2 Das Substitutionsprinzip
|  |  | 6.9.3 Typen mit dem binären Operator instanceof testen
|  | 6.10 Methoden überschreiben
|  |  | 6.10.1 Methoden in Unterklassen mit neuem Verhalten ausstatten
|  |  | 6.10.2 Mit super an die Eltern
|  |  | 6.10.3 Finale Klassen und finale Methoden
|  |  | 6.10.4 Kovariante Rückgabetypen
|  |  | 6.10.5 Array-Typen und Kovarianz
|  | 6.11 Dynamisches Binden/Polymorphie
|  |  | 6.11.1 Unpolymorph bei privaten, statischen und finalen Methoden
|  |  | 6.11.2 Polymorphie bei Konstruktoraufrufen
|  | 6.12 Abstrakte Klassen und abstrakte Methoden
|  |  | 6.12.1 Abstrakte Klassen
|  |  | 6.12.2 Abstrakte Methoden
|  | 6.13 Schnittstellen
|  |  | 6.13.1 Deklarieren von Schnittstellen
|  |  | 6.13.2 Implementieren von Schnittstellen
|  |  | 6.13.3 Markierungsschnittstellen
|  |  | 6.13.4 Ein Polymorphie-Beispiel mit Schnittstellen
|  |  | 6.13.5 Die Mehrfachvererbung bei Schnittstellen
|  |  | 6.13.6 Keine Kollisionsgefahr bei Mehrfachvererbung
|  |  | 6.13.7 Erweitern von Interfaces – Subinterfaces
|  |  | 6.13.8 Vererbte Konstanten bei Schnittstellen
|  |  | 6.13.9 Abstrakte Klassen und Schnittstellen im Vergleich
|  | 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) Typen und Eigenschaften
Das Gesetz ist der abstrakte Ausdruck des allgemeinen an und für sich seienden Willens. – Georg Wilhelm Friedrich Hegel # 6 Eigene Klassen schreiben ## 6.1 Eigene Klassen mit Eigenschaften deklarieren Die Deklaration einer Klasse leitet das Schlüsselwort class ein. Im Rumpf der Klasse lassen sich deklarieren: Attribute (Variablen) Methoden Konstruktoren Klassen- sowie Exemplarinitialisierer innere Klassen beziehungsweise innere Schnittstellen #### Eine ganz einfache Klassendeklaration Wir wollen die Konzepte der Klassen und Schnittstellen an einem kleinen Spiel verdeutlichen. Beginnen wir mit dem Spieler, den die Klasse Player repräsentieren soll. Listing 6.1 com/tutego/insel/game/v1/Player.java, Player
    class Player
    {
    }
Die Klasse hat einen vom Compiler generierten Konstruktor, sodass sich ein Exemplar unserer Klasse mit new Player() erzeugen lässt. ### 6.1.1 Attribute deklarieren Diese Player-Klasse hat bisher keine Attribute und kann bisher nichts. Geben wir dem Spieler zwei Attribute: eines für den Namen und ein zweites für einen Gegenstand, den er trägt. Die Datentypen sollen beide String sein. Listing 6.2 com/tutego/insel/game/v2/Player.java, Player
    class Player
    {
      String name;
      String item;
    }
Hinweis Eine spezielle Namenskonvention für Objektvariablen gibt es nicht. So ist es zwar möglich, zur Unterscheidung von lokalen Variablen ein Präfix wie »f« oder »_« voranzustellen, doch sogar die Eclipse-Macher sind davon abgekommen. Objektvariablen können auch grundsätzlich wie Methoden heißen, doch ist das unüblich, da Variablennamen im Allgemeinen Substantive und Methoden Verben sind.
Eine zweite Klasse Playground erzeugt in der main()-Funktion für den mutigen Spieler ein Player-Objekt, schreibt und liest die Attribute. Listing 6.3 com/tutego/insel/game/v2/Playground.java, Playground
    class Playground
    {
      public static void main( String[] args )
      {
        Player p = new Player();
        p.name = "Mutiger Manfred";
        p.item = "Schlips";

        System.out.printf( "%s nimmt einen %s mit.", p.name, p.item );
      }
    }
Hier klicken, um das Bild zu vergrößern #### Initialisierung von Attributen Anders als lokale Variablen initialisiert die Laufzeitumgebung alle Attribute mit einem Standardwert: 0 bei numerischen Werten und char false bei boolean null bei Referenzvariablen Gefällt uns das nicht, lassen sich die Variablen mit einem Wert belegen:
    class Player
    {
      String name = "";
    }
### 6.1.2 Methoden deklarieren Zu Attributen gesellen sich Methoden, die üblicherweise auf den Objektvariablen arbeiten. Geben wir der Klasse Player zwei Methoden: clearName() soll den Namen auf den Leerstring "" zurücksetzen, und hasCompoundName() soll verraten, ob der Spielername aus einem Vor- und Nachnamen zusammengesetzt ist. Der Name »Parry Hotter« ist zum Beispiel zusammengesetzt, »Spuckiman« aber nicht. Listing 6.4 com/tutego/insel/game/v3/Player.java, Player
    class Player
    {
      String name = "";
      String item = "";

      void clearName()
      {
        name = "";
      }

      boolean hasCompoundName()
      {
        return (name == null) ? false : name.contains( " " );
      }
    }
Hier klicken, um das Bild zu vergrößern Testen wir die Methode mit zwei Spielern: Listing 6.5 com/tutego/insel/game/v3/Playground.java, main()
    Player parry = new Player();
    parry.name = "Parry Hotter";
    System.out.printf( "'%s' hat zusammengesetzten Namen: %b%n",
                       parry.name, parry.hasCompoundName() );

    Player spucki = new Player();
    spucki.name = "Spuckiman";
    System.out.printf( "'%s' hat zusammengesetzten Namen: %b%n",
                       spucki.name, spucki.hasCompoundName() );
    spucki.clearName();
    System.out.printf( "Spuckis Name ist leer? %b%n", spucki.name.isEmpty() );
Wie zu erwarten, ist die Ausgabe:
    'Parry Hotter' hat zusammengesetzten Namen: true
    'Spuckiman' hat zusammengesetzten Namen: false
    Spuckis Name ist leer? true
Hier klicken, um das Bild zu vergrößern Abbildung 6.1 Ein Sequenzdiagramm stellt nur die Objekterzeugung und Methodenaufrufe, jedoch keine Attributzugriffe dar. Um schnell von einer Methode (oder Variablen) zur anderen zu navigieren, zeigt + ein Outline an (dieselbe Ansicht wie in der View Outline). Im Unterschied zur View lässt sich in diesem kleinen gelben Fenster mit den Cursor-Tasten navigieren, und ein befördert uns zur angewählten Methode oder Attribut. Wird in der Ansicht erneut + gedrückt, befinden sich dort auch die in den Oberklassen deklarierten Eigenschaften. Sie sind grau, und zusätzlich befinden sich hinter den Eigenschaften die Klassennamen. #### Methodenaufrufe und Nebeneffekte Alle Variablen und Methoden einer Klasse sind in der Klasse selbst sichtbar. Das heißt: Innerhalb einer Klasse werden die Objektvariablen und Methoden mit ihrem Namen verwendet. Somit greift die Methode hasCompoundName() direkt auf das nötige Attribut name zu, um die Programmlogik auszuführen. Dies wird oft für Nebeneffekte (Seiteneffekte) genutzt. Die Methode clearName() ändert ausdrücklich eine Objektvariable und verändert so den Zustand des Objekts. hasCompoundName() liest dagegen nur den Zustand, modifiziert ihn aber nicht. Methoden, die Zustände ändern, sollten das in der API-Beschreibung entsprechend dokumentieren. #### Objektorientierte und prozedurale Programmierung im Vergleich Entwickler aus der prozeduralen Welt haben ein anderes Denkmodell verinnerlicht, sodass wir an dieser Stelle die Besonderheit der Objektorientierung noch einmal verdeutlichen wollen. Während in der guten objektorientierten Modellierung Objekte immer Zustand und Verhalten besitzen, gibt es in der prozeduralen Welt nur Speicherbereiche, die referenziert werden; Daten und Verhalten liegen hier nicht zusammen. Problematisch wird es, wenn die prozedurale Denkware in Java-Programme abgebildet wird. Dazu ein Beispiel: Die Klasse PlayerData ist ein reiner Datencontainer für den Zustand, aber Verhalten wird hier nicht definiert. Listing 6.6 PlayerData.java
    class PlayerData
    {
      String name = "";
      String item = "";
    }
Anstatt nun die Methoden ordentlich wie in unserem ersten Beispiel mit an die Klasse zu hängen, würde in der prozeduralen Welt eine Funktion genau ein Datenobjekt bekommen und von diesem Zustände erfragen oder ändern: Listing 6.7 PlayerFunctions.java
    class PlayerFunctions
    {
      static void clearName( PlayerData data )
      {
        data.name = "";
      }

      static boolean hasCompoundName( PlayerData data )
      {
        return (data.name == null) ? false : data.name.contains( " " );
      }
    }
Da die Funktionen nun nicht mehr an Objekte gebunden sind, können sie statisch sein. Genauso falsch wären aber auch Methoden (egal ob statisch oder nicht) in der Klasse PlayerData, wenn sie ein PlayerData-Objekt übergeben bekommen. Beim Aufruf ist dieser nicht-objektorientierte Ansatz gut zu sehen. Setzen wir links den falschen und rechts den korrekt objektorientiert modellierten Weg ein:
Prozedural | Objektorientiert
    PlayerData parry = new PlayerData();
    parry.name = "Parry Hotter";
    PlayerFunctions.hasCompoundName( parry );
    PlayerFunctions.clearName( parry );
    Player parry = new Player();
    parry.name = "Parry Hotter";
    parry.hasCompoundName();
    parry.clearName();
Ein Indiz für problematische objektorientierte Modellierung ist also, wenn externen Funktionen Objekte übergeben werden, anstatt die Methoden selbst an die Objekte zu setzen. ### 6.1.3 Die this-Referenz In jeder Objektmethode und jedem Konstruktor steht eine Referenz mit dem Namen this bereit, die auf das eigene Exemplar zeigt. Mit dieser this-Referenz lassen sich elegante Lösungen realisieren, wie die folgenden Beispiele zeigen: Die this-Referenz löst das Problem, wenn lokale Variablen Objektvariablen verdecken. Liefert eine Methode als Rückgabe die this-Referenz auf das aktuelle Objekt, lassen sich Methoden der Klasse einfach hintereinandersetzen. Mit der this-Referenz lässt sich einer anderen Methode eine Referenz auf uns selbst geben. #### Überdeckte Objektvariablen nutzen Trägt eine lokale Variable den gleichen Namen wie eine Objektvariable, so verdeckt sie diese. Das folgende Beispiel deklariert in der Player-Klasse eine Objektvariable name, und eine Methode quote() deklariert in der Parameterliste eine Variable, die ebenfalls name heißt. Somit bezieht sich in der Methode jeder Zugriff auf name auf die Parametervariable und nicht auf die Objektvariable.
    class Player
    {
      String name;                                // Objektvariable name

      void quote( String name )                   // Lokale Parametervariable name
      {
        System.out.println( "'" + name + "'" );   // Bezieht sich auf Parametervariable
      }
    }
Das heißt aber nicht, dass auf die äußere Variable nicht mehr zugegriffen werden kann. Die this-Referenz zeigt auf das aktuelle Objekt, und damit ist auch ein Zugriff auf Objekteigenschaften jederzeit möglich.
    class Player
    {
      String name;

      void quote( String name )
      {
        System.out.println( "'" + this.name + "'" ); // Zugriff auf Objektvariable
        System.out.println( "'" + name + "'" );      // Zugriff auf Parametervariable
      }
    }
Häufiger Einsatzort für das this in Methoden sind Methoden, die Zustände initialisieren. Gerne nennen Entwickler die Parametervariablen so wie die Exemplarvariablen, um damit eine starke Zugehörigkeit auszudrücken. Schreiben wir eine Methode setName():
    class Player
    {
      String name;

      void setName( String name )
      {
        this.name = name;
      }
    }
Der an setName() übergebene Wert soll die Objektvariable name initialisieren. So greift this.name auf die Objektvariable direkt zu, sodass die Zuweisung this.name = name; die Objektvariable mit dem Argument initialisiert. Hier klicken, um das Bild zu vergrößern #### this für kaskadierte Methoden Die append()-Methoden bei StringBuilder liefern die this-Referenz, sodass sich Folgendes schreiben lässt:
    StringBuilder sb = new StringBuilder();
    sb.append( "Microsoft kauft Ebay" ).append( '?' );
Jedes append() liefert das StringBuilder-Objekt, auf dem es aufgerufen wird. Wir wollen diese Möglichkeit bei einem Spieler programmieren, sodass die Methoden name() und item() Spielername und Gegenstand zuweisen. Beide Methoden liefern ihr eigenes Player-Objekt über die this-Referenz zurück. Listing 6.8 com/tutego/insel/game/v4/Player.java, Player
    class Player
    {
      String name = "", item = "";

      Player name( String name )
      {
        this.name = name;
        return this;
      }

      String name()
      {
        return name;
      }

      Player item( String item )
      {
        this.item = item;
        return this;
      }

      String item()
      {
        return item;
      }

      String id()
      {
        return name + " has " + item;
      }
    }
Hier klicken, um das Bild zu vergrößern Erzeugen wir einen Player, und kaskadieren wir einige Methoden: Listing 6.9 com/tutego/insel/game/v4/Playground.java, main()
    Player patty = new Player().name( "Parry" ).item( "helmet" );
    System.out.println( patty.name() );                     // Parry
    System.out.println( patty.id() );                       // Parry has helmet
Der Ausdruck new Player() liefert eine Referenz, die wir sofort für den Methodenaufruf nutzen. Da name(String) wiederum eine Objektreferenz vom Typ Player liefert, ist dahinter direkt .item(String) möglich. Die Verschachtelung von name(String).item(String) bewirkt, dass Name und Gegenstand gesetzt werden und der jeweils nächste Methodenaufruf in der Kette über this eine Referenz auf dasselbe Objekt, aber mit verändertem internen Zustand bekommt. Hier klicken, um das Bild zu vergrößern
Hinweis Bei Anfragemethoden könnten wir versucht sein, diese praktische Eigenschaft überall zu verwenden. Üblicherweise sollten Objekte jedoch ihre Eigenschaften nach der JavaBeans-Konvention mit void setXXX() setzen, und dann liefern sie ausdrücklich keine Rückgabe. Eine mit dem Objekttyp deklarierte Rückgabe Player setName(String) verstößt also gegen diese Konvention, sodass die Methode in dem Beispiel einfach Player name(String) heißt. Beispiele dieser Bauart sind in der Java-Bibliothek an einigen Stellen zu finden. Sie werden auch Builder genannt.
### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück | <top> | vor >>
Zum Katalog
Java ist auch eine Insel Jetzt bestellen
Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen? Ihre Meinung
Tipp
| Coding for Fun
Buchempfehlungen
| Objektorientierte Programmierung
| Einstieg in Eclipse 3.4
| Java 6 lernen mit Eclipse
| NetBeans Platform 6
| Java und XML
| Visual C# 2008
| IT-Handbuch für Fachinformatiker
| C++ von A bis Z
Shopping
Versandkostenfrei bestellen in Deutschland und Österreich Info

Copyright © Galileo Press 2009
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