05.10.2013 Aufrufe

Programmieren in Java

Programmieren in Java

Programmieren in Java

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Prof. Jürgen Sauer<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Skriptum zur Vorlesung im WS 2000/2001<br />

1


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Inhaltsverzeichnis<br />

0. E<strong>in</strong>führung <strong>in</strong> die <strong>Java</strong>-Programmierung<br />

0.1 Ziel der Vorlesung "<strong>Programmieren</strong>"<br />

0.2 Basis der Vorlesung: "Die <strong>Java</strong>-Masch<strong>in</strong>e"<br />

0.3 Der erste Versuch<br />

0.3.1 Das erste Programm<br />

0.3.2 Bestandteile e<strong>in</strong>es Programms<br />

1. E<strong>in</strong>führung <strong>in</strong> die <strong>Java</strong>-Programmierung<br />

1.1 Übersicht zur Entwicklung der Programmiersprache <strong>Java</strong><br />

1.2 Was ist <strong>Java</strong>?<br />

1.3 E<strong>in</strong>stieg <strong>in</strong> die <strong>Java</strong>-Programmierung<br />

1.3.1 Die Software für die <strong>Java</strong>-Programmierung<br />

1.3.2 Applets und Anwendungen<br />

1.3.2.1 Entwickeln von <strong>Java</strong>-Anwendungen<br />

1.3.2.2 Entwickeln von <strong>Java</strong>-Applets<br />

1.4 Die Objektorientierung von <strong>Java</strong><br />

1.4.1 Grundlegende Konzepte<br />

1.4.1.1 Zustand und Verhalten von Objekten, Klassen, Instanz- und Klassenvariable bzw. -<br />

methoden<br />

1.4.1.2 Superklassen und Subklassen, Vererbung und Klassenhierarchie<br />

1.4.1.3 Referenzen und Referenztypen<br />

1.4.1.4 Konvertieren von Objekten und Primitivtypen<br />

1.4.1.5 Manipulieren von Objekten<br />

Vergleichen von Objekten<br />

Kopieren von Objekten<br />

1.4.1.6 Lokale, <strong>in</strong>nere und anonyme Klassen<br />

1.4.1.7 Schnittstellen und anonyme Klassen<br />

1.4.1.8 Polymorphismus und B<strong>in</strong>den<br />

1.4.2 Klassen des Pakets java.lang<br />

1.4.3 Ausnahmen und Ausnahmenbehandlung<br />

Ausnahmen<br />

Globales Exception Handl<strong>in</strong>g<br />

Die Fehlerklassen von <strong>Java</strong><br />

Auslösen von Ausnahmen<br />

1.4.4 E<strong>in</strong>fache E<strong>in</strong>- und Ausgaben<br />

2


2. Hauptbestandteile der Sprache<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2.1 Token<br />

2.1.1 Schlüsselworte<br />

2.1.2 Bezeichner und Namenskonventionen<br />

2.1.3 Literale<br />

1. Ganzzahlige Literale<br />

2. Gleitpunktliterale<br />

3. Boolesche Literale<br />

4. Zeichenliterale<br />

5. Zeichenkettenliterale<br />

2.1.4 Trennzeichen<br />

2.1.5 Operatoren<br />

2.1.6 Kommentare, e<strong>in</strong>gebettete Dokumentation<br />

2.2 Typen<br />

2.2.1 Primitive Datentypen<br />

2.2.2 Operationen mit primitiven Datentypen<br />

2.2.3 Datenfelder (Arrays)<br />

2.2.3.1 Deklarieren, Erstellen von Array-Objekten<br />

2.2.3.2 Zugriff auf Datenfeld-Elemente<br />

2.2.3.3 Anwendungen mit e<strong>in</strong>dimensionalen Feldern<br />

2.2.3.4 Multidimensionale Datenfelder<br />

2.2.3.5 Die Klasse Arrays<br />

2.3 Ausdrücke<br />

2.3.1 Arithmetische Ausdrücke<br />

2.3.2 Bewertung von Ausdrücken<br />

2.3.3 Typkonvertierungen<br />

2.3.4 Vergleichsoperatoren<br />

2.3.5 Logische Ausdrücke<br />

2.4 Anweisungen<br />

2.4.1 Blöcke und Anweisungen<br />

2.4.2 Leere Anweisungen<br />

2.4.3 Benannte Anweisungen<br />

2.4.4 Deklarationen<br />

2.4.5 Ausdrucksanweisungen<br />

2.4.6 Auswahlanweisungen<br />

2.4.7 Wiederholungsanweisungen<br />

2.4.8 Sprunganweisungen<br />

2.4.9 Synchronisationsanweisungen<br />

2.4.10 Schutzanweisungen<br />

2.4.11 Unerreichbare Anweisungen<br />

2.5 Klassen<br />

2.6 Methoden<br />

2.6.1 Die Deklaration<br />

2.6.2 Die Zugriffsspezifizierung<br />

3


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2.6.3 Die Methodenmodifizierer<br />

2.6.4 Rückgabewerte von Methoden<br />

2.6.5 Methodenname und Parameterliste<br />

2.6.6 Überladen und Überschreiben von Methoden<br />

3. Grafische Benutzeroberflächen und Applets<br />

3.1 Ereignisbehandlung unter grafischen Benutzeroberflächen (Graphical User Interface)<br />

1. Gestaltung von grafischen Benutzeroberflächen mit Hilfe der AWT-Klassen<br />

2. Ereignisbehandlung unter grafischen Benutzeroberflächen<br />

3. Anwendung lokaler Klassen für die Ereignisbehandlung<br />

4. Externe- und <strong>in</strong>terne Darstellung numerischer Werte<br />

5. Low-Level-Events<br />

3.2 Kommunikation des Anwenders mit Programmen <strong>in</strong> GUI über Dialoge bzw. Menüs<br />

mit vordef<strong>in</strong>ierten Dialogelementen<br />

3.2.1 Dialoge<br />

3.2.2 Menüs<br />

3.3 Grundlagen der Applet-Erstellung<br />

3.3.1 HTML-Grundlagen<br />

3.3.2 Die <strong>in</strong>terne Arbeitsweise e<strong>in</strong>es Applets<br />

3.3.3 „Multithread<strong>in</strong>g“-fähige Applets<br />

3.3.4 Animation <strong>in</strong> Applets<br />

3.3.5 Das Laden und Anzeigen von Bildern<br />

3.3.6 Das Laden und Anzeigen von Sound-Clips<br />

Sound-Ausgabe <strong>in</strong> Applets<br />

Sound-Ausgabe <strong>in</strong> Applikationen<br />

3.4 Grafische Benutzeroberflächen mit Observable-Observer<br />

Die Klasse Observable<br />

Die Schnittstelle Observable<br />

Observable-Observer: Kopplung von Anwendung und GUI<br />

3.5 Sw<strong>in</strong>g<br />

3.6 <strong>Java</strong>Beans<br />

4. Grafik und Bildverarbeitung<br />

4.1 Allgeme<strong>in</strong>e Zeichenvorgänge<br />

4.1.1 Punkte, L<strong>in</strong>ien, Kreise, Bögen<br />

4.1.2 Farbangaben<br />

4.1.3 Textausgabe über den Zeichenmodus<br />

Die Klasse Font<br />

Die Klasse FontMetrics<br />

4.1.4 Die <strong>Java</strong>-Zeichenmodi<br />

4


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

4.2 Das Zeichnen von Bildern<br />

4.2.1 Laden und Anzeigen e<strong>in</strong>er Bitmap<br />

4.2.2 Die Klasse MediaTracker<br />

4.2.3 Entwickl<strong>in</strong>g e<strong>in</strong>er eigenen Bitmap-Komponente<br />

4.2.4 Überspielen e<strong>in</strong>er Folge von Bitmaps<br />

4.3 Grafikoperationen mit <strong>Java</strong> 2D<br />

5. AWT<br />

5.1 Bestandteile des AWT<br />

5.2 Die AWT-Komponenten<br />

5.2.1 Schaltflächen (Buttons)<br />

5.2.2 Labels<br />

5.2.3 Kontrollkästchen und Optionsfelder<br />

5.2.4 Auswahlmenüs<br />

5.2.5 Listenfelder<br />

5.2.6 Textbereiche und Textfelder<br />

5.2.7 Schieber und Bildlaufleisten<br />

5.2.8 Zeichenbereiche<br />

5.3 Conta<strong>in</strong>er<br />

5.3.1 Panels<br />

5.3.2 Frames<br />

5.3.3 Menüs<br />

5.3.4 Dialoge<br />

5.4 Die Layout-Manager<br />

5.4.1 Layout-Regeln<br />

5.4.2 Die e<strong>in</strong>zelnen Layout-Manager<br />

5.5 Die Event-Modelle 1.0 und 1.1<br />

5.5.1 Der AWT-Handler 1.0<br />

5.5.2 Das Event-Handl<strong>in</strong>g 1.1<br />

5.6 Benutzerschnittstellen mit Sw<strong>in</strong>g<br />

6. Utilities<br />

6.1 Collections<br />

6.1.1 Die Klasse Vector<br />

6.1.2 Die Klasse Stack<br />

6.1.3 Die Klasse Hashtabelle<br />

6.1.4 Die Klasse Bitset<br />

6.2 <strong>Java</strong> 2 Collections<br />

5


6.3 Die Klasse Str<strong>in</strong>gTokenizer<br />

6.4 Die Klasse Random<br />

6.5 Die Klassen Date, Calendar<br />

7. E<strong>in</strong>-/ Ausgabe<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

7.1 Die abstrakten Klassen InputStream und OutputStream<br />

7.1.1 InputStream<br />

7.1.2 OutputStream<br />

7.2 Gefilterte Ströme<br />

7.3 Die Klasse File<br />

7.4 Die Klasse RandomAccessFile<br />

7.5 Spezielle nützliche Ströme<br />

7.6 <strong>Java</strong> 1.1 IO-Ströme<br />

7.6.1 Grundlagen<br />

7.6.2 Die abstrakte Klasse Reader und ihre Ableitungen<br />

7.6.3 Die abstrakte Klasse Writer und ihre Ableitungen<br />

7.6.4 Demonstrationsprogramm zur E<strong>in</strong>-/Ausgabe (ab <strong>Java</strong> Version 1.1)<br />

8. Serialisierung<br />

9. Netzwerkprogrammierung<br />

6


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Literaturverzeichnis<br />

Alexander Newman u.a.: JAVA, Referenz und Anwendungen, 1996, Que, Haar bei München<br />

Ralph Steyer: JAVA 1.2, Kompendium, 1998, Markt & Technik, Haar bei München<br />

Laura Lemay u. Roger Cadenhead; JAVA 2 <strong>in</strong> 21 Tagen, 1999, Markt & Technik, Haar bei<br />

München<br />

Guide Krüger: Go To <strong>Java</strong> 2, 1999, Addison-Wesley, München ...<br />

David Flanagan: <strong>Java</strong> <strong>in</strong> a Nutshell, 1996, O’Reilly&Associates Inc, Bonn ...<br />

7


0. Übersicht<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

0.1 Ziel der Vorlesung „<strong>Programmieren</strong>“<br />

„Vermittlung grundlegender Kenntnisse, die zum Lösen von Problemen mit e<strong>in</strong>er<br />

Rechenanlage (Computer, Rechner) nötig s<strong>in</strong>d.“<br />

Die Rechenanlage ist „irgende<strong>in</strong>e“ (vom „Jumbo“ bis zum Personal Computer) und<br />

muß<br />

- e<strong>in</strong>e E<strong>in</strong>gabemöglichkeit für Ziffern, Buchstaben und Sonderzeichen besitzen (Tastatur)<br />

- programmierbar se<strong>in</strong><br />

- e<strong>in</strong>e Ausgabemöglichkeit haben (Bildschirm)<br />

Zum Erwerb grundlegender Kenntnisse für das Lösen von Problemen auf e<strong>in</strong>em<br />

Universalrechner ist<br />

- zu zeigen, wie man von der Problemstellung zum Lösungsverfahren (Algorithmus) kommt. Alle<br />

Probleme, für die e<strong>in</strong> Lösungweg genügend präzis formuliert werden kann, s<strong>in</strong>d über den Rechner<br />

lösbar.<br />

- zu üben: Der Umgang mit den Algorithmen. Dazu wird die Programmiersprache <strong>Java</strong> benutzt, <strong>in</strong> der<br />

die Algorithmen formuliert werden. Der <strong>in</strong> <strong>Java</strong> formulierte Lösungsweg (Algorithmus) ist das <strong>Java</strong>-<br />

Programm (Anwendung, Applet), der Rechner auf dem das Programm ausführbar ist, ist die <strong>Java</strong>-<br />

Masch<strong>in</strong>e. <strong>Java</strong> ist e<strong>in</strong>e Sprache, die die Arbeitsanweisungen e<strong>in</strong>es Programmierers e<strong>in</strong>fach und<br />

anschaulich darstellen kann.<br />

<strong>Java</strong> wurde ab 1991 bei Sun Microsystems entwickelt. Verantwortlich für <strong>Java</strong> ist<br />

<strong>Java</strong>Soft, e<strong>in</strong>e Tochterfirma von Sun Microsystems. <strong>Java</strong> und <strong>Java</strong>Soft 1 halten<br />

permanent die aktuellsten Informationen im Internet bereit.<br />

0.2 <strong>Java</strong>-Masch<strong>in</strong>e und Programmiersystem<br />

Die <strong>Java</strong>-Masch<strong>in</strong>e 2 nutzt die Möglichkeiten des Universalrechners.<br />

Die E<strong>in</strong>gabemöglichkeit dient zum E<strong>in</strong>schreiben von Daten und Programmen <strong>in</strong> den<br />

Speicher der Zentrale<strong>in</strong>heit (central process<strong>in</strong>g unit, CPU). Die Zentrale<strong>in</strong>heit<br />

verarbeitet die e<strong>in</strong>gegebenen Daten nach den Anweisungen des e<strong>in</strong>gelesenen<br />

Programms, das zur Ausführung <strong>in</strong> b<strong>in</strong>äre Form gebracht wurde. Das Steuerwerk<br />

überwacht die Ausführung des Programms (Entschlüsseluung der b<strong>in</strong>är dargestellten<br />

Anweisungen). Das eigentliche Abarbeiten der Programmanweisungen<br />

(arithmetische, logische Operatoren) <strong>in</strong> der gegebenen Reihenfolge übernimmt das<br />

Rechenwerk. Daten, Programme, die im Hauptspeicher ke<strong>in</strong>en Platz f<strong>in</strong>den, s<strong>in</strong>d auf<br />

externen Speichermedien ausgelagert (Magnetband, Magnetplatte, Floppy Disc).<br />

1 http://java.sun.com<br />

2 Die virtuelle Masch<strong>in</strong>e von <strong>Java</strong> (<strong>Java</strong> VM) ist wirklich e<strong>in</strong>e Masch<strong>in</strong>e, d.h. Hardware, die bestimmte<br />

Operationscodes (Masch<strong>in</strong>enanweisungen) <strong>in</strong>terpretieren kann. Es wurden bzw. werdem Chips entwickelt, die<br />

diese Masch<strong>in</strong>e <strong>in</strong> Hardware implementieren. Im Regelfall geschieht aber e<strong>in</strong>e Emulation durch das<br />

Laufzeitsystem auf der jeweiligen Zielplattform.<br />

8


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>gabee<strong>in</strong>heit Externer Speicher Ausgabee<strong>in</strong>heit<br />

Hauptspeicher Steuerwerk Rechenwerk<br />

Zentrale<strong>in</strong>heit<br />

Abb. 0.2-1: Pr<strong>in</strong>zipieller Aufbau e<strong>in</strong>es Universalrechners<br />

Der Universalrechner ist vielfältig anwendbar. Welche Anwendungsmöglichkeit<br />

(z.B. <strong>Java</strong>-Masch<strong>in</strong>e) gewünscht wird, gibt der Benutzer durch Systemkommandos<br />

bekannt. Diese Kommandos werden von Systemprogrammen entschlüsselt und<br />

anschließend <strong>in</strong>terpretiert. E<strong>in</strong>es dieser Kommandos verwandelt, falls die die dazu<br />

nötigen Programme vorhanden s<strong>in</strong>d, den Universalrechner <strong>in</strong> e<strong>in</strong>e <strong>Java</strong>-Masch<strong>in</strong>e.<br />

Für die <strong>Java</strong>-Masch<strong>in</strong>e s<strong>in</strong>d danach die <strong>Java</strong>-Programme des Benutzers die Quelle<br />

aller Erkenntnisse.<br />

Quellprogramme werden über die Tastatur e<strong>in</strong>gegeben und auf externen Speicher<br />

abgelegt. Zur E<strong>in</strong>gabe, Korrektur und Änderung stellt das System e<strong>in</strong> Programm mit<br />

dem Namen „Editor" zur Verfügung. Das Speichern der e<strong>in</strong>gegebenen bzw.<br />

geänderten Programme auf Externspeicher übernimmt das Systemprogramm<br />

„Dateiverwaltung“.<br />

<strong>Java</strong>-Programm Daten<br />

E<strong>in</strong>gabe (Tastatur)<br />

Externer Speicher Externer Speicher<br />

<strong>Java</strong>-Compiler<br />

System, <strong>Java</strong>-Quellpro-<br />

System- <strong>Java</strong>-Masch<strong>in</strong>e gramme<br />

programme <strong>Java</strong>-Laufzeitsystem<br />

<strong>Java</strong>-Bytecode-<br />

Dateien<br />

Ausgabe (Bildschirm)<br />

9


0.3 Der erste Versuch<br />

0.3.1 Das erste Programm<br />

Quelltext:<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

import java.lang.*;<br />

/* ErstesProgramm ist e<strong>in</strong>e Applikation, die den e<strong>in</strong>fachen<br />

Gebrauch von Zeichenketten aufzeigt */<br />

public class ErstesProgramm extends Object<br />

{<br />

// Beg<strong>in</strong>n der Ausfuehrung vom Programm<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Ausgabe auf das Standard-Ausgabegeraet<br />

System.out.pr<strong>in</strong>tln(<br />

"Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.");<br />

}<br />

}<br />

Das Programm umfaßt zwei Teile: e<strong>in</strong>e Klassendef<strong>in</strong>ition und e<strong>in</strong>en<br />

Programmabschnittt, der durch die Methode ma<strong>in</strong>() bestimmt ist.<br />

Jede <strong>Java</strong>-Anwendung besteht aus mehreren Klassen. Die Klasse, die die<br />

Ausgangsbasis für <strong>Java</strong>-Programme ist, muß die ma<strong>in</strong>()-Methode benutzen:<br />

public static void ma<strong>in</strong>(Strig args[]) { ... }.<br />

Es bedeuten:<br />

public ... Die Methode ist für andere Klassen und Objekte verfügbar<br />

static ... Es handelt sich um e<strong>in</strong>e Klassenmethode<br />

ma<strong>in</strong>() ... Die Funktion ma<strong>in</strong>() hat e<strong>in</strong>en Parameter vom Typ Zeichenkette<br />

(Str<strong>in</strong>g). Dieser Parameter dient zur Aufnahme von<br />

Befehlszeilenargumente. Argumente, die an <strong>Java</strong>-Programme<br />

übergeben werden, werden zu Zeichenketten konvertiert. In <strong>Java</strong>-<br />

Programmen ist ma<strong>in</strong>(), wie <strong>in</strong> C/C++-Programmen, die erste<br />

Rout<strong>in</strong>e des Programms, die ausgeführt wird.<br />

Durch die „import“-Anweisung können Entwickler Klassen verwenden, die <strong>in</strong><br />

anderen Dateien def<strong>in</strong>iert s<strong>in</strong>d. Compiler bzw. Interpreter greifen auf die Dateien zu.<br />

Über „import“ wird bestimmt, wo diese Dateien liegen. <strong>Java</strong> importiert immer das<br />

Paket „java.lang“, denn hier ist die Klasse Object enthalten, von der alle <strong>Java</strong>-<br />

Klassen abgeleitet s<strong>in</strong>d. Das Paket „java.lang“, die unmittelbare Ableitung von der<br />

Klasse Object werden <strong>in</strong> <strong>Java</strong> per Default bereitgestellt. Die diesbezüglichen<br />

Angaben im Programm können entfallen, der Quelltext kann deshalb auch folgende<br />

Gestalt annehmen:<br />

/* ErstesProgramm ist e<strong>in</strong>e Applikation, die den e<strong>in</strong>fachen<br />

Gebrauch von Zeichenketten aufzeigt */<br />

public class ErstesProgramm<br />

{<br />

// Beg<strong>in</strong>n der Ausfuehrung vom Programm<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Ausgabe auf das Standard-Ausgabegeraet<br />

System.out.pr<strong>in</strong>tln(<br />

"Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.");<br />

}<br />

}<br />

10


Token<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Ausdrucksformen der Sprache <strong>Java</strong> werden Token genannt. In derartige für die<br />

Sprache <strong>Java</strong> s<strong>in</strong>nvolle E<strong>in</strong>heiten muß sich der Quelltext e<strong>in</strong>es <strong>Java</strong>-Programms<br />

zerlegen lassen. Es gibt <strong>in</strong> <strong>Java</strong> fünf Arten von Token: Bezeichner oder Identifizierer,<br />

Schlüsselworte, Literale, Operatoren, Trennzeichen.<br />

Bezeichner, Identifizierer: Darunter versteht man die Benennungen (Namen) für<br />

Klassen, Objekte, Variable, Methoden. Namen s<strong>in</strong>d zusammengesetzt aus Unicode-<br />

Zeichen. <strong>Java</strong> benutzt den 16-Bit-Unicode-Zeichensatz, dessen erste 256 Zeichen<br />

dem normalen ASCII-Zeichensatz entsprechen (Byte 1 ist immer auf 0 gesetzt). Im<br />

vorliegenden Programm s<strong>in</strong>d z. B. Bezeichner: ErstesProgramm, ma<strong>in</strong>, System.<br />

<strong>Java</strong> unterscheidet Groß-/ Kle<strong>in</strong>schreibung. Namen bestehen <strong>in</strong> der Regel aus<br />

alphabetischen Zeichen und Dezimalziffern. An der ersten Stelle darf ke<strong>in</strong>e Zahl<br />

stehen.<br />

Schlüsselwörter: Das s<strong>in</strong>d Wörter, die e<strong>in</strong> wesentlicher Teil der <strong>Java</strong>-<br />

Sprachdef<strong>in</strong>ition s<strong>in</strong>d, z.B.: public, class, void, Str<strong>in</strong>g.<br />

Literale: mit e<strong>in</strong>em Literal können Variablen und Konstanten bestimmte Werte<br />

zugewiesen werden. Literale können annehmen: numerische Werte (z.B. 13),<br />

boolesche Werte (true bzw. false), Zeichen (z.B. ‘A‘) und Zeichenketten (z.B.<br />

"Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.").<br />

Operatoren: Das s<strong>in</strong>d Zeichen bzw. Zeichenkomb<strong>in</strong>ationen zur Ausgabe e<strong>in</strong>er<br />

auszuführenden Operation mit e<strong>in</strong>er oder mehreren Variablen oder Konstanten<br />

(Operanden), z.B. + - / >.<br />

Variable s<strong>in</strong>d Arbeitsspeicherstellen, an denen Informationen gespeichert werden<br />

können. Zur Deklaration erhält e<strong>in</strong>e Variable Namen (Bezeichner) und Typ<br />

zugeordnet. Der Typ kennzeichnet die Art der Information, die die Variable<br />

aufnehmen kann, z.B.:<br />

<strong>in</strong>t i; // zur Aufnahme ganzer Zahlen<br />

Str<strong>in</strong>g s; // zur Aufnahme von Zeichenketten<br />

In <strong>Java</strong> unterscheidet man: elementare (primitive Typen) und benutzerdef<strong>in</strong>ierte<br />

Typen (e<strong>in</strong>schl. der vom System bereitgestellten Klassen: Str<strong>in</strong>g und Array). Es<br />

gibt acht primitive Typen zum Speichern von ganzen Zahlen (byte, short, <strong>in</strong>t,<br />

long), Gleipunktzahlen (float, double), Zeichen (char) und booleschen Werten<br />

(boolean).<br />

Sobald die Variable deklariert wurde, kann ihr über den Zuweisungsoperator („=“) e<strong>in</strong><br />

Wert zugewiesen werden, z.B. <strong>in</strong>nerhalb der ma<strong>in</strong>()-Methode<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Str<strong>in</strong>g s; // Deklaration der Variablen s zur Aufnahme von Zeichenketten<br />

// Zuweisung<br />

s = "Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>."<br />

// Aufruf der Methode pr<strong>in</strong>tln() der Klasse System, die sich im Paket<br />

// java.lang bef<strong>in</strong>det<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

11


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Vorrang Operator Operandentyp Assoziation Operation<br />

1 ++<br />

Arithmetisch R<br />

Pre- oder Post-Inkrement<br />

(unär)<br />

--<br />

Arithmetisch R<br />

Pre- oder Post-<br />

Dekrement (unär)<br />

+, -<br />

Arithmetisch R<br />

Unäres<br />

M<strong>in</strong>us<br />

Plus, unäres<br />

~<br />

Integral<br />

R<br />

Bitweises<br />

(unär)<br />

Komplement<br />

!<br />

boolean<br />

R<br />

Logisches<br />

(unär)<br />

Komplement<br />

(type)<br />

irgende<strong>in</strong><br />

R<br />

cast<br />

2 *, /, % arithmetisch L Multiplikation,<br />

Rest<br />

Division,<br />

3 +, -<br />

Arithmetisch L<br />

Addition, Subtraktion<br />

+<br />

Str<strong>in</strong>g<br />

L<br />

Verkettung<br />

4 ><br />

Integral<br />

L<br />

Rechts-Shift<br />

Vorzeichen<br />

mit<br />

>>><br />

Integral<br />

L<br />

Rechts-Shift mit Nullen-<br />

Nachziehen<br />

5 =<br />

Arithmetisch L<br />

Größer als, größer als<br />

oder gleich<br />

<strong>in</strong>stanceof Objekt, Typ L<br />

Objekt?, Instanz?<br />

6 ==<br />

Primitiver Typ L<br />

Gleich (identische Werte)<br />

!=<br />

Primitiver Typ L<br />

Ungleich<br />

Werte)<br />

(verschiedene<br />

==<br />

Objekt<br />

L<br />

Gleich (Referenz auf das<br />

gleiche Objekt)<br />

!=<br />

Objekt<br />

L<br />

Ungleich (Referenz auf<br />

verschiedene Objekte)<br />

7 &<br />

Integral<br />

L<br />

Bitweises Und<br />

&<br />

boolean<br />

L<br />

Logisches Und<br />

8 ^<br />

Integral<br />

L<br />

Bitweises Oder<br />

^<br />

boolean<br />

L<br />

Logisches<br />

(exklusiv)<br />

Oder<br />

9 |<br />

Integral<br />

L<br />

Bitweises Oder<br />

|<br />

boolean<br />

L<br />

Logisches Oder (<strong>in</strong>klusiv)<br />

10 && boolean L Konditionelles Und<br />

11 || boolean L Konditionelles Oder<br />

12 ?= boolean, irgende<strong>in</strong>, R Konditioneller (ternärer)<br />

irgende<strong>in</strong><br />

Operator<br />

13 =<br />

Variable, irgende<strong>in</strong> R<br />

Zuweisung<br />

*=, /=,<br />

+=, -=<br />

=,<br />

>>>=,<br />

&=, ^=,<br />

|=<br />

Variable, irgende<strong>in</strong> R<br />

Zuweisung mit Operation<br />

Abb. 0.3-1: <strong>Java</strong>-Operatoren<br />

12


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

System.out.pr<strong>in</strong>tln(s); ist e<strong>in</strong>e Anweisung. Anweisungen stehen für e<strong>in</strong>e<br />

e<strong>in</strong>zelne Aktion, die <strong>in</strong> e<strong>in</strong>em <strong>Java</strong>-Programm ausgeführt wird. Jede Anweisung wird<br />

mit e<strong>in</strong>em Strichpunkt „;“ abgeschlossen. E<strong>in</strong>ige Anweisungen erzeugen e<strong>in</strong>en Wert,<br />

wie das bspw. beim Addieren zweier Zahlen der Fall ist. Derartige Anweisungen<br />

werden als Ausdrücke bezeichnet.<br />

E<strong>in</strong> Ausdruck ist e<strong>in</strong>e Anweisung, die als Ergebnis e<strong>in</strong>en (Rückgabe-) Wert<br />

produziert. Dieser Wert kann zur späteren Verwendung im Programm gespeichert,<br />

direkt <strong>in</strong> e<strong>in</strong>er anderen Anweisung verwendet oder überhaupt nicht beachtet werden.<br />

Ausdrücke können Konstanten, Variablen, Operatoren be<strong>in</strong>halten. Ausdrücke s<strong>in</strong>d<br />

vielfach mit unären und b<strong>in</strong>ären Operatoren verknüpft.<br />

Trennzeichen: Das s<strong>in</strong>d Symbole und Zusammenfassungen von Quellcode: ( ) {<br />

} [ ] ; . , .<br />

„(“: wird sowohl zum Öffnen e<strong>in</strong>er Parameterliste für e<strong>in</strong>e Methode als auch zur<br />

Festlegung der Priorität für Operationen <strong>in</strong> e<strong>in</strong>em Ausdruck benutzt.<br />

„)“: wird sowohl zum Schließen e<strong>in</strong>er Parameterliste für e<strong>in</strong>e Methode als auch zur<br />

Festlegung der Priorität für Operationen <strong>in</strong> e<strong>in</strong>em Ausdruck benutzt.<br />

Bsp.: public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

„{“: wird zu Beg<strong>in</strong>n e<strong>in</strong>es Blocks mit Anweisungen oder e<strong>in</strong>er Initialisierungsliste<br />

gesetzt.<br />

„}“:wird an das Ende e<strong>in</strong>es Blocks mit Anweisungen oder e<strong>in</strong>er Initialisierungsliste<br />

gesetzt.<br />

Bsp.: Methoden werden <strong>in</strong> <strong>Java</strong> durch e<strong>in</strong>en Anweisungsblock bestimmt. E<strong>in</strong> Anweisungsblock besteht<br />

<strong>in</strong> der Regel aus e<strong>in</strong>er Reihe von Anweisungen, die von geschweiften Klammern umschlossen s<strong>in</strong>d.<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Str<strong>in</strong>g s;<br />

s = "Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.";<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

„[“: steht für e<strong>in</strong>e Ausdruck, der als Index für e<strong>in</strong> Datenfeld (Array) steht.<br />

„]“: folgt e<strong>in</strong>em Ausdruck, der als Index für e<strong>in</strong> Datenfeld steht.<br />

Bsp.: Str<strong>in</strong>g args[] = {“Juergen“, “Hubert“, “Josef“, “Liesel“, “Christian“};<br />

def<strong>in</strong>iert e<strong>in</strong>en Array mit 5 Komponenten, die alle den gleichen Typ besitzen<br />

Datenfelder (Arrays) dienen zum Speichern von Elementen, die alle denselben Typ aufweisen. Jedem<br />

Element wird <strong>in</strong>nerhalb des Datenfelds e<strong>in</strong> eigener Speicherplatz zugewiesen. Dieser Speicherplatz ist<br />

für den leichten Zugriff durchnumeriert.<br />

[0] “Juergen“<br />

[1] “Hubert“<br />

[2] “Josef“<br />

[3] “Liesel“<br />

[4] “Christian“<br />

Auf den Wert e<strong>in</strong>er Komponenten kann über den Array-Namen (z.B. args), gefolgt von e<strong>in</strong>em Index <strong>in</strong><br />

eckigen Klammern (z.B. [0]) zugegriffen werden. Mit<br />

args[0] = “Roland“;<br />

kann dem ersten Element des Array args e<strong>in</strong> neuer Wert zugewiesen werden.<br />

„;“: dient zum Beenden e<strong>in</strong>er Anweisung.<br />

„,“: wird häufig als Begrenzer (z.B. <strong>in</strong> e<strong>in</strong>er Parameterliste) benutzt.<br />

„.“: wird als Dezimalpunkt als auch zum Trennen solcher D<strong>in</strong>ge wie Paketnamen von<br />

Klassennamen oder Variablennamen benutzt (z.B. System.out.pr<strong>in</strong>tln(s);).<br />

Standardmäßig haben Klassen Zugriff auf die Klassen im Paket „java.lang“. Zur<br />

13


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bezugnahme auf e<strong>in</strong>e Klasse, die sich nicht <strong>in</strong> java.lang bef<strong>in</strong>det, s<strong>in</strong>d alle<br />

Pakete, <strong>in</strong> denen sich die Klasse bef<strong>in</strong>det, anzugeben, z.B.<br />

java.awt.Color // bezieht sich auf die Klasse Color im Paket awt,<br />

// das sich im Paket java bef<strong>in</strong>det.<br />

Leerraumzeichen: Sie können <strong>in</strong> beliebiger Anzahl und an jedem Ort zwischen<br />

Token (, die e<strong>in</strong>e Funktion besitzen) zur übersichtlichen Gestaltung des Quellcodes<br />

plaziert werden. Solche Zeichen s<strong>in</strong>d bspw.: Space, Tab, Zeilenende,<br />

Formularvorschub<br />

Kommentar: Er wird vom Compiler ignoriert. Man unterscheidet den Kommentar bis<br />

zum Zeilenende „//“ und den e<strong>in</strong>gebetteten Kommentar „/* ... */“, z.B.:<br />

/* ErstesProgramm ist e<strong>in</strong>e Applikation, die den e<strong>in</strong>fachen<br />

Gebrauch von Zeichenketten aufzeigt */<br />

Übersetzung und Ausführung.<br />

Bef<strong>in</strong>det sich der Quelltext zum Programm <strong>in</strong> e<strong>in</strong>er Datei mit dem Namen<br />

ErstesProgramm.java, dann kann dieses Programm durch Aufruf des <strong>Java</strong>-<br />

Compilers javac <strong>in</strong> ablauffähigen Bytecode übersetzt werden. Das geschieht über<br />

das folgende Systemkommando:<br />

javac Erstes.Programm.java<br />

Den Byte-Code, den der <strong>Java</strong>-Compiler <strong>in</strong> der Datei ErstesProgramm.class<br />

h<strong>in</strong>terlegt hat, kann über das Kommando<br />

java ErstesProgramm<br />

zur Ausführung gebracht werden.<br />

Konsole: Arbeitsspeicher: Externspeicher<br />

javac ErstesProgramm.java ErstesProgramm.java<br />

javac<br />

java ErstesProgramm<br />

Abb. 0.3-2: Ablaufplan ErstesProgramm<br />

14<br />

ErstesProgramm.class<br />

ErstesProgramm.class<br />

<strong>Java</strong> (-Interpreter)<br />

"Das erste Programm der Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>"


0.3.2 Bestandteile e<strong>in</strong>es Programms<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Wesentliche Programmelemente <strong>in</strong> <strong>Java</strong> s<strong>in</strong>d:<br />

- Anweisungen<br />

Anweisungen 3 gehören zu den elementaren ausführbaren Programmelementen. E<strong>in</strong>e Anweisung<br />

kann e<strong>in</strong>e Deklaration enthalten, e<strong>in</strong>en Ausdruck 4 auswerten oder den Programmablauf 5 (Auswahl-,<br />

Iterations-, Sprung-Anweisungen und return-, throw-Anweisung) steuern.<br />

- Blöcke<br />

E<strong>in</strong> Block 6 ist e<strong>in</strong>e Zusammenstellung von Anweisungen, die nache<strong>in</strong>ander ausgeführt werden. E<strong>in</strong><br />

Block kann eigene Variable def<strong>in</strong>ieren, die nur <strong>in</strong>nerhalb des Blocks sichtbar s<strong>in</strong>d. Sie werden beim<br />

Aufruf des Blocks angelegt und beim Verlassen des Blocks zerstört. Innerhalb e<strong>in</strong>es Blocks s<strong>in</strong>d nur<br />

die lokalen Variablen des Blocks und die lokalen Variablen des umgebenden Blocks bzw. der<br />

umgebenden Methode sichtbar. Nach außen stellt sich der Block als e<strong>in</strong>e e<strong>in</strong>zige Anweisung dar.<br />

- Methoden<br />

Methoden 7 unterscheiden sich von Blöcken folgendermaßen:<br />

-- Sie haben e<strong>in</strong>en Namen und können von verschiedenen Stellen des Programms aufgerufen<br />

werden.<br />

-- Sie s<strong>in</strong>d parametrisierbar<br />

-- Sie können e<strong>in</strong>en Rückgabewert besitzen.<br />

Methoden werden <strong>in</strong> <strong>Java</strong> immer lokal zu e<strong>in</strong>er Klasse def<strong>in</strong>iert.<br />

- Klassen<br />

Sie 8 enthalten Variablen zur Beschreibung des Zustands von Objekten und Methoden zur<br />

Beschreibung des Verhaltens von Objekten.<br />

- Schnittstellen<br />

E<strong>in</strong>e Schnittstelle (Interface) ist e<strong>in</strong>e Sammlung von Methoden, die e<strong>in</strong>en Namen besitzen, aber nicht<br />

implementiert s<strong>in</strong>d. E<strong>in</strong> Klasse kann beliebig viele Schnittstellen implementieren. Dadurch wird die<br />

Klasse zur Implementierung der Methode gezwungen, deren Namen von der Schnittstelle def<strong>in</strong>iert<br />

wurden. Falls zwei unterschiedliche Klassen, dieselbe Schnittstelle implementieren, können beide auf<br />

Aufrufe der Methode, die <strong>in</strong> der Schnittstelle def<strong>in</strong>iert s<strong>in</strong>d, reagieren. Allerd<strong>in</strong>gs kann die Reaktion<br />

auf diese Methodenaufrufe bei e<strong>in</strong>zelnen Klassen total unterschiedlich se<strong>in</strong>.<br />

- Pakete<br />

E<strong>in</strong> Paket ist e<strong>in</strong>e Sammlung von Klassen. Jede Klasse <strong>in</strong> <strong>Java</strong> gehört zu e<strong>in</strong>em Paket. Pakete<br />

ermöglichen, saß Sammlungen von Klassen bei Bedarf verfügbar s<strong>in</strong>d. Die Klassenbibliotheken<br />

bef<strong>in</strong>den sich <strong>in</strong> e<strong>in</strong>em Paket mit dem Namen „java“. Dieses Paket be<strong>in</strong>haltet Pakete, die spezielle<br />

Bestandteile der Sprache <strong>Java</strong>, z.B. Dateie<strong>in</strong>gabe und Datenausgabe, Multimedia, etc. def<strong>in</strong>ieren.<br />

Standardmäßig haben Klassen der Anwender nur Zugrifff auf Klassen im Paket „java.lang“<br />

(Standard-Feature). Klassen irgende<strong>in</strong>es anderen Pakets müssen importiert werden.<br />

- Applikationen (Anwendungen)<br />

Anwendungen (Applikationen) bilden die eigenständigen Programme. Sie benötigen zur Ausführung<br />

ke<strong>in</strong>en Browser, sondern nur den <strong>Java</strong>-Interpreter und die .class-Dateien der verwendeten<br />

Klassen.<br />

- Applets<br />

Applets s<strong>in</strong>d ebenfalls lauffähige <strong>Java</strong>-Programme. Sie werden aus e<strong>in</strong>er HTML-Seite aufgerufen und<br />

benötigen zur Ausführung e<strong>in</strong>en Web-Browser (oder e<strong>in</strong> Werkzeug wie den Appletviewer). Applets müssen<br />

von der Klasse Applet abgeleitet und nach den Regeln dieser Klasse aufgebaut se<strong>in</strong>. Zum Starten des<br />

Programms erzeugt der Browser e<strong>in</strong>e Instanz der abgeleiteten Klasse und ruft e<strong>in</strong>e Reihe vordef<strong>in</strong>ierter<br />

Callback-Methoden 9 auf.<br />

3 vgl. 2.4<br />

4 vgl. 2.4.5<br />

5 vgl. 2.4.6<br />

6 vgl. 2.4.1<br />

7 vgl. 2.6<br />

8 vgl. 2.5<br />

9 CallBack-Methoden s<strong>in</strong>d von der abgeleiteteten Klasse zur Verfügung gestellte Methoden, die vom Browser<br />

bzw. Appletviewer aufgerufen werden<br />

15


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1. E<strong>in</strong>führung <strong>in</strong> die <strong>Java</strong>-Programmierung<br />

1.1 Übersicht zur Entwicklung der Programmiersprache <strong>Java</strong><br />

<strong>Java</strong> ist <strong>in</strong> den Entwicklungslaboren der amerikanischen Firma Sun Microsystems 10<br />

entstanden. Man entschied sich bei Sun zur Realisierung e<strong>in</strong>es im Jahre 1990<br />

begonnenen Projekts 11 für e<strong>in</strong>e neue Programmiersprache, da bisher entwickelte<br />

Programme mit vorliegenden Programmiersprachen zu große Schwächen zeigten.<br />

Der erste Versuch war nur bed<strong>in</strong>gt erfolgreich. Lediglich der damals im Internet<br />

verbreitete Mosaic-Browser 12 wurde zu e<strong>in</strong>er Zielplattform der neuen<br />

Programmiersprache 13 , die Ende 1994 für das Internet umgearbeitet wurde und über<br />

das Netz frei und umsonst verteilt wurde.<br />

1995 wurde die neue Programmiersprache mit dem Namen <strong>Java</strong> 14 der Internet-<br />

Öffentlichkeit <strong>in</strong> Komb<strong>in</strong>ation mit e<strong>in</strong>em Browser, Hot<strong>Java</strong>, präsentiert. Hot<strong>Java</strong><br />

war die erste komplexe und vollständig <strong>in</strong> <strong>Java</strong> geschriebene Anwendung, der erste<br />

<strong>Java</strong>-fähige Browser und damit die Präsentationsform für die ersten <strong>Java</strong>-Applets.<br />

Außerdem war dieser Browser e<strong>in</strong>e wesentliche Ergänzung des ersten <strong>Java</strong>-<br />

Entwicklungstools von Sun – das <strong>Java</strong> Develelopment Kit (JDK 1.0). E<strong>in</strong><br />

kommerzielles Produkt, der <strong>Java</strong> Workshop 15 , wurde kurz nach der Präsentation von<br />

JDK 1.0 bereitgestellt.<br />

Natürlich gab es im JDK noch diverse K<strong>in</strong>derkrankheiten. Im zweiten Quartal 1997<br />

fogte deshalb nach e<strong>in</strong>igen Zwischenversionen die Version 1.1 des JDK. Parallel zur<br />

10 Sun ist e<strong>in</strong>e der führenden Hersteller von Workstations<br />

11 Entwicklung e<strong>in</strong>es vollkommen neuen, plattformunabhängigen Betriebssystems für den „Consumerbereich der<br />

allgeme<strong>in</strong>en Elektronk (Telefone, Videorecorder, Waschmasch<strong>in</strong>en, Kaffemasch<strong>in</strong>en; eigentlich alle elektrischen<br />

Masch<strong>in</strong>en, die Daten benötigen)<br />

12 der erste WWW-Browser mit e<strong>in</strong>er grafischen Benutzeroberfläche. WWW steht für World Wide Web und ist<br />

<strong>in</strong>zwischen die wichtigste Stütze im Internet. Das WWW ist im wesentlichen durch sog. Hypertexte aufgebaut,<br />

die mit der Sprache HTML entwickelt wurden und werden. E<strong>in</strong> Hypertext ist im wesentlichen e<strong>in</strong> ASCII-Text,<br />

der durch makierte Wörter (sog. Hyperl<strong>in</strong>ks) zu weiteren Seiten führt. Hypertext ist eigentlich nur e<strong>in</strong> Text mit<br />

Verweisen auf andere Texte. Der Verweis auf den weiterführenden Text kann aktiviert werden (z.B. durch<br />

Mausklick), und es wird zu dem gewünschten Text verzweigt.<br />

Das Hypertext Transfer Protocol (HTTP) dient zur Übertragung von Informationen aus dem WWW. HTTP ist<br />

e<strong>in</strong> objektorientiertes Protokoll (TCP/IP-Programm) zur e<strong>in</strong>fachen Übertragung von Hypertext-Dokumenten<br />

zwischen Client und Server. Client-Programme, die HTTP benutzen, werden (<strong>in</strong> der Regel) als Web-Browser,<br />

Server-Programme als Web-Server bezeichnet. Der Browser schickt an den Server die Aufforderung e<strong>in</strong>e<br />

bestimmte HTML-Seite zu übertragen. Falls er <strong>in</strong> dieser Seite weitere Verweise (z.B. auf Bilder) entdeckt,<br />

schickt er weitere Übertragungswünsche h<strong>in</strong>terher. Das Besorgen der gewünschten Dokumente erfolgt über e<strong>in</strong><br />

e<strong>in</strong>heitliches Adressierungsschema, dem Uniform Resource Loader (URL), durch den Internet-Standort und die<br />

Art der zu übertragenden Information identifiziert werden.<br />

13 Dem WWW mit dem bis zu diesem Zeitpunkt realisierten Stand der HTML fehlten: dreidimensionale<br />

Darstellung der Objekte, e<strong>in</strong>e bewegte Animation und e<strong>in</strong>e Möglichkeit zur vernünftigen Interaktion mit dem<br />

Anwender. Deshalb waren hier die Multimedia- und Interaktionseigenschaften der neuen Programmiersprache<br />

besonders erfolgreich.<br />

14 verantwortlich für <strong>Java</strong> ist die Firma <strong>Java</strong>Soft – e<strong>in</strong>e Tochterfirma von Sun Microsystems. Sun bzw. <strong>Java</strong>Soft<br />

halten im Internet permanent die aktuellste Information von <strong>Java</strong> bereit. E<strong>in</strong>ige der Informationen f<strong>in</strong>det man<br />

bereits auf der E<strong>in</strong>stiegseite von Sun (http://java.sun.com), andere Informationen bekommt man von der<br />

Neuigkeitenseite (http://java.sun.com/nav/new/<strong>in</strong>dex.html)<br />

15 mit Test- und Debug-Möglichkeiten, e<strong>in</strong>em Referenzcompiler, e<strong>in</strong>er <strong>in</strong>tegrierten Entwicklungsumgebung mit<br />

Editor, Browser, Project-, Portfolio- und Build-Manager, Debugger, Project-Tester und Onl<strong>in</strong>e-Hilfe. Der<br />

Workshop geht mit der Version 2.0 <strong>in</strong>zwischen <strong>in</strong> e<strong>in</strong>e neue Phase zur Unterstützung des neuen <strong>Java</strong>.<br />

16


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1.1.x-Version gab es auch e<strong>in</strong>en neuen Hot-<strong>Java</strong>-Browser zur Unterstützung der<br />

neuen 1.1-API-Funktionen.<br />

<strong>Java</strong> 1.2 ist die neueste Version. In Verb<strong>in</strong>dung mit dem JDK 1.2 wurde der Begriff<br />

<strong>Java</strong> 2 16 e<strong>in</strong>geführt. Inzwischen gibt es schon die Version 1.3, die nur wenige neue<br />

Programmierschnittstellen bietet, dafür aber e<strong>in</strong>e komfortablere und schnellere<br />

Laufzeitumgebung.<br />

Seit Version 1.2 ist <strong>Java</strong> <strong>in</strong> verschiedenen Ausgaben (Editionen) erhältlich. Sun hat<br />

drei verschiedene Editionen mit unterschiedlicher ausrichtung def<strong>in</strong>iert:<br />

1. Standard-Edition für den Desktop Client oder PC<br />

2. Enterprise-Edition für Application Server<br />

3. Micro-Edition für Kle<strong>in</strong>geräte.<br />

Am weitesten entwickelt ist die Standard-Edition.<br />

Neben dem JDK gibt es zahlreiche kommerzielle Entwicklungstolls für <strong>Java</strong>-<br />

Programmierer, z. B.: Symantec Visual Café, Borland JBuilder, SuperCade, National<br />

Intelligence Roaster, SunSoft <strong>Java</strong> Workshop.<br />

1.2 Was ist <strong>Java</strong>?<br />

<strong>Java</strong> ist 17 e<strong>in</strong>e e<strong>in</strong>fache, objektorientierte, dezentrale, <strong>in</strong>terpretierte, stabil laufende,<br />

sichere, architekturneutrale, portierbare und dynamische Sprache, die<br />

Hochleistungs-geschw<strong>in</strong>digkeits-Anwendungen und Multithread<strong>in</strong>g unterstützt.<br />

- <strong>Java</strong> ist e<strong>in</strong>fach, obwohl es sehr nahe an der ziemlich komplizierten C/C++-Syntax entworfen wurde.<br />

Die komplexen Teile von C/C++ wurden jedoch aus <strong>Java</strong> ausgeschlossen. In <strong>Java</strong> gibt es ke<strong>in</strong>e<br />

Zeiger (Po<strong>in</strong>ter) und auch ke<strong>in</strong>e Zeiger-Arithmetik. Str<strong>in</strong>gs und Arrays s<strong>in</strong>d echte Objekte. Die<br />

Speicherverwaltung erfolgt weitgehend automatisch.<br />

Die Ausdrücke <strong>in</strong> <strong>Java</strong> 18 entsprechen aber weitgehend denen von C/C++. <strong>Java</strong> besitzt e<strong>in</strong>e „if“-<br />

Anweisung, e<strong>in</strong>e „while“-, „do“- und „for“-Schleife und e<strong>in</strong>e „switch“-Anweisung. Es gibt die von C<br />

bekannten „break“- und „cont<strong>in</strong>ue“-Anweisungen (<strong>in</strong> normaler und mit e<strong>in</strong>em „Label“ versehenen<br />

Form) 19 .<br />

- <strong>Java</strong> ist kle<strong>in</strong>. E<strong>in</strong>e der ursprünglichen Ziele von <strong>Java</strong> war die Erleichterung der Software-Entwicklung für<br />

kle<strong>in</strong>e Rechner.<br />

- <strong>Java</strong> ist objektorientiert. Es gehört zu e<strong>in</strong>er Familie von Sprachen, die Daten als Objekte def<strong>in</strong>ieren<br />

und Methoden zur Bearbeitung dieser Objekte verwenden. Das objektorientierte Konzept von <strong>Java</strong><br />

hat viel von C++ geerbt, aber auch Konzepte anderer objektorientierter Sprachen wurden<br />

übernommen. Wie die meisten objektorientierten Sprachen umfaßt <strong>Java</strong> e<strong>in</strong>e umfangreiche<br />

Klassenbibliothek, die grundlegende Datentypen, Systeme<strong>in</strong>- und Systemausgabe und andere<br />

Hilfsmittel (utilities) bietet. Die grundlegenden Klassem s<strong>in</strong>d Teil des JDK, das darüber h<strong>in</strong>aus noch<br />

Klassen besitzt, die Funtionen im Zusammenhang mit <strong>in</strong> Netzwerken üblichen Internet-Protokollen<br />

und Benutzeroberflächen unterstützen. Da diese Klassenbibliotheken <strong>in</strong> <strong>Java</strong> geschrieben s<strong>in</strong>d, s<strong>in</strong>d<br />

sie wie alle <strong>Java</strong>-Anwendungen auf alle Plattformen portierbar.<br />

- <strong>Java</strong> ist dezentral und erfüllt e<strong>in</strong>e wesentliche Eigenschaft von Client/Server-Anwendungen. Die<br />

Fähigkeit der Verteilung von Informationen für die Berechnung der Daten. „Dezentral“ beschreibt die<br />

Beziehung von Systemobjekten: Es ist gleichgültig, ob die Objekte sich auf lokalen oder entfernten<br />

16 Die exakte Bezeichnung für das JDK 1.2 ist <strong>Java</strong> 2 JDK v1.2. Nähere Information enthält die Webseite:<br />

http://java.sun.com/products/jdk/1.2/java2.html<br />

17 Offizielle Def<strong>in</strong>ition von Sun Microsystems<br />

18 vgl. 2.3<br />

19 vgl. 2.4.<br />

17


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Systemen bef<strong>in</strong>den. Objekte können mit <strong>Java</strong>-Programmen über URLs 20 vom gesamten Web<br />

genauso wie auf dem lokalen Rechner geöffnet und bearbeitet werden. Wichtige Teile der<br />

Anwendung bzw. der Daten können lokal vorhanden se<strong>in</strong>, andere werden bei Bedarf geladen.<br />

- <strong>Java</strong> ist <strong>in</strong>terpretiert. E<strong>in</strong> gewisser Teil des <strong>Java</strong>-Codes (ca. 20 %) werden vom Conta<strong>in</strong>er, dem<br />

Browser <strong>in</strong>terpretiert. Der <strong>Java</strong>-Quellcode wird mit dem <strong>Java</strong>-Compiler <strong>in</strong> Bytecode<br />

(architekturneutrales Object-Code-Format) kompiliert. Bytecode ist nicht lauffähig, bis er von der<br />

<strong>Java</strong>-Laufzeitumgebung 21 <strong>in</strong>terpretiert wird.<br />

<strong>Java</strong>-Code<br />

Abb. 1.2-1:<br />

<strong>Java</strong>-Compiler (Pentium) <strong>Java</strong>-Interpreter (Pentium)<br />

<strong>Java</strong>-Compiler (SPARC) <strong>Java</strong>-Interpreter (SPARC)<br />

- <strong>Java</strong> ist stabil, d.h. zuverlässig. Die Stabilität e<strong>in</strong>er Programmiersprache zeigt sich dar<strong>in</strong>, daß<br />

während der Kompilierungsphase der gößte Teil der Datenüberprüfung ausgeführt werden kann.<br />

<strong>Java</strong> ist stark typisiert. Damit können Fehler früh gefunden werden. E<strong>in</strong> weiteres Stabilitätskriterium<br />

von <strong>Java</strong>-Programmen ist die e<strong>in</strong>gebaute Begrenzung der Zugriffsmöglichkeiten auf den<br />

Speicherbereich des Rechners 22 . H<strong>in</strong>zu kommt auch noch die anschließende<br />

Sicherheitsüberprüfung durch den „L<strong>in</strong>ker“. Der L<strong>in</strong>ker ist e<strong>in</strong> Teil der Laufzeitumgebung, das die im<br />

System e<strong>in</strong>gehenden Daten überprüft.<br />

20 Rechner s<strong>in</strong>d über IP-Nummern bzw. über Alias-Namen (Doma<strong>in</strong>-Name-System, DNS) im Internet e<strong>in</strong>deutig<br />

adressiert. Innerhalb des Internet müssen aber auch alle Daten und Programme über unverwechselbare Internet-<br />

Adressen bestimmt se<strong>in</strong>. Der Name dieser Internet-Adressen für konkrete Adreßanfragen an Dokumente im<br />

Internet lautet URL und steht für Uniform Resource Locator („e<strong>in</strong>heitliches Adressierungsschema für<br />

„Objekte“ im Internet). „E<strong>in</strong>heitlich“ deshalb, weil mit e<strong>in</strong>er URL sowohl die verschiedenen Dienste (WWW,<br />

FTP, Gopher usw.) als auch Rechner oder Dokumente beschrieben werden können. Der Begriff „Objekt“ steht<br />

bspw. für Datei, Text, Videos, Sounds usw., also für ziemlich alles, was sich im Netz bef<strong>in</strong>det. Die exakte<br />

Schreibweise e<strong>in</strong>er URL ist je nach Dienstprotokoll etwas unterschiedlich, sieht jedoch <strong>in</strong> der Regel so aus:<br />

Dienstprotokoll://host.doma<strong>in</strong>:port/pfad/datei<br />

Dienstprotokoll ist bspw.: http, ftp, gopher, news, mailto, wais. Danach folgen fast immer Doppelpunkt und zwei<br />

Slashes (Ausnahme: mailto).<br />

Mit hosts.doma<strong>in</strong> wird e<strong>in</strong> Rechner im Internet adressiert. Dabei kann die IP-Nummer des Rechner angegeben<br />

werden (unüblich). Häufiger nimmt man dafür den DNS-Namen (<strong>in</strong> der Form<br />

host.{localDoma<strong>in</strong>}.SecondLevelDoma<strong>in</strong>.TopLevelDoma<strong>in</strong>.<br />

Auf e<strong>in</strong>em Internet-Rechner kann unter e<strong>in</strong>em Namen e<strong>in</strong>e ganze Reihe von verschiedenen Diensten parallel<br />

betrieben werden (z.B. FTP-Server, HTTP-Server). Zum Erreichen des gewünschten Dienstes auf dem<br />

ausgewählten Rechner benötigt man den sog. Port. Ports s<strong>in</strong>d numerische Werte (zwischen 0 und 1023). In der<br />

Regel hat jeder Internet-Dienst e<strong>in</strong>en Default-Wert, der immer verwendet wird, wenn ke<strong>in</strong> Port explizit<br />

angegeben ist. Der Port für e<strong>in</strong>en HTTP-Server ist immer „80“, e<strong>in</strong> FTP-Server hat immer den Port „21“.<br />

Das genaue Objekt verbirgt sich h<strong>in</strong>ter der Angabe /pfad/datei.<br />

21 Normalerweise durch e<strong>in</strong>en <strong>Java</strong>-Browser<br />

22 Ungeprüfte Zugriffe auf Speicherbereiche des Rechners ermöglicht C/C++ (Zeigerarithmetik, implizite<br />

Deklaration)<br />

18


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

- <strong>Java</strong> gilt als sicher. In dieser H<strong>in</strong>sicht muß sich <strong>Java</strong> allerd<strong>in</strong>gs noch bewähren 23 .<br />

- <strong>Java</strong> ist auf verschieden Systemen mit unterschiedlichen Prozessoren und Betriebssystem-<br />

Architekturen lauffähig (architekturneutral). Die komplette <strong>Java</strong>-Bytecode kann auf jedem Prozessor<br />

ausgeführt werden, der e<strong>in</strong>en javafähigen Browser (bspw. die virtuelle Masch<strong>in</strong>e von <strong>Java</strong> 24 )<br />

unterstützt. Plattformunabhängiger B<strong>in</strong>ärcode wird allerd<strong>in</strong>gs nicht erzeugt, sondern <strong>Java</strong>-Bytecode<br />

wird während der Laufzeit <strong>in</strong> systemeigenen Masch<strong>in</strong>encode übertragen (<strong>in</strong>terpretiert).<br />

- <strong>Java</strong> unterstützt „Multithread<strong>in</strong>g“. „Multthread<strong>in</strong>g bedeutet: Mehrere Aufgaben oder Prozesse können<br />

gleichzeitig ausgeführt werden. Nicht die quasi gleichzeitige Ausführung mehrerer Programme<br />

(Multitask<strong>in</strong>g), sondern die gleichzeitige, parallele Ausführung von e<strong>in</strong>zelnen Programmschritten<br />

(oder zusammenhängenden Prozessen) ist „Multithread<strong>in</strong>g“. Das kann bedeuten: Innerhalb e<strong>in</strong>es<br />

Programms können mehrere D<strong>in</strong>ge gleichzeitig geschehen, mehrere Faden / Threads e<strong>in</strong>es<br />

Programms können gleichzeitig verfolgt und abgearbeitet werden.<br />

23 Verschiedene Sicherheitslücken wurden aufgedeckt und wurden <strong>in</strong>zwischen beseitigt.<br />

24 Die virtuelle Masch<strong>in</strong>e wird auch als <strong>Java</strong> Interpreter oder <strong>Java</strong> Environment (<strong>Java</strong>-Laufzeitumgebung)<br />

bezeichnet<br />

19


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1.3 E<strong>in</strong>stieg <strong>in</strong> die <strong>Java</strong>-Programmierung<br />

1.3.1 Die Software für die <strong>Java</strong>-Programmierung<br />

Das JAVA Development Kit (JDK) enthält die Entwicklungsumgebung zum<br />

Schreiben von <strong>Java</strong> Programmen. Das JDK ist für Sun-SPARC-Systeme mit Solaris<br />

2.2 (oder höher) sowie für W<strong>in</strong>dows NT und W<strong>in</strong>dows 95 über das Internet 25<br />

erhältlich.<br />

Nach der Installation hat das <strong>Java</strong>-Verzeichnis 26 folgenden Inhalt 27 :<br />

Abb. 1.3-1: Inhalt des <strong>Java</strong>-Verzeichnisses<br />

Innerhalb des <strong>Java</strong>-Verzeichnisses bef<strong>in</strong>den sich Unterverzeichnisse 28 mit<br />

folgendem Inhalt:<br />

Verzeichnis Inhalt<br />

\b<strong>in</strong> In diesem Verzeichnis bef<strong>in</strong>den sich die JDK-Programme<br />

\lib In diesem Verzeichnis bef<strong>in</strong>den sich defaultmäßig die Standard-<strong>Java</strong>-Klassen des<br />

JDK 29<br />

\<strong>in</strong>clude In diesem Verzeichnis bef<strong>in</strong>den sich diverse Header-Dateien für die geme<strong>in</strong>same<br />

Verwendung von <strong>Java</strong> und C/C++<br />

\demo Das Demo-Verzeichnis e<strong>in</strong>thälz Beispielprogramme<br />

\src Falls „<strong>Java</strong>-Source“ im InstallShield ausgewählt wurde, wird dieses Verzeichnis<br />

25 Das jeweils aktuelle JDK (aber auch ältere Versionen) können von den Sun-Microsytem-Webseiten bzw. der<br />

<strong>Java</strong>Soft-Homepage geladen werden (http://www.sun.com bzw. http://www.javasoft.com/ ). Genutzt werden kann<br />

auch die <strong>Java</strong>Soft-WWW-Download-Seite für das jeweilige JDK (http://java.sun.com.products/jdk/x.x , die<br />

Angabe x.x ist durch die gewünschte Versionsnummer zu ersetzen). Auch e<strong>in</strong>e FTP-Download, z.B. vom Sun-<br />

FTP-Server (ftp.javasoft.com) ist möglich.<br />

26 Erzeugt von der Entpackungsrout<strong>in</strong>e des JDK<br />

27 Das Verzeichnis „me<strong>in</strong>epr“ dient zur Aufnahme von Projekten und zählt nicht standardmäßig zum Inhalt e<strong>in</strong>es<br />

<strong>Java</strong>-Verzeichnisses<br />

28 unter W<strong>in</strong>dows<br />

29 Im wesentlichen ist das die Datei classes.zip<br />

20


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

mit angelegt. Dar<strong>in</strong> bef<strong>in</strong>den sich die entkomprimierten <strong>Java</strong>-Dateien, die sonst<br />

nur im gepackten Zustand (Datei SRC.ZIP) vorhanden s<strong>in</strong>d.<br />

Es ist s<strong>in</strong>nvoll, die <strong>in</strong> der JDK-Umgebung verfügbaren Werkzeuge von allen<br />

Verzeichnissen aus zugänglich zu machen. Für W<strong>in</strong>dows-NT und W<strong>in</strong>dows-95-<br />

Anwender wird das Verzeichnis mit den Werkzeugen <strong>in</strong> der Pfadangabe der Datei<br />

„autoexec.bat“ e<strong>in</strong>getragen, z.B.:<br />

PATH c:\;C:\ORAWIN95\BIN;c:\w<strong>in</strong>dows;c:\w<strong>in</strong>dows\command;c:\jdk1.1.6\b<strong>in</strong>;c:\jdk1.1.6\<strong>in</strong>clude;<br />

Die CLASSPATH-Umgebungsvariable 30 sollte unter W<strong>in</strong>dows <strong>in</strong> der Datei<br />

„autoexec.bat“ so vorliegen:<br />

set classpath=c:\jdk1.1.6\lib\classes.zip;<br />

Im JDK 1.2 wird die CLASSPATH-Umgebungsvariable nicht mehr benötigt. Ist<br />

allerd<strong>in</strong>gs e<strong>in</strong>e CLASSPATH-Variable gesetzt, so wird sie auch verwendet.<br />

Nach der Installation des JDK 1.2 bzw. JDK 1.3 muß das Verzeichnis<br />

\jdk1.3\b<strong>in</strong> <strong>in</strong> den Suchpfad ausführbarer Dateien e<strong>in</strong>getragen werden. Das<br />

kann direkt <strong>in</strong> der autoexec.bat durch Modifikation der PATH-Anweisung, mit Hilfe<br />

e<strong>in</strong>er Batch-Datei oder direkt erledigt werden, z.B.:<br />

set PATH=d:\jdk1.3\b<strong>in</strong>;%PATH%<br />

30 Umgebungsvariable s<strong>in</strong>d E<strong>in</strong>stellungen, mit denen die Hot<strong>Java</strong>- und <strong>Java</strong>-Interpreter-Umgebungen des<br />

Systems spezifiziert werden. Sie werden z.B. unter W<strong>in</strong>dows im allg. auf Befehlszeilenebene oder <strong>in</strong> der<br />

„autoexec.bat“ mit der Anweisung „SET [Umgebungsvariable]= ....“ gesetzt.<br />

CLASSPATH ist die wichtigste der Umgebungsvariablen von <strong>Java</strong>. Mit dieser Umgebungsvariablen wird<br />

bestimmt, woher die Systemklassen importiert werden.<br />

21


1.3.2 Applets und Anwendungen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

<strong>Java</strong> Programme werden <strong>in</strong> zwei Hauptanwendungs-Gruppen gegliedert: Applets<br />

und Anwendungen.<br />

Applets s<strong>in</strong>d <strong>Java</strong>-Programme, die über das WWW heruntergeladen und von e<strong>in</strong>em<br />

Web-Browser auf dem Rechner des Anwenders ausgeführt werden. Applets können<br />

nur auf e<strong>in</strong>em javafähigen Browser ausgeführt werden bzw. mit e<strong>in</strong>em Tool des JDK,<br />

dem Appletviewer, gesichtet werden.<br />

<strong>Java</strong>-Anwendungen s<strong>in</strong>d allgeme<strong>in</strong>e, <strong>in</strong> der <strong>Java</strong>-Sprache geschriebene Programme.<br />

Zum Ausführen von <strong>Java</strong>-Anwendungen ist ke<strong>in</strong> Browser nötig.<br />

1.3.2.1 Entwicklung von <strong>Java</strong>-Anwendungen<br />

1. Aufgabe: Erstelle e<strong>in</strong>e Anwendung, die den Text „Willkommen <strong>in</strong> der <strong>Java</strong>-<br />

Welt“ ausgibt.<br />

Lösungsschritte:<br />

1) Erstelle die folgende Datei mit dem Namen „Willkommen.java“ mit Hilfe e<strong>in</strong>es<br />

Dateiaufbereiters (Editor):<br />

class Willkommen<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

System.out.pr<strong>in</strong>tln("Willkommen <strong>in</strong> der <strong>Java</strong>-Welt!");<br />

}<br />

}<br />

Das Programm umfaßt zwei Teile: e<strong>in</strong>e Klassendef<strong>in</strong>ition und e<strong>in</strong><br />

Programmabschnitt, der unter ma<strong>in</strong>() angegeben ist.<br />

2) Speichern der Datei mit dem Namen „Willkommen.java“ unter e<strong>in</strong>em beliebigen<br />

Verzeichnis 31 .<br />

3) Aufruf des <strong>Java</strong>-Übersetzers über die folgende Befehlszeilene<strong>in</strong>gabe: javac<br />

[optionen] date<strong>in</strong>ame.<br />

optionen .... bestimmen das Verhalten vom Compiler<br />

date<strong>in</strong>ame ... Name der Datei mit dem <strong>Java</strong>-Quellcode. „javac“ fordert, daß<br />

der Quelltext <strong>in</strong> Dateien steht, deren Date<strong>in</strong>ame die Extension „.java“<br />

besitzt.<br />

„javac“ kompiliert den Quellcode <strong>in</strong> <strong>Java</strong>-Bytecode und speichert se<strong>in</strong>e Ausgabe <strong>in</strong><br />

e<strong>in</strong>er Datei mit dem Namen „date<strong>in</strong>ame.class“. Standardmäßig werden .class-<br />

Dateien im gleichen Verzeichnis wie die .java-Quelldatei erzeugt 32 . Im<br />

vorliegenden Fall ist der Aufruf: javac Willkommen.java.<br />

4) Ausführen der Bytecode-Datei „Willkommen.class“ mit dem <strong>Java</strong>-Interpreter<br />

java: „java Willkommen“. Der im JDK enthaltene Interpreter heißt „java“. Falls<br />

alles richtig gelaufen ist, ersche<strong>in</strong>t <strong>in</strong> der letzten (Ausgabe-) Zeile: Willkommen <strong>in</strong><br />

der <strong>Java</strong>-Welt!.<br />

31 Vgl. PR13210<br />

32 Mit der Option „-d“ im javac-Aufruf kann die .class-Dateii an e<strong>in</strong>em anderen Ort gespeichert werden.<br />

22


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2. Aufgabe: Erstelle e<strong>in</strong>e Anwendung, die den Text „Herzlich Willkommen<br />

Juergen Hubert Josef Liesel“ ausgibt. Die angebenen Namen<br />

sollen auf Befehlszeilenebene als Parameter e<strong>in</strong>geben werden.<br />

Lösungsschritte:<br />

1) Erstellen e<strong>in</strong>er Quelle (Datei), die folgenden Quellcode 33 enthält:<br />

class WillkommensGruss<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

System.out.pr<strong>in</strong>t("Herzlich Willkommen ");<br />

System.out.pr<strong>in</strong>t(args[0]);<br />

}<br />

}<br />

2) Speichern der Datei, Übersetzen und Aufruf des Programm mit dem Parameter<br />

Juergen führt zu: „Herzlich Willkommen Juergen“.<br />

Argumente auf Befehlszeilenebene werden <strong>in</strong> den Zeichenketten-Array „Str<strong>in</strong>g<br />

args[]“ aufgenommen. „args“ ist der Name des Zeichenketten-Arrays, das die<br />

Argumentenliste enthält und dem Programm immer zur Verfügung steht. Hier wurde<br />

nur das erste Argument der Liste (args[0])ausgegeben. Sollen alle Argumente, die<br />

auf der Befehlszeileneben e<strong>in</strong>gegeben wurden, ausgegeben werden, dann ist die<br />

Liste komponentenweise mit e<strong>in</strong>er Zählschleife abzuarbeiten. Die Zählschleife (for-<br />

Schleife) sieht <strong>in</strong> <strong>Java</strong> so aus:<br />

for (Initialisierung; Test; Inkrement)<br />

{<br />

// Anweisungen<br />

}<br />

Initialisierung ist e<strong>in</strong> Ausdruck, der den Beg<strong>in</strong>n der Zählschleife e<strong>in</strong>leitet, z.B.<br />

Initialiserung e<strong>in</strong>es Schleifen<strong>in</strong>dex (z.B. <strong>in</strong>t i = 0;). Die Variablen, die <strong>in</strong> diesem<br />

Teil der Schleife deklariert werden, s<strong>in</strong>d lokal (<strong>in</strong> Bezug auf die Schleife). Das<br />

bedeutet: Sie gehören zur Schleife und existieren nicht mehr nach der vollständigen<br />

Ausführung der Schleife. Man kann <strong>in</strong> diesem Bereich mehr als e<strong>in</strong>e Variable<br />

<strong>in</strong>itialisieren (durch Angabe mehrerer durch Kommas getrennte Ausdrucke, z.B.<br />

<strong>in</strong>t i = 0, <strong>in</strong>t j = 10).<br />

Test ist e<strong>in</strong> Ausdruck, der nach jeder Iteration der Schleife ausgeführt wird. Der Test<br />

muß e<strong>in</strong> boolescher Ausdruck oder e<strong>in</strong>e Funktion se<strong>in</strong>, die e<strong>in</strong>en booleschen Wert<br />

zurückgibt (true oder false). Ergibt der Test true, wird die Schleife ausgeführt. Sobald<br />

er false ergibt, wird die Schleifenausführung angehalten.<br />

Inkrement ist e<strong>in</strong> beliebiger Audruck oder Funktionsaufruf. Üblicherweise wird er<br />

verwendet, um den Wert des Schleifen<strong>in</strong>dex näher an den Endwert zu br<strong>in</strong>gen und<br />

damit für Beendigung der Schleife zu sorgen. Wie im Initialisierungsbereich kann im<br />

Inkrement-Bereich mehr als e<strong>in</strong> Ausdruck untergebracht se<strong>in</strong>, falls die e<strong>in</strong>zelnen<br />

Ausdrücke mit Kommas vone<strong>in</strong>ander getrennt s<strong>in</strong>d.<br />

Auf den Wert e<strong>in</strong>es Elements <strong>in</strong> e<strong>in</strong>em Array wird über den Namen des Array,<br />

gefolgt von e<strong>in</strong>em Index <strong>in</strong> eckigen Klammern zugegriffen (z.B. args[i]). Array-<br />

Indizes beg<strong>in</strong>nen mit 0. Alle Array-Indizes werden geprüft, um sicher zu stellen, daß<br />

sie sich <strong>in</strong>nerhalb der Grenzen des Array bef<strong>in</strong>den, wie sie bei der Erzeugung des<br />

Arrays festgelegt wurden. Die Länge des Array kann im Programm mit der<br />

Instanzvariablen length getestet werden (z.B. args.length).<br />

33 Vgl. PR13210<br />

23


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3) Erweitern der Quellcode-Datei um e<strong>in</strong>e Zählschleife, die die Argumentenliste<br />

abarbeitet:<br />

class WillkommensGruss<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

<strong>in</strong>t i; // Lokale Variable<br />

System.out.pr<strong>in</strong>t("Herzlich Willkommen ");<br />

for (i=0; i < args.length;i++)<br />

{<br />

System.out.pr<strong>in</strong>t(args[i] + " ");<br />

}<br />

}<br />

}<br />

„args.length“ bestimmt die Länge der Argumentenliste.<br />

4) Speichern der Datei, Übersetzen und Aufruf des Programm mit Parametern führt<br />

zu: „Herzlich Willkommen Juergen Liesel Vera Christian Hubert“.<br />

3. Aufgabe: Die auf Befehlszeilenebene e<strong>in</strong>gegebenen Namen sollen sortiert<br />

werden. So soll die E<strong>in</strong>gabe der Befehlszeile „java<br />

WillkommensGruss Juergen Hubert Josef Liesel<br />

Christian“ zu folgender Ausgabe führen: „Herzlich Willkommen<br />

Christian Hubert Josef Juergen Liesel“.<br />

Lösungsschritte:<br />

1) Gesucht ist e<strong>in</strong> Algorithmus, der die über die Befehlszeile e<strong>in</strong>gegebenen Namen<br />

sortiert. E<strong>in</strong> e<strong>in</strong>facher Sortieralgorithmus ist unter dem Namen „Bubble-Sort“<br />

bekannt. Man vergleicht dabei zunächst den ersten unter args[0] abgelegten Namen<br />

gegen alle weiteren im Datenfeld args abgelegten Namen.<br />

args<br />

[0] “Juergen“<br />

[1] “Hubert“<br />

[2] “Josef“<br />

[3] “Liesel“<br />

[4] “Christian“<br />

Nach 4 Vergleichen hat das Datenfeld args folgende Gestalt angenommen:<br />

args<br />

[0] “Christian“<br />

[1] “Juergen“<br />

[2] “Josef“<br />

[3] “Liesel“<br />

[4] “Hubert“<br />

Die erste Position (args[0]) ist im Datenfeld damit schon richtig e<strong>in</strong>geordnet.<br />

Danach muß jetzt der Name an der 2. Position ([1]) mit den übrigen Namen des<br />

Datenfelds verglichen werden. Nach 3 Vergleichen zeigt sich folgendes Bild:<br />

24


args<br />

[0] “Christian“<br />

[1] “Hubert“<br />

[2] “Juergen“<br />

[3] “Liesel“<br />

[4] “Josef“<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

„Christian“ und „Hubert“ s<strong>in</strong>d jetzt richtig e<strong>in</strong>geordnet. Num muß der Name an der<br />

dritten Position mit allen noch verbliebenen Namen auf Position 4 und 5 noch<br />

verglichen werden. Das Resultat der Vergleiche zeigt:<br />

args<br />

[0] “Christian“<br />

[1] “Hubert“<br />

[2] “Josef“<br />

[3] “Liesel“<br />

[4] “Juergen“<br />

Der nächste Durchgang führt dann zum sortierten Datenfeld:<br />

args<br />

[0] “Christian“<br />

[1] “Hubert“<br />

[2] “Josef“<br />

[3] “Juergen“<br />

[4] “Liesel“<br />

2) Der soeben beschrieben Sortieralgorithmus muß <strong>in</strong> <strong>Java</strong>-Programmcode<br />

abgebildet werden. Es ist leicht erkennbar, daß hier zwei verschachtelte for-<br />

Schleifen die Sortierung erreichen können.<br />

for (i = 0; i < args.length; i++)<br />

{<br />

for (j = i + 1; j < args.length; j++)<br />

{<br />

if (args[i].compareTo(args[j]) > 0)<br />

{ // Tauschen<br />

Str<strong>in</strong>g temp = args[i]; // lokale Variable<br />

args[i] = args[j];<br />

args[j] = temp;<br />

}<br />

}<br />

}<br />

Zeichenketten werden über die Methode „compareTo“ der Klasse Str<strong>in</strong>g<br />

verglichen. Generell stehen die Vergleichsoperatoren (== != < >=) nur für<br />

das Vergleichen von Zahlen zur Verfügung.<br />

Die Vergleichsbed<strong>in</strong>gung wird durch das Schlüsselwort if erzeugt:<br />

if (Ausdruck)<br />

{<br />

// Anweisung(en)<br />

}<br />

else {<br />

// Anweisung(en)<br />

}<br />

E<strong>in</strong>e if-Bed<strong>in</strong>gung verwendet e<strong>in</strong>en booeleschen Ausdruck für die Entscheidung, ob<br />

e<strong>in</strong>e Anweisung ausgeführt werden soll. Die Anweisung wird ausgeführt, wenn der<br />

25


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Ausdruck den Wert true zurückliefert. Falls gewünscht wird, daß e<strong>in</strong>e bestimmete<br />

Anweisung bzw. Anweisungen ausgeführt werden, wenn der boolesche Ausdruck<br />

false zurückliefert, ist dieser Anweisungsblock durch das Schlüsselwort else<br />

e<strong>in</strong>zuleiten.<br />

3) Das vollständige Programm umfaßt folgenden Quelltext:<br />

class WillkommensGruss<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

<strong>in</strong>t i, j; // Lokale Variable<br />

System.out.pr<strong>in</strong>t("Herzlich Willkommen ");<br />

for (i = 0; i < args.length; i++)<br />

{<br />

for (j = i + 1; j < args.length; j++)<br />

{<br />

if (args[i].compareTo(args[j]) > 0)<br />

{<br />

Str<strong>in</strong>g temp = args[i];<br />

args[i] = args[j];<br />

args[j] = temp;<br />

}<br />

}<br />

}<br />

for (i = 0; i < args.length; i++)<br />

{<br />

System.out.pr<strong>in</strong>t(args[i] + " ");<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

}<br />

4) Speichern der Datei, Übersetzen und Aufruf des Programm mit Parametern führt<br />

zu: „Herzlich Willkommen Christian Hubert Josef Juergen Liesel“.<br />

26


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

4. Aufgabe: Die Argumentenliste args soll auf folgende Weise angezeigt werden:<br />

args[0] = “Christian“<br />

args[1] = “Hubert“<br />

args[2] = “Josef“<br />

args[3] = “Juergen“<br />

args[4] = “Liesel“<br />

Lösungsschritte:<br />

1) System.out.pr<strong>in</strong>tln() bzw. System.out.pr<strong>in</strong>t() erwarten e<strong>in</strong> e<strong>in</strong>ziges<br />

Argument <strong>in</strong>nerhalb der Klammern. Sollen, wie hier gewünscht, mehrere Variable<br />

vom Typ Str<strong>in</strong>g oder Zeichenkettenliterale Argument für pr<strong>in</strong>tln() se<strong>in</strong>, dann<br />

können diese Elemente mit dem Verkettungsoperator „+“ zu e<strong>in</strong>em e<strong>in</strong>zigen Str<strong>in</strong>g<br />

oder Zeichenkettenliteral verknüpft werden. Der Umgang mit dem<br />

Verkettungsoperator ist <strong>in</strong> <strong>Java</strong> e<strong>in</strong>fach, da er alle Variablentypen und Objektwerte<br />

wie Str<strong>in</strong>gs behandelt. Sobald e<strong>in</strong> Teil e<strong>in</strong>er Verkettung e<strong>in</strong> Str<strong>in</strong>g oder e<strong>in</strong> Str<strong>in</strong>g-<br />

Literal ist, werden alle Operatoren wie Str<strong>in</strong>gs behandelt, z.B.:<br />

System.out.pr<strong>in</strong>tln(“1 + 2 = “ 3);.<br />

2) Die Ausgabe kann über die folgende Anweisungen so erfolgen<br />

for (i = 0; i < args.length; i++)<br />

{<br />

System.out.pr<strong>in</strong>tln("args[" + i + "] = \"" + args[i] + "\"");<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

Die Zeichen für doppelte Anführungszeichen(“) und Backslash(\) müssen durch die<br />

Verwendung von sog. Escape-Sequenzen (\“ und \\) dargestellt werden. Die<br />

beiden Anführungszeichen, die das Literal umschliessen, müssen <strong>in</strong> derselben Zeile<br />

des Quellcodes stehen. E<strong>in</strong>e neue Zeile kann <strong>in</strong>nerhalb e<strong>in</strong>es Literals durch die<br />

Escape-Sequenz \n erreicht werden.<br />

5. Aufgabe: Zwei Gleitpunktzahlen sollen über die Befehlszeile e<strong>in</strong>gelesen werden.<br />

Anschließend sollen mit diesen beiden Zahlen alle zugelassenen,<br />

b<strong>in</strong>ären arithmetischen Operationen für Gleitpunktzahlen (des<br />

primitiven Datentyps float) und unäre Inkrement- bzw. Dekrement-<br />

Operationen ausgeführt werden.<br />

Lösungsschritte:<br />

1) Die Übergabe der beiden Zahlen über die Befehlsargumentenliste erfordert die<br />

Konvertierung des Typs Str<strong>in</strong>g <strong>in</strong> e<strong>in</strong>en Typ der Klasse Float. Das konvertierte<br />

Datum kann anschließend e<strong>in</strong>er Variablen des primitiven Typs float zugewiesen<br />

werden.<br />

float x = Float.valueOf(args[0]).floatValue();<br />

float y = Float.valueOf(args[1]).floatValue();<br />

2) Für ganze Zahlen und Gleitpunktzahlen s<strong>in</strong>d Additions- (+), Subtraktions- (-),<br />

Multiplikations- (*) und Divisionsopertoren (/) def<strong>in</strong>iert. Es gibt außerdem für unäre<br />

Arithmetik noch Inkrement- und Dekrementoperatoren zur Manipulation des Werts<br />

von Variablen.<br />

27


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3) Der Quelltext zur Programmlösung ist dann:<br />

public class FloatDemo<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Konvertieren<br />

float x = Float.valueOf(args[0]).floatValue();<br />

float y = Float.valueOf(args[1]).floatValue();<br />

// Ausgabe der ueber die Befehlszeile e<strong>in</strong>gegebenen Zahlen<br />

System.out.pr<strong>in</strong>tln("x = " + x);<br />

System.out.pr<strong>in</strong>tln("y = " + y);<br />

// B<strong>in</strong>aere Arithmetik mit den Operatoren + - * /<br />

float z;<br />

z = x + y;<br />

System.out.pr<strong>in</strong>tln("z = x + y = " + z);<br />

z = x - y;<br />

System.out.pr<strong>in</strong>tln("z = x - y = " + z);<br />

z = x * y;<br />

System.out.pr<strong>in</strong>tln("z = x * y = " + z);<br />

z = x / y;<br />

System.out.pr<strong>in</strong>tln("z = x / y = " + z);<br />

// Unaere Arithmetik mit Inkrement- / Dekrementoperator<br />

x++;<br />

System.out.pr<strong>in</strong>tln("Nach x++: x = " + x);<br />

y--;<br />

System.out.pr<strong>in</strong>tln("Nach y--: y = " + y);<br />

z = x++;<br />

System.out.pr<strong>in</strong>tln("Nach z = x++: z = " + z + ", x = " + x);<br />

z = ++x;<br />

System.out.pr<strong>in</strong>tln("Nach z = ++x: z = " + z + ", x = " + x);<br />

System.out.pr<strong>in</strong>tln("x = " + x);<br />

System.out.pr<strong>in</strong>tln("y = " + y);<br />

z = ++x + y--;<br />

System.out.pr<strong>in</strong>tln("nach z = ++x + y--: z = " + z + ", x = "<br />

+ x + " y = " + y);<br />

System.out.pr<strong>in</strong>tln("x = " + x);<br />

System.out.pr<strong>in</strong>tln("y = " + y);<br />

z = x + y * ++y;<br />

System.out.pr<strong>in</strong>tln("nach z = x + y * ++y: z = " + z + ", x = "<br />

+ x + " y = " + y);<br />

z = (float) (1.0f / 0.0f);<br />

System.out.pr<strong>in</strong>tln("z = (float) (1.0f / 0.0f) = " + z);<br />

}<br />

}<br />

4) Der Aufruf java FloatDemo 17 4 führt dann zu folgenden Ausgabe:<br />

x = 17.0<br />

x = 4.0<br />

z = x + y = 21.0<br />

z = x - y = 13.0<br />

z = x * y = 68.0<br />

z = x / y = 4.25<br />

Nach x++: x = 10.0<br />

Nach y--: y = 3.0<br />

Nach z = x++: z = 18.0, x = 19.0<br />

Nach z = ++x: x = 20.0, x = 20.0<br />

x = 20.0<br />

y = 3.0<br />

Nach z = ++x + y--: z = 23.0, x = 21.0 y = 2.0<br />

x = 21.0<br />

y = 2.0<br />

Nach z = x + y * ++y: z = 27.0, x = 21.0 y = 3.0<br />

z = (float) (1.0f / 0.0f) = Inf<strong>in</strong>ity<br />

28


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das zuletzt angegebenen Resultat zeigt die Zuordnung "Inf<strong>in</strong>ity" falls e<strong>in</strong>e Zahl<br />

ungleich Null durch Null geteilt wird. 1.0f und 0.0f s<strong>in</strong>d Gleitpunkt-Literale. Da<br />

"Inf<strong>in</strong>ity" als sehr groß <strong>in</strong>terpretiert (Typ double) wird, muß hier <strong>in</strong> den Typ<br />

float konvertiert werden.<br />

Die Anwendung zeigt außerdem die Anwendungsweise der Inkrement- und<br />

Dekrementoperatoren <strong>in</strong> Präfix- und Postfix-Schreibweise. Steht der Operator vor der<br />

Variablen (z.B. ++x), dann wird er angewendet, bevor der Wert der Variablen <strong>in</strong> e<strong>in</strong>e<br />

Anweisung e<strong>in</strong>gesetzt wird. Im umgekehrten Fall (z.B. x++) wird die Variable zuerst<br />

<strong>in</strong> e<strong>in</strong>er Anweisung benutzt und dann erhöht.<br />

6. Aufgabe: In der 5. Aufgabe führt der Aufruf java FloatDemo zu e<strong>in</strong>em Fehler.<br />

Dieser Fehler soll aufgefangen werden.<br />

Lösungsschritte:<br />

1) <strong>Java</strong> verfügt zur Behandlung von Fehlern e<strong>in</strong>e spezielle<br />

Ausnahmenbehandlungsrout<strong>in</strong>e (exception handl<strong>in</strong>g) den „try-catch“-Block. Im<br />

„try“-Block wird der normale Ablauf behandelt. Im „catch“-Block erfolgt die<br />

Behandlung der Ausnahmen. Die Verzweigung <strong>in</strong> den „catch“-Block erfolgt beim<br />

Auftreten e<strong>in</strong>er Ausnahme automatisch, der „try“-Block bleibt dabei unberührt.<br />

2) Der Quelltext nimmt nach dem E<strong>in</strong>fügen e<strong>in</strong>es „try-catch“-Blocks folgende<br />

Gestalt an:<br />

public class FloatDemo<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

try {<br />

// Konvertieren<br />

................<br />

}<br />

catch(Exception e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Fehler bei der E<strong>in</strong>gabe: java FloatDemo a b");<br />

System.out.pr<strong>in</strong>tln(e.getMessage());<br />

}<br />

}<br />

}<br />

29


1.3.2.2 Entwicklung von <strong>Java</strong>-Applets<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Entwicklung e<strong>in</strong>es Applets unterscheidet sich von e<strong>in</strong>er Anwendung, weil <strong>Java</strong>-<br />

Applets <strong>in</strong> e<strong>in</strong>er Web-Seite mit anderen Seitenelementen zusammen ausgeführt<br />

werden. Zur Ausführung e<strong>in</strong>es Applets ist es demnach nötig, das Applet <strong>in</strong> e<strong>in</strong>em<br />

HTML-Dokument 34 e<strong>in</strong>zubetten. In diesem HTML-Dokument werden dem<br />

javafähigen Browser die Informationen mitgeteilt, die er zur Ausführung des Applets<br />

benötigt. Der Browser lädt die Klassendatei und führt das Applet automatisch aus.<br />

Aus der Sicht des Programmierers ist das Applet e<strong>in</strong>e Klasse, die von der Applet-<br />

Klasse abgeleitet wird.<br />

1. Aufgabe: Erstelle e<strong>in</strong> Applet, das <strong>in</strong> e<strong>in</strong>em Fenster den Text „Herzlich<br />

Willkommen <strong>in</strong> der <strong>Java</strong>-Welt“ ausgibt.<br />

Lösungsschritte:<br />

1) Erstelle die folgende Datei mit dem Namen „WillkommenApplet.java“ mit Hilfe<br />

e<strong>in</strong>es Dateiaufbereites (Editor):<br />

/* Das erste <strong>Java</strong>-Applet */<br />

import java.awt.Graphics;<br />

public class WillkommenApplet extends java.applet.Applet<br />

{<br />

public void pa<strong>in</strong>t (Graphics g)<br />

{<br />

g.drawStr<strong>in</strong>g("Herzlich willkommen <strong>in</strong> der <strong>Java</strong> Welt!",5,25);<br />

}<br />

}<br />

Durch die „import“-Anweisung können Entwickler Klassen verwenden, die <strong>in</strong><br />

anderen Dateien def<strong>in</strong>iert s<strong>in</strong>d. Compiler bzw. Interpreter greifen auf die class-<br />

Dateien zu. Über „import“ wird bestimmt, wo diese Dateien liegen. <strong>Java</strong> importiert<br />

immer das Paket „java.lang“, denn hier ist die Klasse Object enthalten, von der<br />

alle <strong>Java</strong>-Klassen abgeleitet s<strong>in</strong>d. Die Graphics-Klasse enthält Methoden zum<br />

Zeichnen von Textzeichen und Zeichenketten. Mit der „drawstr<strong>in</strong>g“-Methode der<br />

Graphics-Klasse können Textzeichen auf den Bildschirm gemalt werden.<br />

Die folgende Abbildung zeigt die Modellierung 35 des vorliegenden Quellcodes:<br />

WillkommenApplet<br />

pa<strong>in</strong>t() g.drawStr<strong>in</strong>g<br />

(“Herzlich Willkommen <strong>in</strong> der <strong>Java</strong>-Welt!“,5,25)<br />

Abb. 1.3-2: Klassendiagramm zu WillkommenApplet<br />

34 e<strong>in</strong>e entsprechende Referenz <strong>in</strong>nerhalb e<strong>in</strong>er HTML-Seite mit e<strong>in</strong>em speziellen Tag, dem -Tag<br />

erledigt die E<strong>in</strong>bettung <strong>in</strong> den Browser<br />

35 Die Modellierung erfolgt nach den Regeln der Unified Modell<strong>in</strong>g Language (UML). Die UML ist e<strong>in</strong>e<br />

grafische, standardisierte Sprache zum Spezifizieren, Konstruieren, Visualisieren und Dokumentieren.<br />

30


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Klasse WillkommenApplet läßt sich grafisch als rechteckiges Symbol<br />

darstellen. Die pa<strong>in</strong>t()-Methode wird ohne formale Parameter beschrieben, ihre<br />

Implementierung wird durch die beigefügte Notiz gezeigt.<br />

Die unmittelbare Superklasse wird im Quelltext direkt <strong>in</strong> der „extends“-Klausel<br />

angegeben. „extends java.applet.Applet“ bestimmt das die angegebene<br />

Applet-Klasse von der Applet-Klasse des Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit (AWT)<br />

abgeleitet ist. Der andere Teil der Klassendef<strong>in</strong>ition enthält das Schlüsselwort<br />

„public“ mit der Bedeutung: Die Klasse ist nach dem Laden für das gesamte <strong>Java</strong>-<br />

System verfügbar. Applets müssen „public“ deklariert werden.<br />

Die folgende Abbildung zeigt die Beziehungen der Klasse WillkommenApplet zu<br />

ihren unmittelbaren Nachbarn:<br />

Applet<br />

WillkommenApplet<br />

pa<strong>in</strong>t() Graphics<br />

Abb. 1.3-3: Die unmittelbare Umgebung von WillkommenApplet<br />

Die gerichtete L<strong>in</strong>ie mit der unausgefüllten Pfeilspitze von WillkommenApplet zu<br />

Applet repräsentiert e<strong>in</strong>e Generalisierung, d.h.: WillkommenApplet ist e<strong>in</strong>e<br />

Unterklasse von Applet. Der gestrichelte Pfeil repräsentiert e<strong>in</strong>e<br />

Abhängigkeitbeziehung: WillkommenApplet verwendet Graphics.<br />

E<strong>in</strong> eigenes, vom Benutzer erstelltes Applet überschreibt gewöhnlich Methoden, die<br />

<strong>in</strong> der Superklasse Applet def<strong>in</strong>iert s<strong>in</strong>d. Diese Methoden übernehmen Aufgaben zur<br />

Initialisierung des Applet vor der Ausführung (public void start()), zur<br />

Reaktion auf Mause<strong>in</strong>gaben, zum Anhalten des Applet (public void stop())<br />

und zu Aufräumungsarbeiten (public void destroy()), wenn das Applet<br />

beendet wird. E<strong>in</strong>e dieser Methoden ist pa<strong>in</strong>t(), die sich um die Anzeige des<br />

Applet <strong>in</strong> e<strong>in</strong>er Webseite kümmert. Die pa<strong>in</strong>t()-Methode besitzt e<strong>in</strong> e<strong>in</strong>ziges<br />

Argument, e<strong>in</strong>e Instanz der Klasse Graphics. Die Klasse Graphics stellt<br />

Verhaltensweisen zur Darstellung von Schriften, Farben, zum Zeichnen von<br />

L<strong>in</strong>ien 36 , von Ellipsen bzw. Kreisen 37 , von Rechtecken 38 und anderen Formen zur<br />

Verfügung. In der pa<strong>in</strong>t()-Methode wurde hier der Str<strong>in</strong>g “Herzlich<br />

Willkommen <strong>in</strong> der <strong>Java</strong> Welt!“ bei den (x,y)-Koord<strong>in</strong>aten (5,25) ausgegeben.<br />

Der Ursprung des Koord<strong>in</strong>atensystems liegt <strong>in</strong> der l<strong>in</strong>ken oberen Ecke des<br />

Darstellungsbereichs. Der Str<strong>in</strong>g wird <strong>in</strong> e<strong>in</strong>er defaultmäßig festgelegten Schrift und<br />

Farbe angezeigt.<br />

36 public void drawL<strong>in</strong>e(<strong>in</strong>t x1, <strong>in</strong>t y1, <strong>in</strong>t x2, <strong>in</strong>t y2); (x1,y1) bestimmt den<br />

Anfangspunkt, (x2,y2) bestimmt den Endpunkt der L<strong>in</strong>ie.<br />

37 public void drawOval(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height); (x,y) gibt die<br />

Koord<strong>in</strong>aten der oberen l<strong>in</strong>ken Ecke des die Ellipse umschreibenden Rechtecks mit der Höhe height und der<br />

Breite width am<br />

38 public void drawRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height); bestimmt die obere<br />

l<strong>in</strong>ke Ecke des Rechtecks, (width, height) legen Breite und Höhe des Rechtecks fest.<br />

31


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Untersuchung der <strong>Java</strong>-Bibliotheken zu Applet und Graphics zeigt: Die beiden<br />

Klassen s<strong>in</strong>d Teil e<strong>in</strong>er größeren Hierarchie. Verfolgt man die von Applet erweiterten<br />

und implementierten Klassen, dann kann man das folgende Klassendiagramm<br />

erhalten:<br />

ImageObserver<br />

Object<br />

Component<br />

Conta<strong>in</strong>er<br />

Panel<br />

Applet<br />

WillkommenApplet<br />

Abb. 1.3-4: Verrebungshierarchie von WillkommenApplet<br />

Die Beziehung zwischen ImageObserver und Component ist e<strong>in</strong>e Schnittstelle.<br />

ImageObserver wird von Component implementiert.<br />

WillkommenApplet arbeitet mit den Klassen Applet und Graphics unmittelbar<br />

zusammen. Diese beiden Klassen bilden lediglich e<strong>in</strong>en kle<strong>in</strong>en Ausschnitt aus der<br />

Bibliothek mit vordef<strong>in</strong>ierten <strong>Java</strong>-Klassen. Die Verwaltung dieser Klassen und<br />

Schnittstellen organisiert <strong>Java</strong> <strong>in</strong> mehreren verschiedenen Paketen. Das<br />

Wurzelpaket <strong>in</strong> der <strong>Java</strong>-Umgebung heißt java. In dieses Paket s<strong>in</strong>d mehrere<br />

weitere Pakete geschachtelt, die wiederum andere Pakete, Schnittstellen und<br />

Klassen enthalten. Object existiert im Paket lang, Panel, Conta<strong>in</strong>er,<br />

Component existieren im Paket awt, und die Klasse Applet im Paket applet. Die<br />

Schnittstelle ImageObserver existiert im Paket image, das liegt wiederum im Paket<br />

awt (qualifizierter Name: java.awt.ImageObeserver). Die Paketstruktur 39 kann<br />

<strong>in</strong> e<strong>in</strong>em Klassendiagramm visualisiert werden:<br />

39 Pakete werden <strong>in</strong> der UML als Akten mit Reitern dargestellt. Die gestrichelten Pfeile repräsentieren die<br />

Abhängigkeiten zwischen den Paketen.<br />

32


java<br />

WillkommenApplet applet<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

awt<br />

Abb. 1.3-5: Paketstruktur im WillkommenApplet<br />

2) Speichern der Datei mit dem Namen „WillkommenApplet.java“ unter e<strong>in</strong>em<br />

beliebigen Verzeichnis.<br />

3) Aufruf des <strong>Java</strong>-Übersetzers über die folgende Befehlszeilene<strong>in</strong>gabe: „javac<br />

WillkommenApplet.java“. Der Compiler gibt bei erfolgreicher Übersetzung ke<strong>in</strong>e<br />

Rückmeldung. Zwei Dateien müssen nach erfolgreicher Übersetzung vorliegen:<br />

„WillkommenApplet.java“ und „WillkommenApplet.class“.<br />

4) Erstellen der folgenden HTML-Datei „WillkommenApplet.html“, anschließend<br />

Speichern dieser Datei.<br />

33<br />

lang<br />

<br />

<br />

Seid gegruesst!<br />

<br />

<br />

Me<strong>in</strong> <strong>Java</strong> Applet sagt:<br />

<br />

<br />

<br />

<br />

Der Bezugspunkt <strong>in</strong> HTML-Dateien auf e<strong>in</strong> Applet erfolgt mit dem -Tag. Das<br />

Code-Attribut dient zur Angabe von dem Namen der Klasse, die das Applet enthält.<br />

Die Attribute WIDTH und HEIGHT dienen zum Bestimmen der Größe des Applets.<br />

Der Browser benutzt diese Werte zur Zuteilung des Raums, der für das Applet auf<br />

der Seite freigehalten werden muß. Hier wurde e<strong>in</strong>e Box mit e<strong>in</strong>er Breite von 200<br />

und e<strong>in</strong>er Höhe von 50 Pixeln def<strong>in</strong>iert.<br />

WillkommenApplet ist als Applet implementiert. Es kann nie isoliert stehen, sondern<br />

ist normalerweise Teil e<strong>in</strong>er Webseite.


WillkommenApplet.html<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

WillkommenApplet.class<br />

Abb. 1.3-6: Die Komponenten von WillkommenApplet<br />

34<br />

WillkommenApplet.java<br />

5) Ausführung des Applet mit e<strong>in</strong>em javafähigen Web-Browser bzw. dem<br />

Appletviewer, z.B. mit dem Aufruf „appletviewer WillkommenApplet.html“. Das<br />

Resultat müßte so aussehen:<br />

Abb. 1.3-7: Darstellung des Fensters mit dem Appletviewer<br />

In e<strong>in</strong>em Browser würde zusätzlich der Text rund um das Applet („Me<strong>in</strong> <strong>Java</strong><br />

Applet sagt:“) gezeigt werden.<br />

2. Aufgabe: Verändern von Schrift und Farbe für den Text „Herzlich Willkommen<br />

<strong>in</strong> der <strong>Java</strong>-Welt“.<br />

Lösungsschritte:<br />

1) Erweitere die Datei mit dem Namen „WillkommenApplet.java“ mit Hilfe e<strong>in</strong>es<br />

Dateiaufbereites (Editor).<br />

Die erste Erweiterung soll die Schrift verändern, <strong>in</strong> der der Text ausgegeben wird. Es<br />

wird e<strong>in</strong> Objekt der Klasse java.awt.Font über folgende Anweisung erzeugt: Font f<br />

= new Font("TimesRoman",Font.BOLD,12);<br />

Objekte der Klasse Font dienen zum Bereitstellen verschiedener Schriftarten für die<br />

Methode drawStr<strong>in</strong>g() und repräsentieren den Namen, den Stil und die Größe<br />

e<strong>in</strong>er Schrift. Mit e<strong>in</strong>em spezifischen Objekt der Klasse Font kann man e<strong>in</strong>e Schrift<br />

aufrufen, die sich von der standardmäßig <strong>in</strong> Applets benutzten Schrift unterscheidet.<br />

Dem Font-Objekt wird hier die Schrift „TimesRoman“, fett <strong>in</strong> „12-Punkt“ Größe<br />

zugewiesen. Das neue Objekt wird anschließend der Instanzvariablen f zugewiesen<br />

und ist so der Methode pa<strong>in</strong>t() zugänglich:


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public void pa<strong>in</strong>t (Graphics g)<br />

{<br />

// Mitteilung: Die Schrift zur Anzeige von Text bef<strong>in</strong>det sich <strong>in</strong> der<br />

// Instanzvariablen f<br />

g.setFont(f);<br />

// Mitteilung: Die Farbe fuer die Ausgabe ist gelb<br />

g.setColor(Color.yellow);<br />

// Die glebe Farbe dient zum Fuellen e<strong>in</strong>es Rahmens fuer den Text, der<br />

// aus e<strong>in</strong>em Rechteck mit abgerundeten Ecken besteht<br />

g.fillRoundRect(0,0,225,30,10,10);<br />

// Mitteilung: die Farbe fuer Textausgaben ist<br />

// e<strong>in</strong>e Instanz der Klasse Color fuer die Farbe rot<br />

g.setColor(Color.red);<br />

// Mitteilung: Text wird <strong>in</strong> festgelegter Schrift und Farbe bei den<br />

// (x,y)-Koord<strong>in</strong>aten (5,25) ausgegeben.<br />

g.drawStr<strong>in</strong>g("Herzlich Willkommen <strong>in</strong> der <strong>Java</strong> Welt!",5,25);<br />

}<br />

Die Klassen Font und Color werden über die folgenden import-Anweisungen<br />

bereitgestellt:<br />

import java.awt.Graphics;<br />

import java.awt.Font;<br />

import java.awt.Color;<br />

Dafür kann man auch „import java.awt.*;“ 1 schreiben.<br />

2) Kompiliere die Datei „WillkommenApplet.java“ <strong>in</strong> e<strong>in</strong>e „.class“-Datei.<br />

3) Ausführung des Applet, z.B. über den Aufruf appletviewer<br />

WillkommenApplet.html.<br />

3. Aufgabe: Überwachen des Lebenszyklus e<strong>in</strong>es Applet.<br />

E<strong>in</strong> Applet führt ke<strong>in</strong>e Aktionen aus eigener Initiative aus, sondern empfängt<br />

Ereignisse vom System und liefert Ergebnisse zurück. Beim Start e<strong>in</strong>es Applet ruft<br />

der Webbrowser die Methode <strong>in</strong>it() des Appletobjekts auf. Beim Beenden e<strong>in</strong>es<br />

Applets wird die Methode destroy() aufgerufen. <strong>in</strong>it() und destroy() werden<br />

im Lebenszyklus e<strong>in</strong>es Applet genau e<strong>in</strong>mal ausgeführt, nämlich beim Erzeugen<br />

bzw. beim Beenden e<strong>in</strong>es Objekts. Zusätzlich s<strong>in</strong>d zwei weitere Methoden start()<br />

und stop() vorgesehen, die an verschiedenen Stellen zur Aktivierung aufgerufen<br />

werden können. Wählt e<strong>in</strong> Anwender bei gestartetem Applet z.B. im Browser e<strong>in</strong>e<br />

andere Internetseite an, so ruft der Browser die stop()-Rout<strong>in</strong>e auf und hält das<br />

Applet an, bis der Anwender wieder auf die Appletseite zurückkehrt. Dann ruft der<br />

Browser die start()-Rout<strong>in</strong>e zum ordnungsgemäßen Fortsetzen des Applet auf.<br />

40 Diese Anweisung stellt alle Klassen des Pakets java.awt zur Verfügung<br />

35


import java.awt.*;<br />

import java.applet.*;<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class AppletDemo extends Applet<br />

{<br />

// Instanzvariable<br />

Str<strong>in</strong>g s;<br />

<strong>in</strong>t <strong>in</strong>itialisierungen = 0;<br />

<strong>in</strong>t startpunkte = 0;<br />

<strong>in</strong>t haltepunkte = 0;<br />

// Methoden<br />

public void <strong>in</strong>it() { <strong>in</strong>itialisierungen++; }<br />

public void start() { startpunkte++; }<br />

public void stop() { haltepunkte++; }<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Zur Ausgabe e<strong>in</strong>er geeigneten Nachricht über das Verhalten<br />

// des Applet wird der Str<strong>in</strong>g s mit Hilfe des Opertors + aus<br />

// Teilstr<strong>in</strong>gs zusammengesetzt. Ganze Zahlen werden dabei <strong>in</strong> Zei-<br />

// chenketten konvertiert.<br />

s = "Initialisierungen: " + <strong>in</strong>itialisierungen +<br />

", Startpunkte: " + startpunkte +<br />

", Haltepunkte: " + haltepunkte;<br />

g.drawStr<strong>in</strong>g(s,10,10);<br />

}<br />

}<br />

Browser<br />

öffnet <br />

Webseite :Applet<br />

<strong>in</strong>it()<br />

start()<br />

pa<strong>in</strong>t()<br />

verlässt stop()<br />

Browser<br />

schliesst destroy()<br />

Browser<br />

Abb.: Lebenszyklus e<strong>in</strong>es Applets<br />

36


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

4. Aufgabe: Entwickle aus der vorliegenden Aufgabe e<strong>in</strong>e allgeme<strong>in</strong>e Applet-<br />

Schablone, die als Vorlage für das Erstellen von Applets dienen kann.<br />

Das folgende Gerüst beschreibt e<strong>in</strong> Muster für alle Applets:<br />

// Name der Klasse:<br />

// Beschreibung:<br />

// Import der Pakete<br />

// import java.lang.*;<br />

// import java.applet.*;<br />

// import java.awt.*;<br />

// Top-Level-Klassen-Deklaration bzw. Def<strong>in</strong>ition des Applets<br />

public Klassenname extends java.applet.Applet<br />

{<br />

// Variablen-Deklarationen bzw. Def<strong>in</strong>itionen<br />

// ...<br />

// Eigene Methoden<br />

// ...<br />

// Methoden, die ueberschrieben werden<br />

//<br />

public void <strong>in</strong>it()<br />

{<br />

// ...<br />

}<br />

public void start()<br />

{<br />

// ...<br />

}<br />

public void stop()<br />

{<br />

// ...<br />

}<br />

public void destroy()<br />

{<br />

// ...<br />

}<br />

// Optional: die Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// ..<br />

}<br />

}<br />

E<strong>in</strong> Applet erbt Methoden und Variablen der Applet-Klasse. Die Applet-Klasse erbt<br />

wiederum von e<strong>in</strong>er Reihe anderer Klassen. E<strong>in</strong>e Klasse, die<br />

java.applet.Applet erweitert, kann Variablen und Methoden aus<br />

java.lang.Object, java.awt.Component, java.awt.Conta<strong>in</strong>er sowie<br />

java.awt.Panel verwenden.<br />

37


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1.4 Die Objektorientierung von <strong>Java</strong><br />

1.4.1 Grundlegende Konzepte<br />

1.4.1.1 Zustand und Verhalten von Objekten, Klassen, Instanz- und Klassen-Variable<br />

bzw. -Methoden<br />

Die Abbildung von Zustand bzw. Verhalten <strong>in</strong> Instanzvariable bzw. Instanzmethoden<br />

Objekte s<strong>in</strong>d die Schlüssel zum Verständnis der objektorientierten Technologie.<br />

Objekte s<strong>in</strong>d Gegenstände des täglichen Lebens: der Schreibtisch, das Skript, die<br />

Vorlesung. All diese Objekte der realen Welt haben Zustand und Verhalten. Auch<br />

Software-Objekte haben Zustand und Verhalten. Der Zustand wird <strong>in</strong> Variablen<br />

festgehalten, das Verhalten der Objekte beschreiben Methoden. Die Variablen<br />

bilden den Kern der Objekte. Methoden schirmen den Objektkern von anderen<br />

Objekten des Programms ab (Kapselung). Software-Objekte kommunizieren und<br />

verkehren über Nachrichen (Botschaften) mite<strong>in</strong>ander. Das sendende Objekt<br />

schickt dem Zielobjekt e<strong>in</strong>e Aufforderung, e<strong>in</strong>e bestimmte Methode auszuführen.<br />

Das Zielobjekt versteht (hoffentlich) die Aufforderung und reagiert mit der<br />

zugehörigen Methode. Die genaue formale Schreibweise solcher Botschaften <strong>in</strong><br />

objektorientierten Sprachen ist im Detail verschieden, jedoch wird meistens folgende<br />

Form verwendet: Empfänger.Methodenname(Argument). „Argument“ ist <strong>in</strong> dem<br />

Botschaftsausdruck e<strong>in</strong> Übergabeparameter für die Methode.<br />

In der realen Welt existieren häufig Objekte der gleichen Art. Sie werden über e<strong>in</strong>en<br />

Prototyp, e<strong>in</strong>e Klasse, zusammengefaßt. E<strong>in</strong>e Klassendef<strong>in</strong>ition <strong>in</strong> <strong>Java</strong> wird durch<br />

das Schlüsselwort „class“ e<strong>in</strong>geleitet. Anschließend folgt <strong>in</strong>nerhalb von<br />

geschweiften Klammern e<strong>in</strong>e beliebige Anzahl an Variablen- und<br />

Methodendef<strong>in</strong>itionen. Zum Anlegen e<strong>in</strong>es Objekts e<strong>in</strong>er Klasse (Instanziierung 41 )<br />

muß e<strong>in</strong>e Variable vom Typ der Klasse deklariert und mit Hilfe des new-Operators<br />

e<strong>in</strong> neu erzeugtes Objekt zugewiesen werden. Das Speicher-Management <strong>in</strong> <strong>Java</strong><br />

erfolgt automatisch. Während das Erzeugen von Objekten immer e<strong>in</strong>en expliziten<br />

Aufruf des new-Operators erfordert 42 , erfolgt die Rückgabe von nicht mehr<br />

benötigtem Speicher automatisch 43 .<br />

Das Schreiben e<strong>in</strong>es Programms besteht damit aus Entwurf und Zusammenstellung<br />

von Klassen. Klassenbibliotheken (Sammlung von Klassen) stellen Lösungen für<br />

grundlegende Programmieraufgaben bereit.<br />

Zustand, Aussehen und andere Qualitäten e<strong>in</strong>es Objekts (Attribute) werden durch<br />

Variable def<strong>in</strong>iert. Da jede Instanz e<strong>in</strong>er Klasse verschiedene Werte für ihre<br />

Variablen haben kann, spricht man von Instanzvariablen. Zusätzlich gibt es noch<br />

Klassenvariable, die die Klasse selbst und alle ihre Instanzen betreffen. Werte von<br />

Klassenvariablen werden direkt <strong>in</strong> der Klasse gespeichert. Der Zustand wird <strong>in</strong><br />

Variablen festgehalten und zeigt den momentanen Stand der Objektstruktur an, d.h.<br />

die <strong>in</strong> den e<strong>in</strong>zelnen Bestandteilen des Objekts enthaltenen Informationen und<br />

41 E<strong>in</strong>e Instanz e<strong>in</strong>er Klasse ist e<strong>in</strong> (tatsächliches) Objekt (konkrete Darstellung)<br />

42 Ausnahmen: Str<strong>in</strong>g-, Array-Literale<br />

43 E<strong>in</strong> Garbage-Collector (niedrigpriorisierte H<strong>in</strong>tergrundprozeß) sucht <strong>in</strong> regelmäßigen Abständen nach nicht<br />

mehr referenzierten Objekten und gibt den durch sie belegten Speicher an das Laufzeitsystem zurück<br />

38


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Daten. Abhängig vom Detaillierungsgrad kann die Notation für e<strong>in</strong>e Variable den<br />

Namen, den Datentyp und den vore<strong>in</strong>gestellten Wert zeigen:<br />

Sichtbarkeit Typ Name = vore<strong>in</strong>gestellter_Wert;<br />

Sichtbarkeit: öffentlich (public), geschützt (protected) oder privat (private)<br />

Typ: Datentyp<br />

Name: e<strong>in</strong>e nach bestimmten Regeln 44 gebildete Zeichenkette<br />

Nach der Initialisierung haben alle Variablen des Objekts zunächst Standardwerte<br />

(vore<strong>in</strong>gestellte Werte). Der Zugriff auf sie erfolgt mit Hilfe der Punktnotation:<br />

Objekt.Variable.<br />

Zur Bezugnahme auf das aktuelle Objekt dient das Schlüsselwort this. Es kann an<br />

jeder beliebigen Stelle angegeben werden, an der das Objekt ersche<strong>in</strong>en kann, z.B.<br />

<strong>in</strong> e<strong>in</strong>er Punktnotation zum Verweis auf Instanzvariablen des Objekts oder als<br />

Argument für e<strong>in</strong>e Methode oder als Ausgabewert der aktuellen Methoden. In vielen<br />

Fällen kann das Schlüsselwort this entfallen. Das hängt davon ab, ob es Variablen<br />

mit gleichem Namen im lokalen Bereich gibt.<br />

Zur Def<strong>in</strong>ition des Verhaltens von Objekten dienen Methoden. Methoden s<strong>in</strong>d<br />

Funktionen, die <strong>in</strong>nerhalb von Klassen def<strong>in</strong>iert werden und auf Klassen<strong>in</strong>stanzen<br />

angewandt werden. Methoden wirken sich aber nicht nur auf e<strong>in</strong> Objekt aus. Objekte<br />

kommunizieren auch mite<strong>in</strong>ander durch Methoden. E<strong>in</strong>e Klasse oder e<strong>in</strong> Objekt kann<br />

Methoden e<strong>in</strong>er anderen Klasse oder e<strong>in</strong>es anderen Objekts aufrufen, um<br />

Änderungen <strong>in</strong> der Umgebung mitzuteilen oder e<strong>in</strong> Objekt aufzufordern, se<strong>in</strong>en<br />

Zustand zu ändern. Instanzmethoden (Operationen, Services) werden auf e<strong>in</strong>e<br />

Instanz angewandt, Klassenmethoden beziehen sich auf e<strong>in</strong>e Klasse.<br />

Klassenmethoden können nur mit Klassenvariablen arbeiten.<br />

Die Beschreibung der Operationen (Nachrichten, Methoden) erfolgt nach dem<br />

folgenden Schema:<br />

Sichbarkeit Rückgabetypausdruck Name(Parameterliste)<br />

Sichtbarkeit: öffentlich (public), geschützt (protected), privat (private) 45<br />

Rückgabetypausdruck: Jede Methode ist typisiert. Der Typ e<strong>in</strong>er Methode bestimt den Typ des<br />

Rückgabewerts. Dieser kann von e<strong>in</strong>em beliebigen primitiven Typ 46 , e<strong>in</strong>em Objekttyp oder vom Typ<br />

void se<strong>in</strong>. Methoden vom Typ void haben ke<strong>in</strong>en Rückgabewert und dürfen nicht <strong>in</strong> Ausdrücken<br />

verwendet werden. Hat e<strong>in</strong>e Methode e<strong>in</strong>en Rückgabewert, dann kann sie mit der „return“-<br />

Anweisung 47 e<strong>in</strong>en Wert an den Aufrufer zurückgeben.<br />

Parameterliste enthält optional Argumente und hat folgende Struktur: Datentyp<br />

variablenname, ..... Die Anzahl der Parameter ist beliebig und kann Null se<strong>in</strong>.<br />

In <strong>Java</strong> wird jede selbstdef<strong>in</strong>ierte Klasse mit Hilfe des Operators new <strong>in</strong>stanziert. Mit<br />

Ausnahme von Zeichenketten (Str<strong>in</strong>gs) und Datenfeldern (Arrays), bei denen der<br />

Compiler auch Literale zur Objekterzeugung bereitstellt, gilt dies für alle<br />

vordef<strong>in</strong>ierten Klassen der <strong>Java</strong>-Bibliothek.<br />

Der Aufruf e<strong>in</strong>er Methode erfolgt ähnlich der Verwendung e<strong>in</strong>er Instanzvariablen <strong>in</strong><br />

„Punktnotation“. Zur Unterscheidung von e<strong>in</strong>em Variablenzugriff müssen zusätzlich<br />

die Parameter <strong>in</strong> Klammern angegeben werden, selbst wenn die Parameter-Liste<br />

leer ist.<br />

44 vgl. 2.1.2 Bezeichner und Namenskonventionen<br />

45 vgl. 2.6.2<br />

46 vgl. 2.2<br />

47 vgl. 2.6.4<br />

39


E<strong>in</strong> praktisches Beispiel<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1. Erstellen der Klasse Rechentafel zum Rechnen mit ganzen Zahlen<br />

Die grundlegende Klassendef<strong>in</strong>ition ist: class Rechentafel{ }<br />

Das ist e<strong>in</strong>e <strong>Java</strong>-Klasse (<strong>in</strong> e<strong>in</strong>fachster Form), selbstverständlich passiert hier noch<br />

nicht viel. Damit etwas Aktion stattf<strong>in</strong>den kann, müssen Zustand und Verhalten<br />

diverser Rechentafel-Objekte festgehalten werden können.<br />

Der Zustand wird <strong>in</strong> Variablen gespeichert. In Rechentafel-Objekten gibt es zwei<br />

Operanden zur Aufnahme ganzzahliger Werte für die Berechnung und e<strong>in</strong>e Variable<br />

zur Aufnahme des Resultats nach der Berechnung. Operanden und Resultat s<strong>in</strong>d <strong>in</strong><br />

der Klasse Rechentafel Instanzvariable, da jedes Rechentafel-Objekt dafür<br />

verschiedene Werte haben kann. Folgende Instanzvariable (mit Datentyp <strong>in</strong>t)<br />

werden <strong>in</strong> den durch „{ }“markierten Klassenkörper e<strong>in</strong>getragen:<br />

// Instanzvariable<br />

<strong>in</strong>t ersterOperand = 0;<br />

<strong>in</strong>t zweiterOperand = 0;<br />

Da ke<strong>in</strong>e spezifische Angabe zur Sichtbarkeit vorliegen, haben Objekte auf die<br />

Variablen Zugriff, die aus Klassen <strong>in</strong>nerhalb des Klassenverzeichnisses gebildet<br />

werden.<br />

Rechentafel-Objekte sollten „Rechnen“ können. Dieses Verhalten bedeutet: Die<br />

vorliegenden Instanzvariablen s<strong>in</strong>d durch Instanzmethoden zu ergänzen, z.B.:<br />

// Operationen<br />

<strong>in</strong>t addiere()<br />

{<br />

return ersterOperand + zweiterOperand;<br />

}<br />

<strong>in</strong>t subtrahiere()<br />

{<br />

return ersterOperand - zweiterOperand;<br />

}<br />

<strong>in</strong>t multipliziere()<br />

{<br />

return ersterOperand * zweiterOperand;<br />

}<br />

<strong>in</strong>t dividiere()<br />

{<br />

// ganzzahlige Division<br />

return ersterOperand / zweiterOperand;<br />

}<br />

Die Klasse ist damit für Rechentafel-Objekte vollständig bereitgestellt. Allerd<strong>in</strong>gs wird<br />

erst nach dem H<strong>in</strong>zufügen der ma<strong>in</strong>()-Methode aus dieser Klasse e<strong>in</strong>e <strong>Java</strong>-<br />

Anwendung 1 :<br />

2. Die Klasse Rechentafeltest zum Überprüfen der Klasse Rechentafel<br />

Die Klasse Rechentafeltest ist durch die Anwendung der Klasse Rechentafel<br />

bestimmt. Sie enthält die ma<strong>in</strong>()-Methode. Im Mittelpunkt der Anwendung steht die<br />

Anweisung:<br />

Rechentafel e<strong>in</strong>Rechenobjekt = new Rechentafel();<br />

Sie erzeugt e<strong>in</strong>e Instanz der Klasse Rechentafel und speichert e<strong>in</strong>e Referenz<br />

darauf <strong>in</strong> der Variablen „e<strong>in</strong>Rechenobjekt“. In jeder objektorientierten<br />

48 vgl. PR14101<br />

40


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Programmiersprache lassen sich spezielle Methoden def<strong>in</strong>ieren, die bei der<br />

Initialisierung e<strong>in</strong>es Objekts aufgerufen werden. In <strong>Java</strong> werden Konstruktoren als<br />

Methoden ohne Rückgabewert def<strong>in</strong>iert, die den Namen der Klasse erhalten, zu der<br />

sie gehören. Falls e<strong>in</strong>e Klasse ke<strong>in</strong>en expliziten Konstruktor besitzt, wird e<strong>in</strong><br />

parameterloser „default“-Konstruktor aufgerufen (, der hier zusammen mit dem<br />

Operator new verwendet wird).<br />

import java.lang.*;<br />

class Rechentafeltest extends Object<br />

{<br />

// Zur Ausführung mit dem <strong>Java</strong>-Interpreter wird e<strong>in</strong>e ma<strong>in</strong>()-Methode<br />

// benoetigt<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g argv[])<br />

{<br />

// Erzeugen e<strong>in</strong>er Instanz der Klasse Rechentafel<br />

Rechentafel e<strong>in</strong>Rechenobjekt = new Rechentafel();<br />

// Setzen der Instanzvariablen<br />

e<strong>in</strong>Rechenobjekt.ersterOperand = 3;<br />

e<strong>in</strong>Rechenobjekt.zweiterOperand = 2;<br />

// Test mit e<strong>in</strong>em Rechenobjekt der Klasse Rechentafel<br />

System.out.pr<strong>in</strong>tln("Test mit e<strong>in</strong>em Rechentafel-Objekt");<br />

// Aufruf der Methoden und Ausgabe des jeweiligen Resultats<br />

System.out.pr<strong>in</strong>t("Addition ");<br />

System.out.pr<strong>in</strong>tln("von " + e<strong>in</strong>Rechenobjekt.ersterOperand + " und "<br />

+ e<strong>in</strong>Rechenobjekt.zweiterOperand + " ist "<br />

+ e<strong>in</strong>Rechenobjekt.addiere());<br />

System.out.pr<strong>in</strong>t("Subtraktion ");<br />

System.out.pr<strong>in</strong>tln("von " + e<strong>in</strong>Rechenobjekt.ersterOperand + " und "<br />

+ e<strong>in</strong>Rechenobjekt.zweiterOperand + " ist "<br />

+ e<strong>in</strong>Rechenobjekt.subtrahiere());<br />

System.out.pr<strong>in</strong>t("Multiplikation ");<br />

System.out.pr<strong>in</strong>tln("von " + e<strong>in</strong>Rechenobjekt.ersterOperand + " und "<br />

+ e<strong>in</strong>Rechenobjekt.zweiterOperand + " ist "<br />

+ e<strong>in</strong>Rechenobjekt.multipliziere());<br />

System.out.pr<strong>in</strong>t("Division ");<br />

System.out.pr<strong>in</strong>tln("von " + e<strong>in</strong>Rechenobjekt.ersterOperand + " und "<br />

+ e<strong>in</strong>Rechenobjekt.zweiterOperand + " ist "<br />

+ e<strong>in</strong>Rechenobjekt.dividiere());<br />

}<br />

}<br />

E<strong>in</strong>fache Typen 50 und Referenztypen<br />

E<strong>in</strong>fache Typen<br />

Jedes <strong>Java</strong>-Programm besteht aus e<strong>in</strong>er Sammlung von Klassen. Der vollständige<br />

Code von <strong>Java</strong> wird <strong>in</strong> Klassen e<strong>in</strong>geteilt. Es gibt davon nur e<strong>in</strong>e Ausnahme:<br />

Boolesche Operatoren, Zahlen und andere e<strong>in</strong>fache Typen 51 s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> erst e<strong>in</strong>mal<br />

ke<strong>in</strong>e Objekte. <strong>Java</strong> hat für alle e<strong>in</strong>fachen Typen sog. Wrapper-Klassen<br />

implementiert. E<strong>in</strong> Wrapper-Klasse ist e<strong>in</strong>e spezielle Klasse, die e<strong>in</strong>e<br />

Objektschnittstelle für die <strong>in</strong> <strong>Java</strong> verschiedenen primitiven Typen darstellt. Über<br />

Wrapper-Objekte können alle e<strong>in</strong>fachen Typen wie Klassen behandelt werden. <strong>Java</strong><br />

besitzt acht primitive Datentypen 52 :<br />

50 vgl. 2.2.1<br />

51 vgl. 2.2.1<br />

52 vgl. 2.2.1<br />

41


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

- vier Ganzzahltypen mit unterschiedlichen Wertebereichen<br />

- zwei Gleitpunktzahlentypen mit unterschiedlichen Wertebereichen nach IEEE Standard of B<strong>in</strong>ary Float<strong>in</strong>g<br />

Po<strong>in</strong>t Arithmetic.<br />

- e<strong>in</strong>en Zeichentyp<br />

Primitiver Typ Größe M<strong>in</strong>imum Maximum Wrapper-Klasse<br />

boolean 1-Bit - - Boolean<br />

char 16-Bit Unicode 0 Unicode 2 16 -1 Character<br />

byte 8-Bit -128 +128 Byte<br />

short 16-Bit -2 15<br />

+2 15 -1 Short<br />

<strong>in</strong>t 32-Bit -2 31<br />

+2 31 -1 Integer<br />

long 64-Bit -2 63<br />

42<br />

+2 63 -1 Long<br />

float 32-Bit IEEE 754 IEEE 754 Float<br />

double 64-Bit IEEE 754 IEEE 754 Double<br />

void - - - Void<br />

Den primitiven Typen s<strong>in</strong>d „Wrapper“-Klassen zugeordnet, die e<strong>in</strong> nicht primitives<br />

Objekt auf dem „Heap“ zur Darstellung des primitiven Typs erzeugen, z.B.:<br />

char zeichen = ‘x‘;<br />

Character zeichenDarstellung = new Character(zeichen)<br />

bzw.<br />

Character zeichenDarstellung = new Character(‘x‘);<br />

Referenztypen<br />

Neben den primitiven Typen gibt es die Referenztypen. Dazu gehören: Objekte der<br />

benutzerdef<strong>in</strong>ierten und aus vom System bereitgestellten Klassen, der Klassen<br />

Str<strong>in</strong>g und Array (Datenfeld). Weiterh<strong>in</strong> gibt es die vordef<strong>in</strong>ierte Konstante<br />

„null“, die e<strong>in</strong>e leere Referenz bezeichnet.<br />

„Str<strong>in</strong>g“ und „Array“ weisen e<strong>in</strong>ige Besonderheiten aus:<br />

- Für Str<strong>in</strong>gs und Arrays kennt der Compiler Literale, die e<strong>in</strong>en expliziten Aufruf des Operator new<br />

überflüssig machen<br />

- Arrays s<strong>in</strong>d klassenlose Objekte. Sie können ausschließlich vom Compiler erzeugt werden, besitzen<br />

aber ke<strong>in</strong>e explizite Klassendef<strong>in</strong>ition. Sie werden dennoch vom Laufzeitsystem wie normale Objeklte<br />

behandelt.<br />

- Die Klasse Str<strong>in</strong>g ist zwar im JDK vorhanden. Der Compiler hat aber Kenntnis über den <strong>in</strong>neren<br />

Aufbau von Str<strong>in</strong>gs und generiert bei Anzeigeoperationen Code, der auf Methoden der Klassen Str<strong>in</strong>g<br />

und Str<strong>in</strong>gBuffer zugreift.<br />

Konstruktoren<br />

E<strong>in</strong>e „Constructor“-Methode bestimmt, wie e<strong>in</strong> Objekt <strong>in</strong>itialisiert wird. Konstruktoren<br />

haben immer den gleichen Namen wie die Klasse und besitzen ke<strong>in</strong>e „return“-<br />

Anweisung. <strong>Java</strong> erledigt beim Aufruf e<strong>in</strong>es Konstruktors folgende Aufgaben:<br />

- Speicherzuweisung für das Objekt<br />

- Initialisieung der Instanzvariablen des Objekts auf ihre Anfangswerte oder e<strong>in</strong>en Default-Wert (0 bei<br />

Zahlen, „null“ bei Objekten, „false“ bei booleschen Operatoren.<br />

- Aufruf der Konstruktor-Methode der Klasse<br />

Gewöhnlich stellt man „explizit“ e<strong>in</strong>en „default“-Konstruktor zur Verfügung. Dieser<br />

parameterlose Konstruktor überlagert den implizit bereitgestellten „default“-<br />

Konstruktor. Er wird dann bei allen parameterlosen Instanzierungen verwendet.


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Konstruktoren können aber auch – wie normale Dateien – Parameter übergeben<br />

bekommen, z.B. 53 :<br />

public Rechentafel(<strong>in</strong>t ersterOperand, <strong>in</strong>t zweiterOperand)<br />

{<br />

super(); // Aufruf des Default-Konstruktors der Superklasse<br />

this.ersterOperand = ersterOperand;<br />

this.zweiterOperand = zweiterOperand;<br />

}<br />

super() bestimmt e<strong>in</strong>en Aufruf des „default“-Konstruktors der e<strong>in</strong>deutig<br />

bestimmten „Superklasse“. „super(...)“ darf nur als erste Anweisung e<strong>in</strong>es<br />

Konstruktors auftreten. Generell bezeichnet das reservierte Wort „super“, die nach<br />

„extends“ benannte Superklasse.<br />

Häufig s<strong>in</strong>d die Parameter Anfangswerte für Instanzvariablen und haben oft den<br />

gleichen Namen wie die entsprechenden Instanzvariablen. In diesen Fällen löst die<br />

Verwendung von bsp. this.ersterOperand = ersterOperand; derartige<br />

Namenskonflikte auf.<br />

Bei „this“ handelt es sich um e<strong>in</strong>en Zeiger, der beim Anlegen e<strong>in</strong>es Objekts<br />

automatisch generiert wird. „this“ ist e<strong>in</strong>e Referenzvariable, die auf das aktuelle<br />

Objekt zeigt und zum Ansprechen der eigenen Methoden und Instanzvariablen dient.<br />

Der „this“-Zeiger ist auch explizit verfügbar und kann wie e<strong>in</strong>e ganz normale<br />

Objektvariable verwendet werden. Er wird als versteckter Parameter an jede nicht<br />

statische Methode übergeben.<br />

Konstruktoren können <strong>in</strong> <strong>Java</strong> verkettet aufgerufen werden, d.h. sie können sich<br />

gegenseitig aufrufen. Der aufrufende Konstruktor wird dabei als normale Methode<br />

angesehen, die über this e<strong>in</strong>en weiteren Konstruktor der aktuellen Klasse aufrufen<br />

kann, z.B.:<br />

public Rechentafel()<br />

{<br />

this(0,1);<br />

}<br />

„Freundliche“ Klassen und „freundliche“ Methoden<br />

„Rechentafel“ ist e<strong>in</strong>e „freundliche“ Klasse. Der vore<strong>in</strong>gestellte „Defaultstatus“<br />

e<strong>in</strong>er Klasse ist immer „freundlich“ und wird dann verwendet, wenn ke<strong>in</strong>e Angaben<br />

über die Sichtbarkeit (Spezifizierer, Modifizierer) am Beg<strong>in</strong>n der Klassendef<strong>in</strong>ition<br />

vorliegen.<br />

Die freundliche Grunde<strong>in</strong>stellung aller Klassen bedeutet: Diese Klasse kann von<br />

anderen Klassen nur <strong>in</strong>nerhalb desselben Pakets benutzt werden. Das Paket-<br />

Konzept von <strong>Java</strong> faßt mehrere Klassen zu e<strong>in</strong>em Paket über die Anweisung<br />

„package“ zusammen. Durch die Anweisung „import“ werden e<strong>in</strong>zelne Pakete<br />

dann <strong>in</strong> e<strong>in</strong>em Programm verfügbar gemacht. Klassen, die ohne „package“-<br />

Anweisung def<strong>in</strong>iert werden, werden vom Compiler <strong>in</strong> e<strong>in</strong> Standardpaket gestellt. Die<br />

„.java“- und „.class“-Dateien dieses Pakets bef<strong>in</strong>den sich im aktuellen<br />

Verzeichnis oder im darunterliegenden Verzeichnis.<br />

Mit dem Voranstellen von „public“ vor die Klassendeklaration wird e<strong>in</strong>e Klasse als<br />

„öffentlich“ deklariert.Dies bedeutet: Alle Objekte haben Zugriff auf „public“-<br />

Klassen (nicht nur die des eigenen Pakets).<br />

53 PR14102<br />

43


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Der vore<strong>in</strong>gestellte Defaultstaus e<strong>in</strong>er Methode ist immer freundlich und wird immer<br />

dann verwendet, wenn ke<strong>in</strong>e explizite Angabe zur Sichtbarkeit am Anfang der<br />

Methodendeklaration vorliegt. Die freundliche Grunde<strong>in</strong>stellung aller Methoden<br />

bedeutet: Die Methoden können sowohl <strong>in</strong>nerhalb der Klasse als auch <strong>in</strong>nerhalb des<br />

zugehörigen Pakets benutzt werden.<br />

Zugriffsrechte auf Klassen, Variable und Methoden<br />

Es gibt <strong>in</strong> <strong>Java</strong> <strong>in</strong>sgesamt 4 Zugriffsrechte:<br />

private Zugriff nur <strong>in</strong>nerhalb e<strong>in</strong>er Klasse<br />

Ohne Schlüsselwort Zugriff <strong>in</strong>nerhalb e<strong>in</strong>es Pakets<br />

protected Zugriff <strong>in</strong>nerhalb e<strong>in</strong>es Pakets oder von Subklassen <strong>in</strong> e<strong>in</strong>em anderen<br />

Paket<br />

public Zugriff von überall<br />

Mit Voranstellen des Schlüsselworts „public“ können alle Klassen, Variablen /<br />

Konstanten und Methoden für e<strong>in</strong>en beliebigen Zugriff e<strong>in</strong>gerichtet werden. E<strong>in</strong>e<br />

derartige Möglichkeit, die <strong>in</strong> etwa der Zugriffsmöglichkeit globaler Variablen <strong>in</strong><br />

konventionellen Programmiersprachen entspricht, ist <strong>in</strong>sbesondere bei komplexen<br />

Programm-Systemen gefährlich. Es ist nicht sichergestellt, daß zu jedem Zeitpunkt<br />

die Werte der Instanzvariablen von Objekten bestimmte Bed<strong>in</strong>gungen erfüllen.<br />

Möglich ist bspw. die Anweisung<br />

e<strong>in</strong>Rechenobjekt.zweiterOperand = 0;<br />

<strong>in</strong> der Klasse „Rechentafeltest“. Mit Sicherheit führt diese Anweisung bei der<br />

Ausführung e<strong>in</strong>er Division auf e<strong>in</strong>en Divisionsfehler.<br />

Abhilfe verspricht hier das Pr<strong>in</strong>zip der Datenkapselung (data hid<strong>in</strong>g, data<br />

encapsulation). Instanzvariable werden als „private“ erklärt, d.h.: Zugriff auf diese<br />

Instanzvariable nur <strong>in</strong>nerhalb der Klasse. Von außerhalb kann nur <strong>in</strong>direkt über das<br />

Aufrufen von Methoden, die als „public“ erklärt s<strong>in</strong>d, auf die Instanzvariablen<br />

zugegriffen werden. Deshalb sollte auch pr<strong>in</strong>zipiell für jede Instanzvariable e<strong>in</strong>e<br />

entsprechende „get“- und e<strong>in</strong>e „set“-Methode („hole“ bzw. „setze“) zur Verfügung<br />

gestellt werden, die jeweils „public“ erklärt werden.<br />

Bsp.: Die Klasse „Rechentafel“ nimmt dann folgenden Gestalt an:<br />

44


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

class Rechentafel extends Object<br />

{<br />

// Instanzvariable<br />

private <strong>in</strong>t ersterOperand = 0;<br />

private <strong>in</strong>t zweiterOperand = 0;<br />

// Konstruktoren<br />

public Rechentafel()<br />

{<br />

this(0,1);<br />

}<br />

public Rechentafel(<strong>in</strong>t ersterOperand, <strong>in</strong>t zweiterOperand)<br />

{<br />

super();<br />

this.ersterOperand = ersterOperand;<br />

this.zweiterOperand = zweiterOperand;<br />

}<br />

// Operationen<br />

public <strong>in</strong>t holersterOperand()<br />

{<br />

return ersterOperand;<br />

}<br />

public void setzersterOperand(<strong>in</strong>t ersterOperand)<br />

{<br />

this.ersterOperand = ersterOperand;<br />

}<br />

public <strong>in</strong>t holzweiterOperand()<br />

{<br />

return zweiterOperand;<br />

}<br />

public void setzweiterOperand(<strong>in</strong>t zweiterOperand)<br />

{<br />

this.zweiterOperand = zweiterOperand;<br />

}<br />

public <strong>in</strong>t addiere()<br />

{<br />

return ersterOperand + zweiterOperand;<br />

}<br />

public <strong>in</strong>t subtrahiere()<br />

{<br />

return ersterOperand - zweiterOperand;<br />

}<br />

public <strong>in</strong>t multipliziere()<br />

{<br />

return ersterOperand * zweiterOperand;<br />

}<br />

public <strong>in</strong>t dividiere()<br />

{<br />

// ganzzahlige Division<br />

if (zweiterOperand == 0)<br />

{<br />

System.out.pr<strong>in</strong>tln("Fehler: Division durch Null");<br />

System.out.pr<strong>in</strong>tln("Divisor wird auf 1 gesetzt!");<br />

zweiterOperand = 1;<br />

}<br />

return ersterOperand / zweiterOperand;<br />

}<br />

}<br />

45


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das Beispiel zeigt folgende Empfehlungen für die Vergabemöglichkeit von Zugriffsrechten:<br />

Klassen public<br />

Instanzvariable private<br />

Instanzkonstanten public<br />

Instanzmethoden public, falls e<strong>in</strong> Zugriff von außen erforderlich und s<strong>in</strong>nvoll ist.<br />

private, falls es sich um klasen<strong>in</strong>terne Hilfsmethoden handelt.<br />

Analoge Überlegungen gelten auch für Klassenvariable und -methoden.<br />

Klassenvariable und Klassenmethoden<br />

Die Klasse „Rechentafel" 54 wurde zusätzlich erweitert um<br />

// Klassenvariable<br />

static <strong>in</strong>t anzRechenobjekte = 0;<br />

Das reservierte Wort static macht Variable und Methoden (wie bspw. ma<strong>in</strong>()) zu<br />

Klassenvariablen bzw. Klassenmethoden.<br />

Klassenvariable werden <strong>in</strong> der Klasse def<strong>in</strong>iert und gespeichert. Deshalb wirken sich<br />

ihre Werte auf die Klasse und all ihre Instanzen aus. Jede Instanz hat Zugang zu der<br />

Klassenvariablen, jedoch gibt es für alle Instanzen dieser Variablen nur e<strong>in</strong>en Wert.<br />

Durch Änderung des Werts ändern sich die Werte aller Instanzen der betreffenden<br />

Klasse.<br />

Die folgende Erweiterung des Konstruktors der Klasse „Rechentafel“ berücksichtigt<br />

das spezielle Verhalten von Klassenvariablen:<br />

public Rechentafel(<strong>in</strong>t ersterOperand, <strong>in</strong>t zweiterOperand)<br />

{<br />

super();<br />

this.ersterOperand = ersterOperand;<br />

this.zweiterOperand = zweiterOperand;<br />

nummer = ++anzRechenobjekte;<br />

}<br />

„nummer“ ist e<strong>in</strong>e Instanzvariable, „anzRechenObjekte“ ist die Klassenvariable.<br />

Das reservierte Wort f<strong>in</strong>al macht Variablen zu Größen, denen nur e<strong>in</strong>mal bei der<br />

Deklaration e<strong>in</strong> Wert zugewiesen werden kann, d.h. sie werden dadurch zu<br />

Konstanten, z.B.: public static f<strong>in</strong>al double PI = 3.1415926535897932846;<br />

Klassenmethoden wirken sich wie Klassenvariable auf die ganze Klasse, nicht auf<br />

e<strong>in</strong>zelne Instanzen aus. Klassenmethoden s<strong>in</strong>d nützlich zum Zusammenfassen<br />

allgeme<strong>in</strong>er Methoden an e<strong>in</strong>er Stelle der Klasse. So umfaßt die Math-Klasse<br />

zahlreiche mathematische Funktionen <strong>in</strong> der Form von Klassenmethoden. Es gibt<br />

ke<strong>in</strong>e Instanzen der Klasse Math.<br />

Auch rekurvive Programme benutzen Klassenmethoden, z.B.:<br />

54 PR14103<br />

46


Berechnung der Fakultaet<br />

public static long fakultaet(<strong>in</strong>t n)<br />

{<br />

if (n < 0)<br />

{<br />

return -1;<br />

}<br />

else if (n == 0)<br />

{<br />

return 1;<br />

}<br />

else<br />

{<br />

return n * fakultaet(n-1);<br />

}<br />

}<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Der Aufruf e<strong>in</strong>er Klassenmethode kann im Rahmen der Punktnotation aber auch<br />

direkt erfolgen, z.B.:<br />

long resultat = fakultaet(i);<br />

bzw.<br />

long resultat = Rechentafel.fakultaet(i);<br />

unter der Voraussetzung: Die Klassenmethode „fakultaet“ bef<strong>in</strong>det sich <strong>in</strong> der Klasse<br />

„Rechentafel“.<br />

Lokale Variable und Konstanten<br />

Lokale Variable werden <strong>in</strong>nerhalb von Methodendef<strong>in</strong>itionen deklariert und können<br />

nur dort verwendet werden. Es gibt auch auf Blöcke beschränkte lokale Variablen.<br />

Die Deklaration e<strong>in</strong>er lokalen Variablen gilt <strong>in</strong> <strong>Java</strong> als ausführbare Anweisung. Sie<br />

darf überall dort erfolgen, wo e<strong>in</strong>e Anweisung verwendet werden darf. Die<br />

Sichtbarkeit e<strong>in</strong>er lokalen Variablen erstreckt sich von der Deklaration bis zum Ende<br />

des umschließenden Blocks.<br />

Lokale Variablen existieren nur solange im Speicher, wie die Methode oder der Block<br />

existiert. Lokale Variable müssen unbed<strong>in</strong>gt e<strong>in</strong> Wert zugewiesen bekommen, bevor<br />

sie benutzt werden können. Instanz- und Klassenvariable haben e<strong>in</strong>en<br />

typspezifischen Defaultwert. Auf lokale Variable kann direkt und nicht über die<br />

Punktnotation zugegriffen werden. Lokale Variable können auch nicht als<br />

Konstanten 55 gesetzt werden.<br />

Beim Bezug e<strong>in</strong>er Variablen <strong>in</strong> e<strong>in</strong>er Methodendef<strong>in</strong>ition sucht <strong>Java</strong> zuerst e<strong>in</strong>e<br />

Def<strong>in</strong>ition dieser Variablen im aktuellen Bereich, dann durchsucht es die äußeren<br />

Bereiche bis zur Def<strong>in</strong>ition der aktuellen Methode. Ist die gesuchte Größe ke<strong>in</strong>e<br />

lokale Variable, sucht <strong>Java</strong> nach e<strong>in</strong>er Def<strong>in</strong>ition dieser Variablen als Instanzvariable<br />

<strong>in</strong> der aktuellen Klasse und zum Schluß <strong>in</strong> der Superklasse.<br />

Konstanten s<strong>in</strong>d Speicherbereiche mit Werten, die sich nie ändern. In <strong>Java</strong> können<br />

solche Konstanten ausschließlich für Instanz- und Klassenvariable erstellt werden.<br />

Konstante bestehen aus e<strong>in</strong>er Variablendeklaration, der das Schlüsselwort f<strong>in</strong>al<br />

vorangestellt ist, und e<strong>in</strong> Anfangswert zugewiesen ist, z.B.: f<strong>in</strong>al <strong>in</strong>t LINKS =<br />

0;<br />

55 Das bedeutet: das Schlüsselwort f<strong>in</strong>al ist bei lokalen Variablen nicht erlaubt<br />

47


Überladen von Methoden<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

In <strong>Java</strong> ist es erlaubt, Methoden zu überladen, d.h. <strong>in</strong>nerhalb e<strong>in</strong>er Klasse zwei<br />

unterschiedliche Methoden mit denselben Namen zu def<strong>in</strong>ieren. Der Compiler<br />

unterscheidet die verschiedenen Varianten anhand Anzahl und Typisierung der<br />

Parameter. Es ist nicht erlaubt, zwei Methoden mit exakt demselben Namen und<br />

identischer Parameterliste zu def<strong>in</strong>ieren. Es werden auch zwei Methoden, die sich<br />

nur durch den Typ ihres Rückgabewerts unterscheiden als gleich angesehen.<br />

Der Compiler kann die Namen <strong>in</strong> allen drei Fällen unterscheiden, denn er arbeitet mit<br />

der Signatur der Methode. Darunter versteht man ihren <strong>in</strong>ternen Namen. Dieser setzt<br />

sich aus dem nach außen sichtbaren Namen und zusätzlich kodierter Information<br />

über Reihenfolge und die Typen der formalen Parameter zusammen.<br />

Überladen kann bedeuten, daß bei Namensgleichheit von Methoden <strong>in</strong><br />

„Superklasse“ und abgeleiteter Klasse die Methode der abgeleitetem Klasse, die der<br />

Superklasse überdeckt. Es wird aber vorausgesetzt, daß sich die Parameter<br />

signifikant unterscheiden, sonst handelt es sich bei der Konstellation Superklasse –<br />

Subklasse um den Vorgang des Überschreibens. Soll die Orig<strong>in</strong>almethode<br />

aufgerufen werden, dann wird das Schlüsselwort „super“ benutzt. Damit wird der<br />

Methodenaufruf <strong>in</strong> der Hierarchie nach oben weitergegeben.<br />

Überschreiben e<strong>in</strong>er Oberklassen-Methode: Zum Überschreiben e<strong>in</strong>er Methode wird<br />

e<strong>in</strong>e Methode erstellt, die den gleichen Namen, Ausgabetyp und die gleiche<br />

Parameterliste wie e<strong>in</strong>e Methode der Superklasse besitzt. Da <strong>Java</strong> die erste<br />

Methodendef<strong>in</strong>ition ausführt, die es f<strong>in</strong>det und die <strong>in</strong> Namen, Ausgabetyp und<br />

Parameterliste übere<strong>in</strong>stimmt, wird die ursprüngliche Methodendef<strong>in</strong>ition dadurch<br />

verborgen.<br />

Konstruktor-Methoden können „technisch“ nicht überschrieben werden. Da sie den<br />

gleichen Namen wie die aktuelle Klasse haben, werden Konstruktoren nicht vererbt,<br />

sondern immer neu erstellt. Wird e<strong>in</strong> Konstruktor e<strong>in</strong>er bestimmten Klasse<br />

aufgerufen, wird gleichzeitig auch der Konstruktor aller Superklassen aktiviert, so<br />

daß alle Teile e<strong>in</strong>er Klasse <strong>in</strong>itialisiert werden. E<strong>in</strong> spezielles Überschreiben kann<br />

über super(arg1, arg2, ...) ermöglicht werden.<br />

Die Methode toStr<strong>in</strong>g() ist e<strong>in</strong>e <strong>in</strong> <strong>Java</strong> häufig verwendete Methode.<br />

„toStr<strong>in</strong>g()“ wird als weitere Instanzmethode der Klasse Rechentafel def<strong>in</strong>iert und<br />

überschreibt die Methode gleichen Namens, die <strong>in</strong> der Oberklasse Object def<strong>in</strong>iert<br />

ist, z.B. 56 :<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

{<br />

return " Rechenobjekt# " + nummer + " Erster Operand: "<br />

+ ersterOperand + " Zweiter Operand: " + zweiterOperand;<br />

}<br />

}<br />

56 PR14103<br />

48


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1.4.1.2 Superklassen und Subklassen, Vererbung und Klassenhierarchie<br />

Def<strong>in</strong>itionen<br />

Klassen können sich auf andere Klassen beziehen. Ausgangspunkt ist e<strong>in</strong>e<br />

Superklasse, von der Subklassen (Unter-) abgeleitet se<strong>in</strong> können. Jede Subklasse<br />

erbt den Zustand (über die Variablen-Deklarationen) und das Verhalten der<br />

Superklasse. Darüber h<strong>in</strong>aus können Subklassen eigene Variable und Methoden<br />

h<strong>in</strong>zufügen. Superklassen, Subklassen bilden e<strong>in</strong>e mehrstufige Hierarchie. In <strong>Java</strong><br />

s<strong>in</strong>d alle Klassen Ableitungen e<strong>in</strong>er e<strong>in</strong>zigen obersten Klasse – der Klasse Object.<br />

Sie stellt die allgeme<strong>in</strong>ste Klasse <strong>in</strong> der Hierarchie dar und legt die Verhaltensweisen<br />

und Attribute, die an alle Klassen <strong>in</strong> der <strong>Java</strong>-Klassenbibliothek vererbt werden, fest.<br />

Vererbung bedeutet, daß alle Klassen <strong>in</strong> e<strong>in</strong>e strikte Hierarchie e<strong>in</strong>geordnet s<strong>in</strong>d und<br />

etwas von übergeordneten Klassen erben. Was kann von übergeordneten Klassen<br />

vererbt werden? Beim Erstellen e<strong>in</strong>er neuen Instanz erhält man e<strong>in</strong> Exemplar jeder<br />

Variablen, die <strong>in</strong> der aktuellen Klasse def<strong>in</strong>iert ist. Zusätzlich wird e<strong>in</strong> Exemplar für<br />

jede Variable bereitgestellt, die sich <strong>in</strong> den Superklassen der aktuellen Klasse<br />

bef<strong>in</strong>det. Bei der Methodenauswahl haben neue Objekte Zugang zu allen<br />

Methodennamen ihrer Klasse und deren Superklasse. Methodennamen werden<br />

dynamisch beim Aufruf e<strong>in</strong>er Methode gewählt. Das bedeutet: <strong>Java</strong> prüft zuerst die<br />

Klasse des Objekts auf Def<strong>in</strong>ition der betreffenden Methode. Ist sie nicht <strong>in</strong> der<br />

Klasse des Objekts def<strong>in</strong>iert, sucht <strong>Java</strong> <strong>in</strong> der Superklasse dieser Klasse usw.<br />

aufwärts <strong>in</strong> der Hierarchie bis die Def<strong>in</strong>ition der Methode gefunden wird.<br />

Ist <strong>in</strong> e<strong>in</strong>er Subklasse e<strong>in</strong>e Methode mit gleichem Namen, gleicher Anzahl und<br />

gleichem Typ der Argumente wie <strong>in</strong> der Superklasse def<strong>in</strong>iert, dann wird die<br />

Methodendef<strong>in</strong>ition, die zuerst (von unten nach oben <strong>in</strong> der Hierarchie) gefunden<br />

wird, ausgeführt. Methoden der abgeleiteten Klasse überdecken die Methoden der<br />

Superklasse (Overrid<strong>in</strong>g beim Überschreiben / Überdef<strong>in</strong>ieren).<br />

Zum Ableiten e<strong>in</strong>er Klasse aus e<strong>in</strong>er bestehenden Klasse ist im Kopf der Klasse mit<br />

Hilfe des Schlüsselworts „extends“ e<strong>in</strong> Verweis auf die Basisklasse anzugeben.<br />

Dadurch wird bewirkt: Die abgeleitete Klasse erbt alle Eigenschaften der<br />

Basisklasse, d.h. alle Variablen und alle Methoden. Durch H<strong>in</strong>zufügen neuer<br />

Elemente oder Überladen der vorhandenen kann die Funktionalität der abgeleiteten<br />

Klasse erweitert werden.<br />

Die Vererbung e<strong>in</strong>er Klasse kann beliebig tief geschachtelt werden. E<strong>in</strong>e abgeleitete<br />

Klasse erbt dabei jeweils die Eigenschaften der unmittelbaren „Superklasse“, die<br />

ihrerseits die Eigenschaften ihrer unmittelbaren „Superklasse“ erbt.<br />

Superklassen können abstrakte Klassen mit generischem Verhalten se<strong>in</strong>. Von e<strong>in</strong>er<br />

abstrakten Klasse wird nie e<strong>in</strong>e direkte Instanz benötigt. Sie dient nur zu<br />

Verweiszwecken. Abstrakte Klassen dürfen ke<strong>in</strong>e Implementierung e<strong>in</strong>er Methode<br />

enthalten und s<strong>in</strong>d damit auch nicht <strong>in</strong>stanziierbar. <strong>Java</strong> charakterisiert abstrakte<br />

Klassen mit dem Schlüsselwort abstract. Abstrakte Klassen werden zum Aufbau<br />

e<strong>in</strong>er Klassenhierarchie verwendet, z.B. für die Zusammenfassung von zwei oder<br />

mehr Klassen.<br />

49


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Auch e<strong>in</strong>e abstrakte Methode ist zunächst e<strong>in</strong>mal durch das reservierte Wort<br />

"abstract" erklärt. E<strong>in</strong>e abstrakte Methode besteht nur aus dem Methodenkopf,<br />

anstelle des Methodenrumpfs (der Methodendef<strong>in</strong>ition) steht nur das "Semikolon",<br />

z.B. public abstract Str<strong>in</strong>g toStr<strong>in</strong>g();.<br />

Enthält e<strong>in</strong>e Klasse m<strong>in</strong>destens e<strong>in</strong>e abstrakte Methode, so wird automatisch die<br />

gesamte Klasse zu e<strong>in</strong>er abstrakten Klasse. Abstrakte Klassen enthalten ke<strong>in</strong>e<br />

Konstruktoren. Sie können zwar Konstruktoren aufnehmen, allerd<strong>in</strong>gs führt jeder<br />

explizite Versuch zur Erzeugung e<strong>in</strong>es Objekts e<strong>in</strong>er abstrakten Klasse zu e<strong>in</strong>er<br />

Fehlermeldung. Abstrakte Methoden stellen e<strong>in</strong>e Schnittstellenbeschreibung dar, die<br />

der Programmierer e<strong>in</strong>er Subklasse zu def<strong>in</strong>ieren hat. E<strong>in</strong> konkrete Subklasse e<strong>in</strong>er<br />

abstrakten Klasse muß alle abstrakten Methoden der Superklasse(n)<br />

implementieren.<br />

Beispiel: E<strong>in</strong>e Klassenhierarchie für "geometrische" Objekte 57<br />

Das folgende Klassendiagramm zeigt die hierarchische Struktur von Klassen, die<br />

"geometrische Objekte" beschreiben. All diesen geometrischen Objekten ist<br />

geme<strong>in</strong>sam: Sie werden durch e<strong>in</strong>en Bezugspunkt (x,y) fixiert. DieGeme<strong>in</strong>samkeiten<br />

s<strong>in</strong>d <strong>in</strong> der abstrakten Klasse "Geomobjekt" zusammengefaßt.<br />

57 vgl. PR14131<br />

50


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

GeomObjekt<br />

private double x;<br />

private double y;<br />

public double holeX();<br />

public void setzeX(double x);<br />

public double holeY();<br />

public void setzeY(double y);<br />

Kreis Rechteck<br />

private double r; private double breite;<br />

private double hoehe;<br />

public double holeR(); public double holeBreite();<br />

public void setzeR(double r); public void setzeBreite(double breite)<br />

public double umfang(); public double holeHoehe(double hoehe);<br />

public double flaeche(); public void setzeHoehe(double hoehe);<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g(); public double umfang();<br />

public double flaeche();<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g();<br />

Ausgangspunkt ist die abstrakte Klasse "GeomObjekt". Dort ist der allen Objekten<br />

zugeordnete Bezugspunkt fixiert. Subklassen (z.B. Kreis und Rechteck) erben diesen<br />

Bezugspunkt und die zum Zugriff auf ihn bereitgestellte Methoden. Außerdem führen<br />

die Subklassen die nötigen Spezialisierungen auf das jeweilige geometrische Objekt<br />

durch.<br />

import java.lang.*;<br />

public abstract class GeomObjekt extends Object<br />

{<br />

// Instanzvariable<br />

private double x, y; // Bezugspunkt geom. Objekte<br />

// Instanzmethoden<br />

public double holeX()<br />

{<br />

return x;<br />

}<br />

public void setzeX(double x)<br />

{<br />

this.x = x;<br />

}<br />

public double holeY()<br />

{<br />

return y;<br />

}<br />

public void setzeY(double y)<br />

{<br />

this.y = y;<br />

}<br />

// Abstrakte Methoden<br />

public abstract Str<strong>in</strong>g toStr<strong>in</strong>g();<br />

public abstract double umfang();<br />

51


public abstract double flaeche();<br />

}<br />

import java.lang.*;<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class Kreis extends GeomObjekt<br />

{<br />

// Instanzvariable<br />

private double r; // Radius<br />

// Konstruktoren<br />

public Kreis()<br />

{<br />

this(0.0,0.0,1.0);<br />

}<br />

public Kreis(double r)<br />

{<br />

this(0.0,0.0,r);<br />

}<br />

public Kreis(double x, double y, double r)<br />

{<br />

super();<br />

super.setzeX(x);<br />

super.setzeY(y);<br />

this.setzeR(r);<br />

}<br />

// Instanzmethoden<br />

public double holeR()<br />

{<br />

return r;<br />

}<br />

public void setzeR(double r)<br />

{<br />

this.r = (r >= 0.0 ? r : -r);<br />

}<br />

public double umfang()<br />

{<br />

double u = 2 * r * Math.PI;<br />

return u;<br />

}<br />

public double flaeche()<br />

{<br />

return r * r * Math.PI;<br />

}<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

{<br />

return "Kreis: (" + holeX() + ", " + holeY() +<br />

") " + "r = " + r;<br />

}<br />

}<br />

import java.lang.*;<br />

public class Rechteck extends GeomObjekt<br />

{<br />

// Instanzvariable<br />

private double breite, hoehe;<br />

// Konstruktoren<br />

public Rechteck()<br />

{<br />

this(0.0,0.0,1.0,1.0);<br />

}<br />

public Rechteck(double breite, double hoehe)<br />

{<br />

this(0.0,0.0,breite,hoehe);<br />

}<br />

public Rechteck(double x, double y, double breite, double hoehe)<br />

{<br />

52


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

super();<br />

super.setzeX(x);<br />

super.setzeY(y);<br />

this.setzeBreite(breite);<br />

this.setzeHoehe(hoehe);<br />

}<br />

// Instanzmethoden<br />

public double holeBreite()<br />

{<br />

return breite;<br />

}<br />

public void setzeBreite(double breite)<br />

{<br />

this.breite = ( breite >= 0 ? breite : -breite);<br />

}<br />

public double holeHoehe()<br />

{<br />

return hoehe;<br />

}<br />

public void setzeHoehe(double hoehe)<br />

{<br />

this.hoehe = ( hoehe >= 0 ? hoehe : -hoehe);<br />

}<br />

public double umfang()<br />

{<br />

return 2 * breite + 2 * hoehe;<br />

}<br />

public double flaeche()<br />

{<br />

return breite * hoehe;<br />

}<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

{<br />

return "Rechteck: (" + holeX() + ", " + holeY()<br />

+ ") " + "breite = " + breite +<br />

" hoehe = " + hoehe;<br />

}<br />

}<br />

Die Klasse "Test" überprüft die vorliegende Klassenhierarchie auf<br />

Funktionsfähigkeit:<br />

import java.lang.*;<br />

public class Test extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Erzeuge e<strong>in</strong>en Kreis<br />

Kreis k1 = new Kreis();<br />

System.out.pr<strong>in</strong>tln(k1.toStr<strong>in</strong>g());<br />

double umfang;<br />

umfang = k1.umfang();<br />

System.out.pr<strong>in</strong>tln("Umfang = " + umfang);<br />

System.out.pr<strong>in</strong>tln("Flaeche = " + k1.flaeche());<br />

// Erzeuge e<strong>in</strong>en anderen Kreises<br />

Kreis k2 = new Kreis(1.0,1.0,2.0);<br />

System.out.pr<strong>in</strong>tln(k2.toStr<strong>in</strong>g());<br />

umfang = k2.umfang();<br />

System.out.pr<strong>in</strong>tln("Umfang = " + umfang);<br />

System.out.pr<strong>in</strong>tln("Flaeche = " + k2.flaeche());<br />

// Erzeuge e<strong>in</strong>en dritten Kreis<br />

Kreis k3 = new Kreis(-2.0);<br />

System.out.pr<strong>in</strong>tln(k3.toStr<strong>in</strong>g());<br />

umfang = k3.umfang();<br />

System.out.pr<strong>in</strong>tln("Umfang = " + umfang);<br />

53


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

System.out.pr<strong>in</strong>tln("Flaeche = " + k3.flaeche());<br />

// Erzeugen e<strong>in</strong>es Rechteck<br />

Rechteck r1 = new Rechteck(2.0,2.0);<br />

System.out.pr<strong>in</strong>tln(r1.toStr<strong>in</strong>g());<br />

umfang = r1.umfang();<br />

System.out.pr<strong>in</strong>tln("Umfang = " + umfang);<br />

System.out.pr<strong>in</strong>tln("Flaeche = " + r1.flaeche());<br />

// Erzeugen e<strong>in</strong>es weiteren Rechtecks<br />

Rechteck r2 = new Rechteck(2.0,2.0,2.0,3.0);<br />

System.out.pr<strong>in</strong>tln(r2.toStr<strong>in</strong>g());<br />

umfang = r2.umfang();<br />

System.out.pr<strong>in</strong>tln("Umfang = " + umfang);<br />

System.out.pr<strong>in</strong>tln("Flaeche = " + r2.flaeche());<br />

}<br />

}<br />

1.4.1.3 Referenzen und Referenztypen<br />

Referenzen<br />

<strong>Java</strong> erlaubt die Def<strong>in</strong>ition von Klassen, aus denen Objekte erzeugt werden können.<br />

Objekte können als Referenztypen behandelt werden, die von Variablen angelegt<br />

und verwendet werden.<br />

Beim Zuweisen von Variablen für Objekte bzw. beim Weiterreichen von Objekten als<br />

Argumente an Methoden werden Referenzen auf diese Objekte festgelegt.<br />

Bsp.: Referenzen auf Objekte <strong>in</strong> der Klasse Rechentafel bzw. Rechentafeltest<br />

System.out.pr<strong>in</strong>tln("Referenzen auf Objekte");<br />

// Referenzen auf Objekte<br />

Rechentafel rechenObj1 = new Rechentafel();<br />

rechenObj1.ersterOperand = 200;<br />

rechenObj1.zweiterOperand = 300;<br />

Rechentafel rechenObj3 = new Rechentafel(300,200);<br />

System.out.pr<strong>in</strong>tln("Operanden von Instanz 1: " +<br />

rechenObj1.ersterOperand + ", " + rechenObj1.zweiterOperand);<br />

System.out.pr<strong>in</strong>tln("Operanden von Instanz 2 vor Zuweisung: " +<br />

rechenObj3.ersterOperand + ", " + rechenObj3.zweiterOperand);<br />

rechenObj3 = rechenObj1;<br />

System.out.pr<strong>in</strong>tln("Operanden von Instanz 2 nach Zuweisung: " +<br />

rechenObj3.ersterOperand + ", " + rechenObj3.zweiterOperand);<br />

// Test auf Gleichheit<br />

if (rechenObj1 == rechenObj3)<br />

{<br />

System.out.pr<strong>in</strong>tln("Die beiden Objekte s<strong>in</strong>d tatsaechlich gleich");<br />

}<br />

Der Test mit „==“ 58 bestätigt: Es handelt sich jetzt (nach der Zuweisung) um das<br />

gleiche Objekt, d.h.: die gleiche Referenz.<br />

<strong>Java</strong> verfügt über e<strong>in</strong> automatisches Speichermanagement. Deshalb braucht der<br />

<strong>Java</strong>-Programmierer sich nicht um die Rückgabe von Speicher zu kümmern, der von<br />

Referenzvariablen belegt ist. E<strong>in</strong> mit niederer Priorität im H<strong>in</strong>tergrund arbeitender<br />

„Garbage Collector“ sucht ständig nach Objekten, die nicht mehr referenziert werden,<br />

um den belegten Speicher freizugeben.<br />

F<strong>in</strong>alizer-Methoden. Sie werden aufgerufen, kurz bevor das Objekt im Papierkob<br />

landet und se<strong>in</strong> Speicher freigegeben wird. Zum Erstellen e<strong>in</strong>er F<strong>in</strong>alizer-Methode<br />

58 Der Operator „==“ überprüft die Gleichheit der Referenzen.<br />

54


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

dient der folgende E<strong>in</strong>trag <strong>in</strong> der Klassendef<strong>in</strong>ition void f<strong>in</strong>alize(){ ... }. Im<br />

Körper dieser Methode können alle möglichen Re<strong>in</strong>igungsprozeduren stehen, die<br />

das Objekt ausführen soll. Der Aufruf der Methode f<strong>in</strong>alize() bewirkt nicht<br />

unmittelbar die Ablage im Papierkorb. Nur durch das Entfernen aller Referenzen auf<br />

das Objekt wird das Objekt zum Löschen markiert.<br />

Referenztypen<br />

<strong>Java</strong> kennt zwei Arten von Typen: e<strong>in</strong>fache Typen und Referenztypen. E<strong>in</strong>fache<br />

Typen s<strong>in</strong>d: boolean, byte, short, <strong>in</strong>t, long, char, float und double.<br />

Klassen und Arrays s<strong>in</strong>d Referenztypen. E<strong>in</strong> Referenzwert enthält e<strong>in</strong>e Referenz auf<br />

die Daten e<strong>in</strong>es Objekts bzw. Arrays. Referenztypen müssen explizit mit Hilfe des<br />

Operators new erzeugt werden.<br />

1.4.1.4 Konvertieren von Objekten und Primitivtypen<br />

„Cast<strong>in</strong>g“ ist e<strong>in</strong> Mechanismus zum Konvertieren des Werts e<strong>in</strong>es Objekts oder e<strong>in</strong>es<br />

primitiven Typs <strong>in</strong> e<strong>in</strong>en anderen Typ. „Cast<strong>in</strong>g“ ergibt e<strong>in</strong> neues Objekt oder e<strong>in</strong>en<br />

neuen Wert und wirkt sich nicht auf das ursprüngliche Objekt bzw. den<br />

ursprünglichen Wert aus.<br />

Konvertieren von Primitivtypen<br />

Ist der angestrebte Typ „größer“ als der zu konvertierende Typ, ist häufig ke<strong>in</strong><br />

explizites „Cast<strong>in</strong>g“ nötig. E<strong>in</strong> „Byte“ oder e<strong>in</strong> Zeichen kann automatisch z.B. als<br />

„<strong>in</strong>t“, e<strong>in</strong> „<strong>in</strong>t“ als „long“, e<strong>in</strong> „<strong>in</strong>t“ als „float“ behandelt werden. Es gehen beim<br />

Konvertieren des Werts ke<strong>in</strong>e Informationen verloren, weil der größere Typ mehr<br />

Genauigkeit bietet als der kle<strong>in</strong>ere.<br />

Ist der angestrebte Typ „kle<strong>in</strong>er“ als der zu konvertierende Typ, ist „Cast<strong>in</strong>g“ nötig.<br />

Explizites Cast<strong>in</strong>g sieht so aus: (typname) wert<br />

„typname“ ist der Name des Typs, auf den konvertiert wird, „wert“ ist e<strong>in</strong> Ausdruck,<br />

der den zu konvertierenden Wert ergibt, z.B.: „(<strong>in</strong>t) x/y;“. Dieser Ausdruck teilt x<br />

durch y und wandelt dann das Ergebnis <strong>in</strong> „<strong>in</strong>t“ um. Da Cast<strong>in</strong>g e<strong>in</strong>e höhere<br />

Priorität als Arithmetik hat, müssen die Klammern angegeben werden.<br />

Konvertieren von Objekten<br />

Mit e<strong>in</strong>er E<strong>in</strong>schränkung können auch Klassen<strong>in</strong>stanzen <strong>in</strong> Instanzen anderer<br />

Klassen konvertiert werden. Die betroffenen Klassen müssen durch Vererbung<br />

mite<strong>in</strong>ander verbunden se<strong>in</strong>, d.h.: E<strong>in</strong> Objekt kann nur <strong>in</strong> e<strong>in</strong>e Instanz der Sub- oder<br />

Superklassen konvertiert werden, nicht aber <strong>in</strong> e<strong>in</strong>e beliebige Klasse.<br />

Durch Konvertieren e<strong>in</strong>es Objekts <strong>in</strong> e<strong>in</strong>e Instanz der Superklasse gehen<br />

Informationen, die die Subklasse bereitgestellt hat, verloren. Spezifisches Cast<strong>in</strong>g ist<br />

erforderlich: (klassename) objekt.<br />

„klassename“ ist der Name der Klasse, <strong>in</strong> die das Objekt konvertiert werden soll.<br />

„objekt“ ist e<strong>in</strong>e Referenz auf das zu konvertierende Objekt.<br />

55


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Konvertieren von Primitivtypen <strong>in</strong> Objekte und umgekehrt<br />

Primitive Typen und Objekte s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> zwei völlig verschiedene D<strong>in</strong>ge.<br />

Konvertierung und automatisches Cast<strong>in</strong>g s<strong>in</strong>d nicht möglich. Allerd<strong>in</strong>gs enthält das<br />

Paket „java.lang“ mehrere Subklassen, die je e<strong>in</strong>em primitiven Datentyp<br />

entsprechen: Integer, Float, Boolean usw. Mit den <strong>in</strong> diesen Klassen def<strong>in</strong>ierten<br />

Klassenmethoden kann mit Hilfe von new für alle Primitivtypen e<strong>in</strong>e „Art Objekt“<br />

erstellt werden, z.B.: „Integer <strong>in</strong>tObjekt = new Integer(13);“. Mit<br />

<strong>in</strong>tValue() wird e<strong>in</strong> primitiver „<strong>in</strong>t“-Wert aus e<strong>in</strong>em Integer-Objekt extrahiert,<br />

z.B.: <strong>in</strong>t ganzeZahl = <strong>in</strong>tObjekt.<strong>in</strong>tValue();<br />

1.4.1.5 Manipulieren von Objekten<br />

Vergleichen von Objekten<br />

Die relationalen Operatoren funktionieren <strong>in</strong> der Regel nur mit Primitivtypen, nicht mit<br />

Objekten. Die Ausnahme zu dieser Regel bilden die Operatoren „==“ und „!=“. Die<br />

Operatoren können für Objekte benutzt werden und prüfen, ob sich zwei Operanden<br />

auf genau das gleiche Objekt beziehen.<br />

<strong>Java</strong> besitzt ke<strong>in</strong> Konzept für das Überladen (Overload<strong>in</strong>g) von Operatoren. Zum<br />

Vergleichen von Instanzen eigendef<strong>in</strong>ierter Klassen müssen Sondermethoden <strong>in</strong> die<br />

Klasse e<strong>in</strong>bezogen werden.<br />

Bsp.: Gleichheitstest mit Objekten der „Str<strong>in</strong>g“-Klasse 59 .<br />

Die Str<strong>in</strong>g-Klasse def<strong>in</strong>iert die Methode equals(), die jeden Zeichen der<br />

Zeichenkette prüft und „true“ ausgibt, falls die beiden Zeichenketten den<br />

gleichen Wert haben. Nach dem Operator „==“ s<strong>in</strong>d die beiden „Str<strong>in</strong>g“-Objekte<br />

nicht gleich, weil sie zwar den gleichen Inhalt haben, aber nicht die gleichen<br />

Objekte s<strong>in</strong>d.<br />

// Besonderheiten im Zusammenhang mit Str<strong>in</strong>g-Objekten<br />

f<strong>in</strong>al class Str<strong>in</strong>gManipulationen<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Str<strong>in</strong>g a = "test";<br />

Str<strong>in</strong>g b = "test";<br />

Str<strong>in</strong>g c = new Str<strong>in</strong>g("test");<br />

Str<strong>in</strong>g d = new Str<strong>in</strong>g("test");<br />

// Díe folgenden Anweisungen geben wahr oder falsch<br />

// an die Konsole aus<br />

System.out.pr<strong>in</strong>tln("a == b " + (a==b)); // true<br />

System.out.pr<strong>in</strong>tln("c == d " + (c==d)); // false<br />

System.out.pr<strong>in</strong>tln("a == c " + (a==c)); // false<br />

System.out.pr<strong>in</strong>tln("a == \"test\" " + (a=="test")); // true<br />

System.out.pr<strong>in</strong>tln("c == \"test\" " + (c=="test")); // false<br />

System.out.pr<strong>in</strong>tln();<br />

System.out.pr<strong>in</strong>tln("a.equals(b) " + a.equals(b)); // true<br />

System.out.pr<strong>in</strong>tln("c.equals(d) " + c.equals(d)); // true<br />

System.out.pr<strong>in</strong>tln("a.equals(c) " + a.equals(c)); // true<br />

System.out.pr<strong>in</strong>tln("a.equals(\"test\") " + a.equals("test")); // true<br />

System.out.pr<strong>in</strong>tln("c.equals(\"test\") " + c.equals("test")); // true<br />

}<br />

}<br />

59 PR14110<br />

56


Kopieren von Objekten<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die clone()-Methode erzeugt e<strong>in</strong> Duplikat als Kopie e<strong>in</strong>es Objekts. Damit e<strong>in</strong><br />

Objekt geklont werden kann, muß es die „Cloneable“-Schnittstelle unterstützen.<br />

Die Cloneable-Schnittstelle im Paket java.lang hat selbst ke<strong>in</strong>e Methoden, sie<br />

dient lediglich als Indikator dafür, daß e<strong>in</strong> Objekt geklont werden kann. Das Format<br />

für die clone()-Methode ist: protected Object clone() throws<br />

CloneNotSupportedException<br />

Bsp.: Die Klasse Rechentafel erhält e<strong>in</strong>e clone()-Methode zum Klonen von<br />

Rechentafel-Objekten 60 .<br />

public class Rechentafel implements Cloneable<br />

{<br />

// Instanzvariable<br />

private <strong>in</strong>t ersterOperand = 0;<br />

private <strong>in</strong>t zweiterOperand = 0;<br />

private <strong>in</strong>t nummer; // Identifikationsnummer<br />

// Klassenvariable<br />

static <strong>in</strong>t anzRechenobjekte = 0;<br />

// Konstruktoren<br />

Rechentafel()<br />

{<br />

this(0,1);<br />

}<br />

Rechentafel(<strong>in</strong>t ersterOperand, <strong>in</strong>t zweiterOperand)<br />

{<br />

super();<br />

this.ersterOperand = ersterOperand;<br />

this.zweiterOperand = zweiterOperand;<br />

nummer = ++anzRechenobjekte;<br />

}<br />

// Kopierkonstruktor<br />

Rechentafel(Rechentafel rechenObjekt)<br />

{<br />

this(rechenObjekt.ersterOperand,rechenObjekt.zweiterOperand);<br />

}<br />

// Operationen<br />

public <strong>in</strong>t holersterOperand()<br />

{<br />

return ersterOperand;<br />

}<br />

public void setzersterOperand(<strong>in</strong>t ersterOperand)<br />

{<br />

this.ersterOperand = ersterOperand;<br />

}<br />

public <strong>in</strong>t holzweiterOperand()<br />

{<br />

return zweiterOperand;<br />

}<br />

public void setzweiterOperand(<strong>in</strong>t zweiterOperand)<br />

{<br />

this.zweiterOperand = zweiterOperand;<br />

}<br />

public <strong>in</strong>t addiere()<br />

{<br />

return ersterOperand + zweiterOperand;<br />

}<br />

public <strong>in</strong>t subtrahiere()<br />

{<br />

60 PR14202<br />

57


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

return ersterOperand - zweiterOperand;<br />

}<br />

public <strong>in</strong>t multipliziere()<br />

{<br />

return ersterOperand * zweiterOperand;<br />

}<br />

public <strong>in</strong>t dividiere()<br />

{<br />

// ganzzahlige Division<br />

try {<br />

/* Innerhalb des try-Blocks werden diejenigen<br />

kritischen Aktionen durchgefuehrt, die<br />

Ausnahmen erzeugen koennen<br />

*/<br />

return (ersterOperand / zweiterOperand);<br />

}<br />

catch(java.lang.ArithmeticException a)<br />

{<br />

System.out.pr<strong>in</strong>tln(" Fehler: Division durch Null");<br />

System.out.pr<strong>in</strong>tln("Divisor wird auf 1 gesetzt!");<br />

zweiterOperand = 1;<br />

return (ersterOperand / zweiterOperand);<br />

}<br />

}<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

{<br />

return "Rechenobjekt# " + nummer + " Erster Operand: "<br />

+ ersterOperand + " Zweiter Operand: " + zweiterOperand;<br />

}<br />

public Object clone()<br />

{<br />

Object o = null;<br />

try {<br />

o = super.clone();<br />

}<br />

catch(CloneNotSupportedException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Objekt kann nicht geklont werden");<br />

}<br />

return o;<br />

}<br />

}<br />

Diese Methode kann dann über e<strong>in</strong> <strong>in</strong> der Klasse Rechentafeltest <strong>in</strong>stanziertes<br />

Objekt der Klasse Rechentafel aufgerufen werden:<br />

import java.lang.*;<br />

class Rechentafeltest extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g argv[])<br />

{<br />

// Erzeugen Instanz der Klasse Rechentafel<br />

Rechentafel erstesRechenobjekt = new Rechentafel(3,2);<br />

System.out.pr<strong>in</strong>tln("E<strong>in</strong>e Instanz der Klasse " +<br />

erstesRechenobjekt.getClass().getName() +<br />

" wurde erzeugt.");<br />

System.out.pr<strong>in</strong>tln(erstesRechenobjekt.toStr<strong>in</strong>g());<br />

// Klonen e<strong>in</strong>es Rechenobjekts<br />

System.out.pr<strong>in</strong>tln("Klonen des Objekts");<br />

Rechentafel zweitesRechenobjekt = (Rechentafel)<br />

erstesRechenobjekt.clone();<br />

System.out.pr<strong>in</strong>tln(zweitesRechenobjekt.toStr<strong>in</strong>g());<br />

if (erstesRechenobjekt == zweitesRechenobjekt)<br />

System.out.pr<strong>in</strong>tln("Erstes Objekt == Zweites Objekt");<br />

else<br />

58


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

System.out.pr<strong>in</strong>tln("Erstes Objekt != Zweites Objekt");<br />

// Manipulation<br />

System.out.pr<strong>in</strong>tln(<br />

"Aenderungen am Orig<strong>in</strong>al bleiben unberuecksichtigt");<br />

erstesRechenobjekt.setzersterOperand(7);<br />

erstesRechenobjekt.setzweiterOperand(5);<br />

System.out.pr<strong>in</strong>tln(erstesRechenobjekt.toStr<strong>in</strong>g());<br />

System.out.pr<strong>in</strong>tln(zweitesRechenobjekt.toStr<strong>in</strong>g());<br />

// Zuweisung<br />

System.out.pr<strong>in</strong>tln("Zuweisen des Objekts");<br />

Rechentafel drittesRechenobjekt;<br />

drittesRechenobjekt = erstesRechenobjekt;<br />

System.out.pr<strong>in</strong>tln(drittesRechenobjekt.toStr<strong>in</strong>g());<br />

if (erstesRechenobjekt == drittesRechenobjekt)<br />

System.out.pr<strong>in</strong>tln("Erstes Objekt == Drittes Objekt");<br />

else<br />

System.out.pr<strong>in</strong>tln("Erstes Objekt != Drittes Objekt");<br />

// Manipulieren<br />

System.out.pr<strong>in</strong>tln("Aenderungen beziehen sich auch auf die Kopie");<br />

erstesRechenobjekt.setzersterOperand(2);<br />

erstesRechenobjekt.setzweiterOperand(3);<br />

System.out.pr<strong>in</strong>tln(erstesRechenobjekt.toStr<strong>in</strong>g());<br />

System.out.pr<strong>in</strong>tln(drittesRechenobjekt.toStr<strong>in</strong>g());<br />

// Kopierkonstruktor<br />

System.out.pr<strong>in</strong>tln("Arbeiten mit e<strong>in</strong>em Kopierkonstruktor");<br />

Rechentafel viertesRechenobjekt = new Rechentafel(erstesRechenobjekt);<br />

System.out.pr<strong>in</strong>tln(viertesRechenobjekt.toStr<strong>in</strong>g());<br />

}<br />

}<br />

Der Test zeigt: Das geklonte Objekt enthält die gleichen Werte.<br />

Bestimmen der Klasse e<strong>in</strong>es Objekts<br />

Die Klasse Class stellt über die Methode getname() den Namen e<strong>in</strong>er Klasse zur<br />

Verfügung: public Str<strong>in</strong>g getName()<br />

Bsp.: Der folgende Aufruf<br />

Rechentafel e<strong>in</strong>Rechenobjekt = new<br />

Rechentafel(3,2);<br />

System.out.pr<strong>in</strong>t("E<strong>in</strong>e Instanz der Klasse ");<br />

e<strong>in</strong>Rechenobjekt.zeigeKlasse();<br />

betimmt den Namen der Klasse von „e<strong>in</strong>Rechenobjekt“. Die Methode „zeigeKlasse“<br />

enthält die Methode getName() der Klasse Class. Das Objekt, dessen<br />

Klassenzugehörigkeit bestimmt werden soll ruft die Methode getClass() der Klasse<br />

Object auf. Das Ergebnis dieser Methode ist e<strong>in</strong> Class-Objekt, das die Methode<br />

getName() kennt. „getName()“ gibt die Zeichenkette aus.<br />

void zeigeKlasse()<br />

{<br />

System.out.pr<strong>in</strong>t(this.getClass().getName());<br />

}<br />

E<strong>in</strong> anderen Test bietet der Operator „<strong>in</strong>stanceof“. Er hat zwei Operanden: E<strong>in</strong><br />

Objekt l<strong>in</strong>ks und den Namen der Klasse rechts. Der Ausdruck gibt true oder false<br />

aus, je nach dem, ob das Objekt e<strong>in</strong>e Instanz der benannten Klasse ist, z.B.:<br />

if (!(anderesObj <strong>in</strong>stanceof Rechentafel)) return false;<br />

59


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

der Operator <strong>in</strong>stanceof kann auch als Schnittstelle benutzt werden. Falls e<strong>in</strong><br />

Objekt e<strong>in</strong>e Schnittstelle implementiert, gibt <strong>in</strong>stanceof mit dem<br />

Schnittstellennamen auf der rechten Seite true aus.<br />

1.4.1.6 Innere (lokale) und anonyme Klassen<br />

Lokale Klassen<br />

Seit JDK 1.1 kann man <strong>in</strong>nerhalb e<strong>in</strong>er bestehenden Klasse z.B. X e<strong>in</strong>e neue Klasse<br />

z.B. Y def<strong>in</strong>ieren 61 . Diese Klasse ist nur <strong>in</strong>nerhalb von X sichtbar. Objekte von Y<br />

können damit nur aus X erzeugt werden. Y kann aber auf alle Instanzmerkmale von<br />

X zugreifen. Bei der Instanzierung wird (neben e<strong>in</strong>em impliziten this-Zeiger) e<strong>in</strong><br />

weiterer Verweis auf die erzeugende Instanz der umschließenden Klasse übergeben,<br />

der es ermöglicht, auf sie zuzugreifen.<br />

Die Anwendung lokaler Klassen für die Ereignisbehandlung besteht dar<strong>in</strong>, mit ihrer<br />

Hilfe die benötigten EventListener zu implementieren. Dazu wird das GUI-Objekt,<br />

das e<strong>in</strong>en Event-Handler benötigt, e<strong>in</strong>e lokale Klasse def<strong>in</strong>iert und aus e<strong>in</strong>er<br />

passenden Adapter-Klasse abgeleitet. Es braucht nicht mehr das gesamte Interface<br />

implementiert zu werden, ( denn die Methodenrümpfe werden ja aus der<br />

Adapterklasse geerbt,) sondern lediglich die tatsächlich benötigetn Methoden.<br />

Anonyme Klassen<br />

E<strong>in</strong>e Variante der lokalen Klassen s<strong>in</strong>d anonyme Klassen. Sie werden ebenfalls lokal<br />

zu e<strong>in</strong>er anderen Klasse erzeugt, kommen aber ohne Klassennamen aus. Dazu<br />

werden sie bei der Übergabe e<strong>in</strong>es Objekts an e<strong>in</strong>e Methode oder als Rückgabewert<br />

e<strong>in</strong>er Methode <strong>in</strong>nerhalb e<strong>in</strong>er e<strong>in</strong>zigen Anweisung def<strong>in</strong>iert und <strong>in</strong>stanziert. Damit<br />

e<strong>in</strong>e anonyme Klasse überhaupt irgende<strong>in</strong>er s<strong>in</strong>nvollen Aufgabe zugeführt werden<br />

kann, muß sie aus e<strong>in</strong>er anderen Klasse abgeleitet se<strong>in</strong> oder e<strong>in</strong> bestehendes<br />

Interface implementieren.<br />

Adapterklassen<br />

E<strong>in</strong>e Adapterklasse implementiert e<strong>in</strong> vorgegebenes Interface mit leeren<br />

Methodenrümpfen. Adapterklassen können verwendet werden, wenn aus e<strong>in</strong>em<br />

Interface lediglich e<strong>in</strong> Teil der Methoden benötigt wird, der Rest aber un<strong>in</strong>teressant<br />

ist. In diesem Fall leitet man e<strong>in</strong>e neue Klasse aus der Adapterklasse ab, anstatt das<br />

zugehörige Interface zu implementieren und überlagert die benötigten Methoden.<br />

Alle übrigen Methoden des Interfaces werden von der Basisklasse zur Verfügung<br />

gestellt.<br />

Zu jedem der Low-Level-Ereignisempfänger stellt java.awt.event e<strong>in</strong>e passende<br />

Adapterklasse zur Verfügung.<br />

61 Im JDK wird das Konzept als Inner Classes bezeichnet<br />

60


1.4.1.7 Schnittstellen und Pakete<br />

Schnittstellen<br />

Def<strong>in</strong>ition<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e Schnittstelle ist <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e Sammlung von Methodennamen ohne konkrete<br />

Def<strong>in</strong>ition. Klassen haben die Möglichkeit zur Def<strong>in</strong>ition e<strong>in</strong>es Objekts, Schnittstellen<br />

können lediglich e<strong>in</strong> paar abstrakte Methoden und Konstanten (f<strong>in</strong>ale Daten)<br />

def<strong>in</strong>ieren 62 .<br />

Schnittstellen bilden <strong>in</strong> <strong>Java</strong> den Ersatz für Mehrfachvererbung. E<strong>in</strong>e Klasse kann<br />

demnach nur e<strong>in</strong>e Superklasse, jedoch dafür mehrere Schnittstellen haben.<br />

E<strong>in</strong> Schnittstelle („Interface“) ist e<strong>in</strong>e besondere Form der Klasse, die ausschließlich<br />

abstrakte Methoden und Konstanten enthält. Anstelle von class dient zur Def<strong>in</strong>ition<br />

e<strong>in</strong>es „Interface“ das Schlüsselwort „<strong>in</strong>terface“.<br />

"Interfaces" werden formal wie Klassen def<strong>in</strong>iert, z.B.:<br />

public <strong>in</strong>terface me<strong>in</strong>eSchnittstelle<br />

{<br />

// Abstrakte Methoden<br />

}<br />

bzw.<br />

public <strong>in</strong>terface me<strong>in</strong>eSpezialschnittstelle extend me<strong>in</strong>eSchnittstelle<br />

{<br />

// Abstrakte Methoden<br />

}<br />

"Interfaces" können benutzt werden, <strong>in</strong>dem sie <strong>in</strong> e<strong>in</strong>er Klasse implementiert werden,<br />

z.B.:<br />

public class Me<strong>in</strong>eKlasse extend Object implements me<strong>in</strong>eSchnittstelle<br />

{<br />

/* Normale Klassendef<strong>in</strong>ition + Methoden aus me<strong>in</strong>eSchnittstelle */<br />

}<br />

E<strong>in</strong>e Klasse kann mehrere Schnittstellen implementieren, z.B.<br />

public class Me<strong>in</strong>eKlasse extends Object<br />

implements me<strong>in</strong>eSchnittstelle1, me<strong>in</strong>eSchnittstelle2<br />

{<br />

/* Normale Klassendef<strong>in</strong>ition + Metoden aus me<strong>in</strong>erSchnittstelle1<br />

und me<strong>in</strong>erSchnittstelle2 */<br />

}<br />

Verwendung<br />

Bei der Vererbung von Klassen spricht man von Ableitung, bei Interfaces nennt man<br />

es Implementierung. Durch Implementieren e<strong>in</strong>er Schnittstelle verpflichtet sich die<br />

Klasse, alle Methoden, die im Interface def<strong>in</strong>iert s<strong>in</strong>d, zu implementieren. Die<br />

Implementierung e<strong>in</strong>es Interface wird durch das Schlüsselwort „implements“ bei<br />

der Klassendef<strong>in</strong>ition angezeigt.<br />

62 Angaben zur Implementierung s<strong>in</strong>d nicht möglich<br />

61


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bsp. 63 : Das folgende Interface 64 mit dem Namen „Vergleich“ umfaßt Deklarationen<br />

für Vergleichsfunktionen.<br />

<strong>in</strong>terface Vergleich<br />

{<br />

boolean kle<strong>in</strong>erAls(Object ls, Object rs);<br />

boolean kle<strong>in</strong>erAlsoderGleich(Object ls, Object rs);<br />

}<br />

Die Vergleichsfunktionen sollen zum Vergleichen aller möglichen Objekte<br />

herangezogen werden:<br />

1. Verwendung des Interface „Vergleich“ zum Sortieren von Zeichenketten<br />

public class Str<strong>in</strong>gSortTest<br />

{<br />

static class Str<strong>in</strong>gVergleich implements Vergleich<br />

{<br />

public boolean kle<strong>in</strong>erAls(Object l, Object r)<br />

{<br />

return((Str<strong>in</strong>g)l).toLowerCase().compareTo(((Str<strong>in</strong>g)r).toLowerCase()) <<br />

0;<br />

}<br />

public boolean kle<strong>in</strong>erAlsoderGleich(Object l, Object r)<br />

{<br />

return((Str<strong>in</strong>g)l).toLowerCase().compareTo(((Str<strong>in</strong>g)r).toLowerCase())


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2. Verwendung des Interface „Vergleich“ zum Sortieren von Zahlen<br />

public class ZahlenSortTest<br />

{<br />

static class ZahlenVergleich implements Vergleich<br />

{<br />

public boolean kle<strong>in</strong>erAls(Object l, Object r)<br />

{<br />

return (((Integer) l).<strong>in</strong>tValue() < ((Integer) r).<strong>in</strong>tValue());<br />

}<br />

public boolean kle<strong>in</strong>erAlsoderGleich(Object l, Object r)<br />

{<br />

return (((Integer) l).<strong>in</strong>tValue()


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die unter 1. und 2. angegebenen Klassen benutzen die Klasse Sort, die die<br />

eigentliche Funktion für das Sortieren enthält:<br />

public class Sort<br />

{<br />

private Vergleich vergleich;<br />

public Sort(Vergleich vergl)<br />

{<br />

vergleich = vergl;<br />

}<br />

public void sort(Object x[],<strong>in</strong>t n)<br />

{<br />

bubbleSort(x,n);<br />

}<br />

public void bubbleSort(Object x[], <strong>in</strong>t n)<br />

{<br />

for (<strong>in</strong>t i = 0; i < x.length; i++)<br />

{<br />

for (<strong>in</strong>t j = i + 1; j < x.length; j++)<br />

{<br />

if (!vergleich.kle<strong>in</strong>erAls(x[i],x[j]))<br />

{<br />

Object temp = x[i];<br />

x[i] = x[j];<br />

x[j] = temp;<br />

}<br />

}<br />

}<br />

}<br />

}<br />

Konstanten. Neben abstrakten Methoden können Interfaces auch Konstanten<br />

(Variablen mit dem Attributen static und f<strong>in</strong>al) enthalten. Wenn e<strong>in</strong>e Klasse e<strong>in</strong><br />

solches Interface implementiert, erbt es gleichzeitig auch alle se<strong>in</strong>e Konstanten.<br />

E<strong>in</strong> Interface kann ausschließlich Konstanten enthalten.<br />

Pakete<br />

Def<strong>in</strong>ition<br />

Pakete s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> Zusammenfassungen von Klassen und Schnittstellen. Sie<br />

entsprechen <strong>in</strong> <strong>Java</strong> den Bibliotheken anderer Programmiersprachen. Pakete<br />

ermöglichen, daß modulare Klassengruppen nur verfügbar s<strong>in</strong>d, wenn sie gebraucht<br />

werden. Potentielle Konflikte zwischen Klassenamen <strong>in</strong> unterschiedlichen<br />

Klassengruppen können dadurch vermieden werden.<br />

Für Methoden und Variablen <strong>in</strong>nerhalb von Paketen besteht e<strong>in</strong>e<br />

Zugriffsschutzschablone. Jedes Paket ist gegenüber anderen, nicht zum Paket<br />

zählenden Klassen abgeschirmt. Klassen, Methoden oder Variablen s<strong>in</strong>d nur<br />

sichtbar für Klassen im gleichen Paket. Klassen, die ohne „package“ Anweisung<br />

def<strong>in</strong>iert s<strong>in</strong>d, werden vom Compiler <strong>in</strong> e<strong>in</strong> „Standardpaket“ gestellt. Voraussetzung<br />

dafür ist: Die „.java“- und „.class“-Dateien dieses Pakets bef<strong>in</strong>den sich im aktuellen<br />

Verzeichnis (oder <strong>in</strong> e<strong>in</strong>en darunter liegenden Klassenverzeichnis).<br />

64


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die <strong>Java</strong>-Klassenbibliothek 65 von <strong>Java</strong> 1.0 enthält folgende Pakete:<br />

- java.lang: Klassen, die unmittelbar zur Sprache gehören. Das Paket umfaßt u.a.<br />

die Klassen Object, Str<strong>in</strong>g, System, außerdem die Sonderklassen für die<br />

Primitivtypen (Integer, Character, Float, etc.)<br />

Object Aus dieser Klasse leiten sich alle weiteren Klassen ab. Ohne explizite Angabe der<br />

Klasse, die e<strong>in</strong>e neue Klasse erweitern soll, erweitert die neue Klasse die Object-Klasse.<br />

Die Klasse Object ist die Basis-Klasse jeder anderen Klasse <strong>in</strong> <strong>Java</strong>. Sie def<strong>in</strong>iert<br />

Methoden, die von allen Klasse <strong>in</strong> <strong>Java</strong> unterstützt werden.<br />

Class Für jede <strong>in</strong> java def<strong>in</strong>ierte Klasse gibt es e<strong>in</strong>e Instanz von Class, die diese Klasse<br />

beschreibt<br />

Str<strong>in</strong>g Enthält Methoden zur Manipulation von <strong>Java</strong>-Zeichenketten<br />

Str<strong>in</strong>gBuffer Dient zum Erstellen von <strong>Java</strong>-Zeichenketten<br />

Thread Stellt e<strong>in</strong>en Ausführungs-Thread <strong>in</strong> e<strong>in</strong>em <strong>Java</strong>-Programm dar. Jedes Programm kann<br />

mehrere Threads laufen lassen<br />

ThreadGroup Ermöglicht die Verknüpfung von Threads untere<strong>in</strong>ander. E<strong>in</strong>ige Thread-Operationen<br />

können nur von Threads aus der gleichen ThreadGroup ausgeführt werden.<br />

Throwable Ist die Basisklasse für Ausnahmen. Jedes Objekt, das mit der "catch"-Anweisung<br />

gefangen oder mit der "throw"-Anweisung verworfen wird, muß e<strong>in</strong>e Subklasse von<br />

Throwable se<strong>in</strong>.<br />

System Stellt spezielle Utilities auf Systemebene zur Verfügung<br />

Runtime Enthält e<strong>in</strong>e Vielzahl gleicher Funktionen wie System, behandelt aber auch das Laufen<br />

externer Programme<br />

Process Stellt e<strong>in</strong> externes Programm dar, das von e<strong>in</strong>em Runtime-Objekt gestartet wurde.<br />

Math Stellt e<strong>in</strong>e Reihe mathematischer Funktionen zur verfügung<br />

Number Ist die Basisklasse für Double,Float, Integer und Long (Objeckt-Wrapper)<br />

Character Ist e<strong>in</strong> Objekt-Wrapper für den datentyp char und enthält e<strong>in</strong>e Reihe nützlicher<br />

zeichenorientierter Operationen<br />

Boolean Ist e<strong>in</strong> Objekt-Wrapper für den Datentyp boolean<br />

ClassLoader Ermöglicht der Laufzeit-Umgebung von <strong>Java</strong> neue Klassen h<strong>in</strong>zuzufügen<br />

SecurityManager Legt die Sicherheits-Restriktionen der aktuellen Laufzeitumgebung fest. Viele <strong>Java</strong>-<br />

Klassen benutzen den Security-Manager zur Sicherstellung, daß e<strong>in</strong>e Operation auch<br />

tatsächlich genehmigt ist.<br />

Compiler Ermöglicht, falls vorhanden, den Zugriff auf den "just-<strong>in</strong>-time" Compiler<br />

Abb.: Klassen des java.lang-Pakets<br />

Zusätzlich enthält das java.lang-Paket noch zwei Schnittstellen:<br />

Cloneable Muß von e<strong>in</strong>em anderen Objekt implementiert werden, das dann geklont oder<br />

kopiert werden kann<br />

Runnable Wird zusammen mit der Thread-Klasse benutzt, um die aufgerufene Methode<br />

zu def<strong>in</strong>ieren, wenn e<strong>in</strong> Thread gestartet wird.<br />

Abb.: Schnittstellen im java.lang-Paket<br />

- java.util<br />

- java.io: Klassen zum Lesen und Schreiben von Datenströmen und zum<br />

Handhaben von Dateien.<br />

65 Die Klassenbibliothek des JDK bef<strong>in</strong>det sich <strong>in</strong> e<strong>in</strong>em Paket mit dem namen „java“.<br />

65


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

- java.net: Klassen zur Netzunterstützung, z.B. socket und URL (e<strong>in</strong>e Klasse<br />

zum Darstellen von Referenzen auf Dokumente im World Wide Web).<br />

- java.awt (Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit): Klassen zum Implementieren e<strong>in</strong>er<br />

grafischen Benutzeroberfläche. Das Paket enthält auch e<strong>in</strong>e Klasse für Grafik<br />

(java.awt.Graphics) und Bildverarbeitung (java.awt.Image).<br />

- java.applet: Klassen zum Implementieren von Applets, z.B. die Klasse Applet.<br />

Die <strong>Java</strong> Version 1.1 hat die Klassenbibliothek umfassend erweitert 66 :<br />

Paket Bedeutung<br />

java.applet Applets<br />

java.awt Abstract W<strong>in</strong>dow Toolkit<br />

java.awt.datatranfer ClipBoard-Funktionalität (Copy / Paste)<br />

java.awt.event AWT Event-handl<strong>in</strong>g<br />

java.awt.image Bildanzeige<br />

java.beans <strong>Java</strong> Beans<br />

java.io E<strong>in</strong>- und Ausgabe, Streams<br />

java.lang Elementare Sprachunterstützung<br />

java.lang.reflect Introspektion, besserer Zugriff auf Klassen durch<br />

Debugger und Inspektoren<br />

java.math<br />

java.net Netzzugriffe<br />

java.rmi Remote Method Invocation, Zugriff auf Objekte <strong>in</strong><br />

anderen virtuellen Masch<strong>in</strong>en<br />

java.rmi.dgc RMI Distributed Garbage Collection<br />

java.rmi.registry Verwaltet Datenbank, die RMI-Verb<strong>in</strong>dungen<br />

koord<strong>in</strong>iert<br />

java.rmi.server RMI-Server<br />

java.security Sicherheit durch digitale Signaturen, Schlüssel<br />

java.security.aci Access Control Lists<br />

java.security.<strong>in</strong>terfaces Digital Signature Algorithm (DAS-Klassen)<br />

java.sql Datenbankzugriff (JDBC)<br />

java.util Diverse Utilities, Datenstrukturen<br />

java.util.zip JAR-Files, Kompression, Prüfsummen<br />

Abb.: Klassenbibliothek der <strong>Java</strong>-Version 1.1<br />

Verwendung<br />

Jede Klasse ist Bestandteil e<strong>in</strong>es Pakets. Der vollständige Name e<strong>in</strong>er Klasse<br />

besteht aus dem Namen des Pakets, danach kommt der e<strong>in</strong> Punkt, gefolgt von dem<br />

eigentlichen Namen der Klasse.<br />

Zur Verwendung e<strong>in</strong>er Klasse muß angegeben werden, <strong>in</strong> welchem Paket sie liegt.<br />

Hier gibt es zwei unterschiedliche Möglichkeiten:<br />

- Die Klasse wird über ihren vollen (qualifizieren) Namen angesprochen, z.B.<br />

java.util.Date d = new java.util.Date();<br />

- Am Anfang des Klassenprogramms werden die gewünschten Klassen mit Hilfe der import-Anweisung<br />

e<strong>in</strong>gebunden, z.B.:<br />

import java util.*;<br />

......<br />

Date d = new Date();<br />

Die import-Anweisung gibt es <strong>in</strong> unterschiedlichen Ausprägungen:<br />

66 Zusätzlich 15 weitere Packages, etwa 500 Klassen und Schnittstellen<br />

66


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

-- Mit "import paket.Klasse" wird genau e<strong>in</strong>e Klasse importiert, alle anderen Klassen des Pakets<br />

bleiben verborgen<br />

--Mit "import paket.*" 67 können alle Klassen des angegebenen Pakets auf e<strong>in</strong>mal importiert<br />

werden.<br />

Standardmäßig haben <strong>Java</strong>-Klassen Zugang zu den <strong>in</strong> java.lang bef<strong>in</strong>dlichen<br />

Klassen. Klassen aus anderen Paketen müssen explizit über den Paketnamen<br />

e<strong>in</strong>bezogen oder <strong>in</strong> die Quelldatei importiert werden.<br />

1.4.1.8 Polymorphismus und B<strong>in</strong>den<br />

Polymorphismus<br />

Def<strong>in</strong>ition<br />

Polymorphismus ist die Eigenschaft von Objekten, mehreren Klassen (und nicht nur<br />

genau e<strong>in</strong>er Klasse) anzugehören, d.h. je nach Zusammenhang <strong>in</strong> unterschiedlicher<br />

Gestalt (polymorph) aufzutreten. <strong>Java</strong> ist polymorph.<br />

Bsp. 68 : Das folgende Programm Poly ist e<strong>in</strong>e Anwendung zu der bereits bekannten<br />

Klassenhierarchie für geometrische Objekte. Es behandelt Ersche<strong>in</strong>ungsformen<br />

des Polymorphismus.<br />

import java.lang.*;<br />

public class Poly extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Kreis k = new Kreis(0.0,1.0,2.0);<br />

Rechteck r = new Rechteck(0.0,1.0,2.0,2.0);<br />

// GeomObjekt geom = new GeomObjekt();<br />

/* unzulaessig, da GeomObjekt abstrakt ist */<br />

Object o = new Object();<br />

// Folgende Zuweisungen s<strong>in</strong>d zulaessig<br />

GeomObjekt geom1 = k;<br />

GeomObjekt geom2 = new Kreis(1.0,1.0,1.0);<br />

GeomObjekt geom3 = r;<br />

GeomObjekt geom4 = new Rechteck(1.0,1.0,1.0,4.0);<br />

o = k;<br />

// Aufruf der Methoden toStr<strong>in</strong>g() und umfang()<br />

// ueber geom1<br />

System.out.pr<strong>in</strong>tln(geom1.toStr<strong>in</strong>g());<br />

System.out.pr<strong>in</strong>tln("Umfang: " + geom1.umfang());<br />

/* geom1 ist e<strong>in</strong> GeomObjekt. GeomObjekt enthaelt e<strong>in</strong>e<br />

(abstrakte) Def<strong>in</strong>ition von toStr<strong>in</strong>g() und von umfang().<br />

Zur Laufzeit ist der Wert von geom1 e<strong>in</strong>e Referenz auf<br />

e<strong>in</strong> Objekt der Klasse Kreis, daher werden die im Kreis<br />

def<strong>in</strong>ierten (allgeme<strong>in</strong>er: die <strong>in</strong> Kreis def<strong>in</strong>ierten<br />

bzw. ererbten) Methoden toStr<strong>in</strong>g() und umfang() ausgefuehrt.<br />

*/<br />

// Aufruf der Methoden toStr<strong>in</strong>g() und umfang() ueber o<br />

System.out.pr<strong>in</strong>tln(o.toStr<strong>in</strong>g());<br />

67 type import on demand, d.h.: Die Klasse wird erst dann <strong>in</strong> dem angegebenen Paket gesucht, wenn das<br />

Programm sie wirklich benötigt.<br />

68 Vgl. PR14181<br />

67


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

/* o ist e<strong>in</strong> Object. Object enthaelt e<strong>in</strong>e Def<strong>in</strong>ition von<br />

toStr<strong>in</strong>g(), daher akzeptiert der <strong>Java</strong>-Compiler<br />

(zur Uebersetzungszeit) o.toStr<strong>in</strong>g().<br />

*/<br />

// System.out.pr<strong>in</strong>tln("Umfang: " + o.umfang());<br />

/* o ist e<strong>in</strong> Object. Object enthaelt oder erbt ke<strong>in</strong>e<br />

Def<strong>in</strong>ition von umfang(), daher akzeptiert der <strong>Java</strong>-<br />

Compiler (zur Uebersetzungszeit) o.umfang() nicht.<br />

*/<br />

// System.out.pr<strong>in</strong>tln("Umfang: " + (Rechteck) o.umfang());<br />

/* (Rechteck) o.umfang() akzeptiert der <strong>Java</strong>-Compiler<br />

(zur Uebesersetzungszeit) aus dem gleichen Grund wie<br />

zuvor nicht.<br />

Die Schreibweise (Rechteck) o.umfang() bedeutet auch:<br />

Der Rueckgabewert von o.umfang() soll als Rechteck-<br />

Referenz <strong>in</strong>terpretiert werden.<br />

*/<br />

System.out.pr<strong>in</strong>tln("Umfang: " + ((Rechteck) o).umfang());<br />

/* o ist e<strong>in</strong> Object, (Rechteck o) bedeutet: o soll als<br />

Rechteck <strong>in</strong>terprtiert werden. Fuer Rechteck-Objekte<br />

ist umfang() erkaert, der <strong>Java</strong>-Compiler akzeptiert<br />

(zur Uebersetzungszeit) ((Rechteck o).umfang().<br />

Zur Laufzeit wird die <strong>in</strong> Recteck def<strong>in</strong>ierte<br />

(allgeme<strong>in</strong>er: die <strong>in</strong> Recheck def<strong>in</strong>ierte bzw. ererbte)<br />

Methode umfang() ausgefuehrt.<br />

*/<br />

}<br />

}<br />

B<strong>in</strong>den<br />

Das Schema e<strong>in</strong>er Botschaft wird aus "Empfänger Methode Argument" gebildet.<br />

Darüber soll e<strong>in</strong>e Nachricht die physikalische Adresse e<strong>in</strong>es Objekts im Speicher<br />

f<strong>in</strong>den. Trotz Polymorphismus und Vererbung ist der Methodenname (oft. Selektor<br />

genannt) nur e<strong>in</strong>e Verknüpfung zum Programmcode e<strong>in</strong>er Methode. Vor der<br />

Ausführung e<strong>in</strong>er Methode muß daher e<strong>in</strong>e genaue Zuordnung zwischen dem<br />

Selektor und der physikalischen Adresse des tatsächlichen Programmcodes erfolgen<br />

(B<strong>in</strong>den oder L<strong>in</strong>ken).<br />

In der objektorientierten Programmierung unterscheidet man: frühes und spätes<br />

B<strong>in</strong>den:<br />

Frühes B<strong>in</strong>den: E<strong>in</strong> Compiler ordnet schon zum Zeitpunkt der Übersetzung des Programms die<br />

tatsächliche, physikalische Adresse der Methode dem Methodenaufruf zu.<br />

Spätes B<strong>in</strong>den: Hier wir erst zur Laufzeit des Programms die tatsächliche Verknüpfung zwischen Selektor und<br />

Code hergestellt. Die richtige Verbidung übernimmt das Laufzeitprogramm der Programmiersprache.<br />

<strong>Java</strong> unterstützt das Konzept des „Late B<strong>in</strong>d<strong>in</strong>g“.<br />

68


1.4.2 Klassen des Pakets java.lang<br />

1.4.2.1 Die Klasse Object<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Object-Klasse ist die Basisklasse für jede andere Klasse <strong>in</strong> <strong>Java</strong>. Sie def<strong>in</strong>iert<br />

Methoden, die von allen Klassen <strong>in</strong> <strong>Java</strong> unterstützt werden.<br />

Test auf Gleichheit von Objekten: public boolean equals(Object ob)<br />

Darüber kann ermittelt werden, ob zwei Objekte gleich s<strong>in</strong>d.<br />

Zeichenkettendarstellung von Objekten: public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

Darüber kann e<strong>in</strong> Objekt an e<strong>in</strong>en Ausgabestrom übergeben werden.<br />

Klonen von Objekten: protected Object clone() throws<br />

CloneNotSupportedException, OutOfMemoryError erzeugt e<strong>in</strong> exaktes<br />

Duplikat e<strong>in</strong>es Objekts. E<strong>in</strong> Objekt kann nur geklont werden, falls es die Cloneable-<br />

Schnittstelle unterstützt.<br />

1.4.2.2 Die Class-Klasse<br />

Sie enthält Informationen, die e<strong>in</strong>e <strong>Java</strong>-Klasse beschreiben. In <strong>Java</strong> hat jede Klasse<br />

e<strong>in</strong>e entsprechende Instanz von Class.<br />

Konstruktor. Es gibt ke<strong>in</strong>en öffentlichen Konstruktor für das Class-Objekt.<br />

Class-Instanzen. E<strong>in</strong>e Class-Instanz kann auf drei unterschiedliche Arten erhalten<br />

werden:<br />

- public f<strong>in</strong>al native Class getClass() ermittelt die Class-Instanz für e<strong>in</strong> Objekt.<br />

Bsp.: void ausgabeClassName(Object obj)<br />

{<br />

System.out.pr<strong>in</strong>tln(“Die Klasse von “ + obj + “: “<br />

+ obj.getClass.getName());<br />

}<br />

- public static Class forName(Str<strong>in</strong>g className) throws<br />

ClassNotFoundException gibt die Instanz von Class wieder, die zu className gehört.<br />

- Laden e<strong>in</strong>er neuen Klasse durch Verwendung e<strong>in</strong>es eigenen ClassLoader-Objekts<br />

Informationen über e<strong>in</strong>e Klasse können bezogen werden über<br />

public Str<strong>in</strong>g getName() gibt den Namen der Klasse zurück.<br />

public boolean isInterface() gibt true aus, falls es sich um e<strong>in</strong>e Schnittstelle handelt.<br />

public Class getSuperClass() gibt die Superklasse der Klasse an.<br />

public Class[] getInterfaces() gibt e<strong>in</strong> Datenfeld aus, das Class-Instanzen für jede<br />

Schnittstelle enthält, die diese Klasse unterstützt.<br />

public ClassLoader getClassLoader() gibt die Instanz von ClassLoader an, die dafür<br />

verantwortlich ist, daß diese Klasse <strong>in</strong> die Laufzeit-Umgebung geladen wird.<br />

69


1.4.2.3 Die Klasse System<br />

System-Properties<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Properties s<strong>in</strong>d Listen von Eigenschaften, die Programmen vom <strong>Java</strong>-Laufzeitsystem<br />

zur Verfügung gestellt werden. Jede Eigenschaft besitzt e<strong>in</strong>en Name, unter dem auf<br />

sie zugegriffen werden kann.<br />

Property Bedeutung<br />

java.version <strong>Java</strong>-Versionsnummer<br />

java.vendor Herstellerspez. Zeichenkette<br />

java.vendor.url URL (Internet-L<strong>in</strong>k)<br />

java.home Installationsverzeichnis<br />

java.class.version Versionsnummer der <strong>Java</strong>-Klassenbibliothek<br />

java.class.path Aktueller Klassenpfad<br />

os.name Name des Betriebssystems<br />

os.arch Betriebssystem-Architektur<br />

os.version Versionsnummer des Betriebssystems<br />

file.seperator Trennzeichen für die Bestandteile des Pfadnamens<br />

path.seperator Trennzeichen für die Laufwerksangabe e<strong>in</strong>es Pfadnamens<br />

l<strong>in</strong>e.seperator Zeichenkette für Zeilenumschaltung<br />

user.name Name des angemeldeten Benutzers<br />

user.home Home-Verzeichnis<br />

user.dir Aktuelles Arbeitsverzeichnis<br />

Für den Zugriff auf diese Eigenschaften steht die Klasse Properties aus dem<br />

Paket java.util zur Verfügung. Sie erzeugt Property-Listen. Die Klasse<br />

Properties ist e<strong>in</strong>e Ableitung der Klasse HashTable und stellt darüber e<strong>in</strong>e<br />

Tabelle mit Schlüssel/Wertepaaren zur Verfügung.<br />

Für den Zugriff auf e<strong>in</strong>zelne Properties reicht meistens die Klassenmethode der<br />

Klasse System aus:<br />

public static Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key)<br />

liefert die Eigenschaft zu dem key <strong>in</strong> Form e<strong>in</strong>er Zeichenkette. Falls ke<strong>in</strong>e Eigenschaft unter diesem<br />

Namen (key) gefunden wird, wird „null“ zurückgegeben.<br />

70


Die Methode<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public static Properties getProperties();<br />

liefert das komplette Properties-Objekt mit den System-Properties.<br />

Bsp. 69 : Ausgabe e<strong>in</strong>er Liste aller System-Properties auf dem Bildschirm<br />

import java.lang.*;<br />

import java.util.*;<br />

class EigenschaftsTest extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g argv[])<br />

{<br />

System.out.pr<strong>in</strong>tln(new Date());<br />

// System-Eigenschaften<br />

Properties p = System.getProperties();<br />

p.list(System.out);<br />

System.out.pr<strong>in</strong>tln("Speicher-Verwendung:");<br />

Runtime rt = Runtime.getRuntime();<br />

System.out.pr<strong>in</strong>tln("Totaler Speicher = " + rt.totalMemory() +<br />

" Freier Speicher = " + rt.freeMemory());<br />

}<br />

}<br />

<strong>in</strong>, err und out<br />

out ist e<strong>in</strong>e statische Variable vom Typ Pr<strong>in</strong>tStream, die beim Starten des<br />

System so <strong>in</strong>itialisiert wird, daß ihre Ausgabe auf die Standardausgabe geleitet wird.<br />

Analog zu out gibt es err und <strong>in</strong>.<br />

public static void exit(<strong>in</strong>t status)<br />

Mit System.exit wird das laufende Programm beendet. „status“ dient als<br />

Fehleranzeige und wird als Exitcode an den Aufrufer des Programms<br />

zurückgegeben. Gemäß Konvention zeigt dabei e<strong>in</strong> Wert größer oder gleich 1 e<strong>in</strong>en<br />

Fehler während der Programmausführung an, 0 signalisiert e<strong>in</strong> fehlerfreies<br />

Programmende.<br />

public static void gc()<br />

führt e<strong>in</strong>en expliziten Aufruf des Garbage Collector durch. Dieser sucht nach<br />

freiem Speicher und gibt ihn dann an das Laufzeitsystem zurück. Normalerweise ist<br />

e<strong>in</strong> aufruf dieser Methode nicht erforderlich, denn der Garbage Collector läuft als<br />

niedrig priorisierter Thread im H<strong>in</strong>tergrund.<br />

public static long currentTimeMillis()<br />

liefert die Anzahl der Millisekunden, die zum Zeitpunkt des Aufrufs seit Mitternacht<br />

des 1.1.1970 vergangen s<strong>in</strong>d.<br />

69 PR14231<br />

71


1.4.2.4 Die Klasse Thread<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Threads werden <strong>in</strong> <strong>Java</strong> durch die Klasse Thread und das Interface Runnable<br />

implementiert. In beiden Fällen wird der Thread-Körper (, also der parallel<br />

auszuführende Code) <strong>in</strong> Form der zu überlagernden Methode run bereitgestellt. Die<br />

Kommunikation kann durch Zugriff auf die Instanz- oder Klassenvariablen oder durch<br />

Aufruf beliebiger Methoden, die <strong>in</strong>nerhalb von run sichtbar s<strong>in</strong>d, erfolgen. E<strong>in</strong><br />

Thread stellt e<strong>in</strong>en e<strong>in</strong>zigen Ablauf von Ausführungen <strong>in</strong> e<strong>in</strong>em <strong>Java</strong>-Programm dar.<br />

Die Klasse Thread ist Bestandteil des Pakets java.lang und steht damit allen<br />

Anwendungen zur Verfügung. Über die Klasse Thread hat <strong>Java</strong> das<br />

(Betriebssystem-) Konzept der Nebenläufigkeit implementiert. Mit Nebenläufigkeit<br />

bezeichnet man die Fähigkeit e<strong>in</strong>es Systems zwei oder mehr Vorgänge gleichzeitig<br />

oder quasi gleichzeitig ausführen zu lassen. E<strong>in</strong> Thread ist e<strong>in</strong> eigenständiges<br />

Programmfragment, das parallel zu e<strong>in</strong>em anderen Thread laufen kann.<br />

Methoden der Klasse Thread<br />

Zum Erzeugen e<strong>in</strong>es Thread muß e<strong>in</strong>e eigene Klasse aus der Klasse Thread<br />

abgeleitet, und die Methode run überlagert werden. Mit Hilfe des Aufrufs der<br />

Methode start wird der Thread gestartet, die weitere Ausführung wird an die<br />

Methode run übertragen. start wird nach dem Start beendet, der Aufrufer kann<br />

parallel zum neu erzeugten Thread fortfahren.<br />

Bsp.: E<strong>in</strong>facher Thread, der <strong>in</strong> e<strong>in</strong>er Endlosschleife e<strong>in</strong>en Thread hochzählt.<br />

class Me<strong>in</strong>Thread extends Thread<br />

{<br />

public void run()<br />

{<br />

<strong>in</strong>t i = 0;<br />

while (true)<br />

{<br />

// Endlosschleife, Abbruch durch Druecken von Strg+C<br />

System.out.pr<strong>in</strong>tln(i++);<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Erzeugen e<strong>in</strong>er Instanz<br />

Me<strong>in</strong>Thread t = new Me<strong>in</strong>Thread();<br />

// Start vom erzeugten Thread<br />

t.start();<br />

// Impliziter Aufruf der Methode run()<br />

}<br />

}<br />

Der (quasi) parallel auszuführende Code wird durch die überlagerte Methode run<br />

bereitgestellt. Die Kommunikation kann durch Zugriff auf Instanz- und<br />

Klassenvariablen oder durch Aufruf beliebiger Methoden erfolgen, die <strong>in</strong>nerhalb von<br />

run sichtbar s<strong>in</strong>d.<br />

E<strong>in</strong>e <strong>Java</strong>-Applikation wird immer dann beendet, wenn der letzte Thread beendet<br />

wurde(, der ke<strong>in</strong> H<strong>in</strong>tergrund-Thread (Dämon) ist). Da e<strong>in</strong> e<strong>in</strong>faches Programm nur<br />

72


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

e<strong>in</strong>en e<strong>in</strong>zigen Vordergrund-Thread besitzt, (nämlich den, <strong>in</strong> dem ma<strong>in</strong>() läuft 70 ,)<br />

wird es beendet, wenn ma<strong>in</strong>() beendet wird. Das Beispielprogramm erzeugt e<strong>in</strong>en<br />

zusätzlichen Vordergrund-Thread und kann erst dann beendet werden, wenn dieser<br />

Thread beendet wurde.<br />

Weitere Methoden<br />

public static void sleep(long millis)<br />

sorgt dafüt, daß der aktuelle Prozeß für die (<strong>in</strong> Millisekunden) angegebene Zeit<br />

unterbrochen wird.<br />

public static void sleep(long millis, <strong>in</strong>t nanos)<br />

Die erzielbare Genauigkeit der Unterbrechungs-Wartezeit wird durch Hardware-<br />

Restriktionen der Masch<strong>in</strong>e begrent<br />

public f<strong>in</strong>al boolean isAlive()<br />

gibt true zurück, wenn der aktuelle Thread gestartet, aber noch nicht beendet<br />

wurde. Beendet wird e<strong>in</strong> Thread, wenn das Ende der run-Methode erreicht ist, oder<br />

wenn die Methode stop aufgerufen wurde.<br />

Bsp.: Beenden des Thread nach 2 Sekunden durch Aufruf von stop<br />

class Me<strong>in</strong>Thread1 extends Thread<br />

{<br />

public void run()<br />

{<br />

<strong>in</strong>t i = 0;<br />

while (true)<br />

{<br />

// Endlosschleife, Abbruch durch Druecken von Strg+C<br />

System.out.pr<strong>in</strong>tln(i++);<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// Erzeugen e<strong>in</strong>er Instanz<br />

Me<strong>in</strong>Thread1 t = new Me<strong>in</strong>Thread1();<br />

// Start vom erzeugten Thread<br />

t.start();<br />

// Impliziter Aufruf der Methode run()<br />

try {<br />

Thread.sleep(2000);<br />

}<br />

catch(InterruptedException e)<br />

{ }<br />

t.stop();<br />

}<br />

}<br />

public f<strong>in</strong>al void jo<strong>in</strong>() throws InterruptedException<br />

Unterbrechen e<strong>in</strong>es Thread: Mit Hilfe der Methoden suspend bzw. resume ist es<br />

möglich e<strong>in</strong>en Thread vorübergehend zu unterbrechen bzw. fortzusetzen. Durch<br />

suspend wird die Ausführung unterbrochen, durch resume wird der Thread<br />

(genauer: die Methode run) an der Stelle fortgesetzt, an der die Unterbrechung<br />

erfolgte.<br />

70 Beim Starten e<strong>in</strong>es <strong>Java</strong>-Programms wird automatisch e<strong>in</strong> Thread für die Ausführung des Hauptprogramms<br />

angelegt.<br />

73


Das Interface Runnable<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Nicht immer ist es möglich, e<strong>in</strong>e Klasse, die als Thread laufen soll, von Thread<br />

abzuleiten. E<strong>in</strong> Thread kann deshalb auch über Implementierung des Interface<br />

Runnable erzeugt werden. Runnable enthält nur e<strong>in</strong>e e<strong>in</strong>zige Deklaration nämlich<br />

die der Methode run:<br />

public <strong>in</strong>terface Runnable<br />

{<br />

public abstract void run();<br />

}<br />

Implementierung von Runnable: Jede Klasse, deren Instanzen als Thread laufen,<br />

muß das Interface Runnable implementieren71 . E<strong>in</strong>e nicht von Thread abgeleitete<br />

Instanz kann nach folgenden Implementierungsschritten als Thread laufen:<br />

- Erzeugen e<strong>in</strong>es neuen Thread-Objekts<br />

- Übergabe des Objekts, das parallel ausgeführt werden soll, an den Konstruktor<br />

- Aufruf der Methode start des Thread-Objekts<br />

Über start() startet das Thread-Objekt die run-Metode des übergebenen Objekts<br />

(, das sie durch die Übergabe an den Konstruktor kennt). Da dieses Objekt das<br />

Interface Runnable implementiert, ist garantiert, daß e<strong>in</strong>e geeignete Methode run<br />

zur Verfügung steht.<br />

Synchronisation nebenläufiger Prozesse<br />

Zur Synchronisation nebenläufiger Prozesse hat <strong>Java</strong> das Konzept des Monitors<br />

implementiert. E<strong>in</strong> Monitor ist die Kapselung e<strong>in</strong>es kritischen Bereichs (also e<strong>in</strong>es<br />

Programmteils, der nur von jeweils e<strong>in</strong>em Prozeß zur aktuellen Zeit durchlaufen<br />

werden darf) mit Hilfe e<strong>in</strong>er automatisch gesetzten Sperre. Die Sperre wird beim<br />

E<strong>in</strong>tritt <strong>in</strong> den Monitor gesetzt und beim Verlassen wieder zurückgenommen. Ist sie<br />

beim E<strong>in</strong>tritt <strong>in</strong> den Monitor bereits von e<strong>in</strong>em anderen Prozeß gesetzt, dann muß<br />

der aktuelle Prozeß warten, bis der Konkurent die Sperre freigegeben und den<br />

Monitor verlassen hat.<br />

Das Monitor-Konzept wird mit Hilfe des Schlüsselworts synchronized realisiert.<br />

Durch synchronized kann entweder e<strong>in</strong>e komplette Methode oder e<strong>in</strong> Block<br />

<strong>in</strong>nerhalb e<strong>in</strong>er Methode geschützt werden. Der E<strong>in</strong>tritt <strong>in</strong> den so deklarierten Monitor<br />

wird als Sperre der this-Po<strong>in</strong>ter verwendet, anderenfalls ist die Objektvariable<br />

explizit anzugeben.<br />

Neben dem Monitorkonzept stehen mit den Methoden wait() und notify() der<br />

Klasse Object noch weitere Synchronisationsprimitive zur Verfügung. Zusätzlich zu<br />

der bereits erwähnten Sperre, die e<strong>in</strong>em Objekt zugeordnet ist, besitzt e<strong>in</strong> Objekt<br />

e<strong>in</strong>e Warteliste. Dabei handelt es sich um e<strong>in</strong>e (möglicherweise leere) Menge von<br />

Threads, die von e<strong>in</strong>em Scheduler unterbrochen wurden und auf Ereignisse warten,<br />

um fortgesetzt werden zu können.<br />

„wait()“ und „notify()“ dürfen nur aufgerufen werden, wenn das Objekt bereits<br />

gesperrt ist, also nur <strong>in</strong>nerhalb e<strong>in</strong>es „synchronized“-Blocks. E<strong>in</strong> Aufruf von<br />

wait() nimmt die bereits gewährten Sperren (temporär) zurück und stellt dem<br />

Prozeß, der den Aufruf von wait() verursachte, <strong>in</strong> die Warteliste des Objekts.<br />

Dadurch wird er unterbrochen. E<strong>in</strong> Aufruf von notify() entfernt e<strong>in</strong>en (beliebigen)<br />

71 sogar die Klasse Thread selbst<br />

74


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Prozeß aus der Warteliste des Objekts, stellt die (temporär) aufgehobenen Sperren<br />

wieder her und führt ihn dem normalen Schedul<strong>in</strong>g zu. „wait()“ und „notify()“<br />

s<strong>in</strong>d damit für elementare Synchronisationsaufgaben geeignet, bei denen es weniger<br />

auf die Kommunikation als auf die Steuerung zeitlicher Abläufe ankommt<br />

75


1.4.2.5 Die Klassen Str<strong>in</strong>g und Str<strong>in</strong>gBuffer<br />

Die Klasse Str<strong>in</strong>g<br />

Konstruktoren:<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Str<strong>in</strong>g() Erzeugt e<strong>in</strong> leeres Str<strong>in</strong>g-Objekt<br />

Str<strong>in</strong>g(Str<strong>in</strong>g wert) Erzeugt e<strong>in</strong>en neuen Str<strong>in</strong>g durch Duplizierung e<strong>in</strong>es bereits<br />

vorhandenen.<br />

Str<strong>in</strong>g(char[] wert) Erzeugt e<strong>in</strong>en neuen Str<strong>in</strong>g aus e<strong>in</strong>em vorhandenen Zeichen-<br />

Array.<br />

Zeichenextraktion<br />

char charAt(<strong>in</strong>t <strong>in</strong>dex) throws<br />

Str<strong>in</strong>gIndexOutOfBoundsException<br />

Str<strong>in</strong>g substr<strong>in</strong>g(<strong>in</strong>t<br />

anfang, <strong>in</strong>t ende)<br />

Liefert das Zeichen an Position <strong>in</strong>dex. Dabei hat das erste<br />

Element e<strong>in</strong>es Str<strong>in</strong>g den wert 0 und das letzte den Index<br />

„length()-1“. Falls der Str<strong>in</strong>g kürzer als „<strong>in</strong>dex + 1“ ist, wird e<strong>in</strong>e<br />

Ausnahme des Typs „Str<strong>in</strong>gIndexOutOfBoundsException“<br />

erzeugt<br />

Liefert den Teilstr<strong>in</strong>g, der an Position anfang beg<strong>in</strong>nt und an<br />

Position ende endet. Wie bei allen Zugriffen über e<strong>in</strong>en<br />

numerischen Index beg<strong>in</strong>nt hier das Zählen bei 0. „ende“<br />

verweist auf das erste Zeichen h<strong>in</strong>ter dem zu extrahierenden<br />

Teilstr<strong>in</strong>g. Der Rückgabewert ist also die Zeichenkette, die von<br />

Indexposition anfang bis zur Indexpostion „ende –1“ reicht<br />

Str<strong>in</strong>g trim() Liefert den Str<strong>in</strong>g, der entsteht, wenn auf beiden Seiten der<br />

Zeichenkette jeweils alle zusammenhängenden Leerzeichen<br />

entfernt werden. Dabei werden alle Zeichen, die e<strong>in</strong>en Code<br />

kle<strong>in</strong>er 32 haben, als Leerzeichen angesehen. „trim“ entfernt<br />

immer Leerzeichen auf beiden Seiten. Da die Klasse Str<strong>in</strong>g als<br />

f<strong>in</strong>al def<strong>in</strong>iert wurde, gibt es ke<strong>in</strong>e Möglichkeit, entsprechende<br />

Methoden nachzurüsten, z.B. für das rechtsbündige oder<br />

l<strong>in</strong>ksbündige Entfernen von Leerzeichen.<br />

Länge der Zeichenkette: <strong>in</strong>t length() liefert die aktuelle Länge des Str<strong>in</strong>g-<br />

Objekts. Ist der Rückgabewert 0, dann ist der Str<strong>in</strong>g leer. Wird e<strong>in</strong> wert „n“ größer 0<br />

zurückgegeben, dann enthält der Str<strong>in</strong>g „n“ Zeichen, die an den Indexpositionen 0<br />

bis „n-1“ liegen.<br />

Vergleichen von Zeichenketten:<br />

boolean equals(Object<br />

e<strong>in</strong>Objekt)<br />

boolean<br />

startsWith(Str<strong>in</strong>g s)<br />

Liefert true, wenn das aktuelle Objekt und e<strong>in</strong>Objekt<br />

identisch s<strong>in</strong>d. „equals“ testet auf <strong>in</strong>haltlliche Gleichheit und<br />

nicht darauf, ob beide Str<strong>in</strong>gs dasselbe Objekt referenzieren.<br />

Neben „equals“ gibt es die Methode equalsIgnoreCase, die<br />

evtl. vorhandene Unterschiede <strong>in</strong> der Groß- und<br />

Kle<strong>in</strong>schreibung beider Zeichenketten ignoriert.<br />

Testet, ob das Str<strong>in</strong>g-Objekt mit der Zeichenkette s beg<strong>in</strong>nt.<br />

Ist dies der Fall, dann gibt die Methode „true“ zurück,<br />

anderenfalls „false“.<br />

boolean endsWith(Str<strong>in</strong>g<br />

s)<br />

<strong>in</strong>t compareTo(Str<strong>in</strong>g s) Führt e<strong>in</strong>en lexikalischen Vergleich der beiden Str<strong>in</strong>gs durch.<br />

Bei e<strong>in</strong>em lexikalischen Vergleich werden die Zeichen<br />

paarweise von l<strong>in</strong>ks nach rechts verglichen. Tritt e<strong>in</strong><br />

Unterschied auf oder ist e<strong>in</strong>er der beiden Str<strong>in</strong>gs beendet, wird<br />

das Ergebnis ermittelt. Ist das aktuelle Str<strong>in</strong>g-Objekt kle<strong>in</strong>er<br />

als s, wird e<strong>in</strong> negativer Wert zurückgegeben. Ist er größer,<br />

wird e<strong>in</strong> positiver Wert zurückgegeben. Bei Gleichheit liefert<br />

76


<strong>in</strong>t regionMatches(<strong>in</strong>t<br />

toffset, Str<strong>in</strong>g other,<br />

<strong>in</strong>t ooffset, <strong>in</strong>t len)<br />

Suchen <strong>in</strong> Zeichenketten<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

die Methode den Rückgabewert 0.<br />

<strong>in</strong>t <strong>in</strong>dexOf(Str<strong>in</strong>g s) Sucht das erste Vorkommen der Zeichenkette s<br />

<strong>in</strong>nerhalb des Str<strong>in</strong>g-Objekts. Wird s gefunden, liefert<br />

die Methode den Index des ersten übere<strong>in</strong>stimmenden<br />

Zeichens zurück, andernfalls wird –1 zurückgegeben.<br />

Die Methode gibt es auch <strong>in</strong> e<strong>in</strong>er anderen Version,<br />

die e<strong>in</strong>en Parameter vom Typ char akzeptiert. In<br />

diesem Fall sucht sie nach dem Auftreten des ersten<br />

<strong>in</strong>t IndexOf(Str<strong>in</strong>g s, <strong>in</strong>t<br />

vonIndex)<br />

angegebenen Zeichens.<br />

Diese Methode arbeitet wie die vorige, beg<strong>in</strong>nt mit der<br />

Suche aber erst ab Position vonIndex. Wird s<br />

beg<strong>in</strong>nend ab dieser Position gefunden, liefert die<br />

Methode den Index des ersten übere<strong>in</strong>stimmenden<br />

Zeichens, andernfalls –1.<br />

E<strong>in</strong>e Variante dieser Methode erwartet anstelle e<strong>in</strong>es<br />

Str<strong>in</strong>g-Parameters e<strong>in</strong> Argument vom Typ char.<br />

<strong>in</strong>t lastIndexOf(Str<strong>in</strong>g s) Sucht nach dem letzten Vorkommen des Teilstr<strong>in</strong>gs s<br />

im aktuellen Str<strong>in</strong>g-Objekt- Wird „s“ gefunden, liefert<br />

die Methode den Index des ersten übere<strong>in</strong>stimmenden<br />

Zeichens, andernfalls –1. E<strong>in</strong>e Variante dieser<br />

Methode erwartet e<strong>in</strong> Argument des Typs char.<br />

Ersetzen von Zeichenketten<br />

Str<strong>in</strong>g toLowerCase() Liefert den Str<strong>in</strong>g zurück, der entsteht, wenn alle Zeichen <strong>in</strong><br />

Kle<strong>in</strong>buchstaben umgewandelt werden. Besitzt der Str<strong>in</strong>g ke<strong>in</strong>e<br />

umwandelbaren Zeichen, dann wird der Orig<strong>in</strong>al-str<strong>in</strong>g<br />

zurückgegeben.<br />

Str<strong>in</strong>g toUpperCase() Liefert den Str<strong>in</strong>g zurück, der entsteht, wenn alle Zeichen <strong>in</strong><br />

Großbuchstaben umgewandelt werden. Besitzt der Str<strong>in</strong>g ke<strong>in</strong>e<br />

Str<strong>in</strong>g replace(char<br />

altesZeichen, char<br />

neuesZeichen)<br />

Konvertierungsfunktionen:<br />

static Str<strong>in</strong>g valueOf(boolean b)<br />

static Str<strong>in</strong>g valueOf(char z)<br />

static Str<strong>in</strong>g valueOf(<strong>in</strong>t i)<br />

static Str<strong>in</strong>g valueOf(long l)<br />

static Str<strong>in</strong>g valueOf(float f)<br />

static Str<strong>in</strong>g valueOf(double d)<br />

umwandelbaren Zeichen, wird der Orig<strong>in</strong>al-Str<strong>in</strong>g zurückgegeben.<br />

Diese Methode führt e<strong>in</strong>e zeichenweise Konvertierung des<br />

aktuellen Str<strong>in</strong>g-Objekts durch. Jedes Auftreten von<br />

altesZeichen wird durch neuesZeichen ersetzt. Es gibt <strong>in</strong><br />

<strong>Java</strong> ke<strong>in</strong>e Methode, die das Ersetzen von Teilstr<strong>in</strong>gs durch andere<br />

Teilstr<strong>in</strong>gs (von möglicherweise unterschiedlicher Länge)<br />

ermöglicht. „replace“ ist das e<strong>in</strong>zige Mittel für Ersetzungen.<br />

Die „valueOf“-Methoden s<strong>in</strong>d als Klassenmethoden implementiert und können<br />

ohne Str<strong>in</strong>g-Objekt aufgerufen werden. Da sie <strong>in</strong> der Regel zur Erzeugung von<br />

Str<strong>in</strong>gs verwendet werden, ist das s<strong>in</strong>nvoll. E<strong>in</strong> Aufruf von „valueOf“ wandelt e<strong>in</strong><br />

primitives Objekt mit Hilfe der Methode „toStr<strong>in</strong>g()“, die von der zugehörigen<br />

Wrapper-Klassen bereitgestellt wird, <strong>in</strong> e<strong>in</strong>e Zeichenkette um.<br />

77


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Weitere Eigenschaften: Die Klasse Str<strong>in</strong>g ist f<strong>in</strong>al. Von e<strong>in</strong>er Str<strong>in</strong>g-Klasse können<br />

ke<strong>in</strong>e neuen Klassen abgeleitet werden.<br />

Str<strong>in</strong>g-Objekte s<strong>in</strong>d nicht dynamisch. Es werden durch die Klasse Str<strong>in</strong>g ke<strong>in</strong>e<br />

dynamischen Zeichenketten implementiert. Nach der Initialisierung e<strong>in</strong>es Str<strong>in</strong>g<br />

bleibt dessen Länge konstant, z.B.:<br />

Str<strong>in</strong>g s = “Hallo Welt“;<br />

s = substr<strong>in</strong>g(0,5);<br />

Die „Substr<strong>in</strong>g“-Methode erzeugt e<strong>in</strong>e Kopie, die mit dem gewünschten Inhalt gefüllt<br />

wird. Diese gibt sie an den Aufrufer zurück, der das Ergebnis erneut s zuweist und<br />

damit die Orig<strong>in</strong>al<strong>in</strong>stanz für den Garbage Collector freigibt.<br />

Bsp.: Anwendung von Methoden der Str<strong>in</strong>g-Klasse<br />

public class PruefeStr<strong>in</strong>g<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Str<strong>in</strong>g str = "<strong>Java</strong> ist die beste Programmiersprache, " +<br />

"die Studenten der Informatik erlernen sollten.";<br />

System.out.pr<strong>in</strong>tln("Der Str<strong>in</strong>g ist: " + str);<br />

System.out.pr<strong>in</strong>tln("Laenge des Str<strong>in</strong>g: " + str.length());<br />

System.out.pr<strong>in</strong>tln("Das Zeichen an Position 7: " + str.charAt(7));<br />

System.out.pr<strong>in</strong>tln("Der Substr<strong>in</strong>g von 24 bis 31: " +<br />

str.substr<strong>in</strong>g(24,31));<br />

System.out.pr<strong>in</strong>tln("Der Index zum Zeichen I: " + str.<strong>in</strong>dexOf(’I’));<br />

System.out.pr<strong>in</strong>tln("Der Index zum Anfang von "<br />

+ "Substr<strong>in</strong>g \"beste\": " + str.<strong>in</strong>dexOf("beste"));<br />

System.out.pr<strong>in</strong>tln("Der Str<strong>in</strong>g <strong>in</strong> Großbuchstaben: " + str.toUpperCase());<br />

}<br />

}<br />

Die Klasse Str<strong>in</strong>gBuffer<br />

Die Klasse Str<strong>in</strong>gBuffer dient zur Implementierung veränderlicher Zeichenketten.<br />

Konstruktoren:<br />

Str<strong>in</strong>gBuffer() Erzeugt e<strong>in</strong>en leeren Str<strong>in</strong>gBuffer<br />

Str<strong>in</strong>gtBuffer(Str<strong>in</strong>g s) Erzeugt e<strong>in</strong> neues Str<strong>in</strong>gBuffer-Objekt, das e<strong>in</strong>e Kopie der<br />

Zeichenkette s ist.<br />

E<strong>in</strong>fügen von Elementen<br />

Str<strong>in</strong>gBuffer append(Str<strong>in</strong>g s) Hängt Str<strong>in</strong>g s an das Ende des Str<strong>in</strong>gBuffer-Objekts.<br />

Zurückgegeben wird das verlängerte Str<strong>in</strong>gBuffer-<br />

Objekt. Zusätzlich gibt es die Methode append <strong>in</strong><br />

Varianten für das Anhängen aller Arten von primitiven<br />

Typen. Anstelle e<strong>in</strong>es Str<strong>in</strong>g-Objekts wird hier der<br />

entsprechende primitive Typ übergeben, <strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g<br />

konvertiert und an das Ende des Objekts angehängt.<br />

Str<strong>in</strong>gBuffer <strong>in</strong>sert(<strong>in</strong>t offset, Str<strong>in</strong>g s) Fügt den Str<strong>in</strong>g s an die Position offset <strong>in</strong> den<br />

aktuellen Str<strong>in</strong>gBuffer e<strong>in</strong>. Zurückgegeben wuird das<br />

verlängerte Str<strong>in</strong>gBuffer-Objekt. Auch diese Methode<br />

gibt es für primitive Typen. Der anstelle e<strong>in</strong>es Str<strong>in</strong>g<br />

übergebene Wert wird zunächst <strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g<br />

konvertiert und dann an die gewünschte Stelle<br />

e<strong>in</strong>gefügt.<br />

78


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Verändern von Elementen: „void setCharAt(<strong>in</strong>t <strong>in</strong>dex, char c) throws<br />

Str<strong>in</strong>gIndexOutOfBoundException“. Das an Position <strong>in</strong>dex stehende Zeichen<br />

wird durch c ersetzt. Falls Str<strong>in</strong>gBuffer zu kurz ist, löst die Methode e<strong>in</strong>e<br />

Ausnahme des Typs Str<strong>in</strong>gIndexOutOfBoundException aus.<br />

Länge e<strong>in</strong>es Str<strong>in</strong>g-Objekts: <strong>in</strong>t length() liefert die Länge des Objekts (Anzahl<br />

der Zeichen, die zum Zeitpunkt des Aufrufs <strong>in</strong> dem Str<strong>in</strong>gBuffer enthalten s<strong>in</strong>d).<br />

Konvertieren <strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g: Str<strong>in</strong>g toStr<strong>in</strong>g(). Nachdem die Konstruktion<br />

e<strong>in</strong>es Str<strong>in</strong>gBuffer-Objekts abgeschlossen ist, kann es mit Hilfe dieser Methode<br />

<strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g verwandelt werden. Die Methode legt dabei ke<strong>in</strong>e Kopie des<br />

Str<strong>in</strong>gBuffer-Objekts an, sondern liefert e<strong>in</strong>en Zeiger auf den <strong>in</strong>ternen Zeichenpuffer.<br />

Erst wenn der Str<strong>in</strong>gBuffer erneut verändert werden soll, wird tatsächlich e<strong>in</strong>e Kopie<br />

erzeugt.<br />

1.4.2.6 Die Math-Klasse<br />

Die Math-Klasse enthält nützliche numerische Konstanten und Funktionen:<br />

1. Die Funktionen „m<strong>in</strong>“ und „max“.<br />

2. Der absolute Betrag<br />

3. Zufallszahlen<br />

Die Klasse Math unterstützt die „random“-Methode: public static synchronized double<br />

random(). Die „random“-Methode gibt e<strong>in</strong>e Zahl zwischen 0.0 und 1.0 aus.<br />

4. Runden<br />

Runden e<strong>in</strong>er Zahl vom Typ float: public static <strong>in</strong>t round(float a). Gerundet wird auf<br />

die nächste ganze Zahl (z.B. 5.4 auf 5, 5.5. auf 6)<br />

Runden e<strong>in</strong>er Zahl vom Typ double: public static long round(double a)<br />

Abrunden: public static double floor(double a). Math.floor rundet immer ab, z.B.<br />

ergibt Math.floor(4.99) die Zahl 4.0.<br />

Aufrunden: public static double ceil(double a). ceil runder immer auf, z.B.:<br />

Math.ceil(4.01) ergibt 5.0.<br />

Runden auf die nächste ganze Zahl: public static double r<strong>in</strong>t(double a).<br />

5. Exponenten und Logarithmen<br />

6. Trigonometrische Funktionen<br />

public static double s<strong>in</strong>(double w<strong>in</strong>kel)<br />

public static double cos(double w<strong>in</strong>kel)<br />

Der Wert von w<strong>in</strong>kel wird im Bogenmaß angegeben.<br />

7. Mathematische Konstanten<br />

public double f<strong>in</strong>al double E;<br />

public static f<strong>in</strong>al double PI;<br />

79


1.4.2.7 Object-Wrapper-Klassen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Object-Wrapper-Klassen s<strong>in</strong>d Wrapper für primitive Typen. Zusätzlich besitzen<br />

sie Methoden zur Umwandlung von Zeichenketten <strong>in</strong> die verschiedenen Datentypen.<br />

Die Klasse Character<br />

Konstruktor:<br />

Ermitteln vom „char“-Wert: public char charValue<br />

Klassifizieren von Zeichen:<br />

Methode Beschreibung<br />

isDigit E<strong>in</strong>e numerische Zahl zwischen 0 und 9<br />

isLetter E<strong>in</strong> Buchstabe des Alphabets<br />

isLetterOrDigit E<strong>in</strong> alphabetischer Buchstabe oder e<strong>in</strong>e numerische Zahl<br />

isLowerCase<br />

isUpperCase E<strong>in</strong> großgeschriebener alphabetischer Buchstabe<br />

is<strong>Java</strong>Letter E<strong>in</strong> Buchstabe, ‚$‘ oder ‚_‘<br />

is<strong>Java</strong>LetterOrDigit E<strong>in</strong> Buchstabe, e<strong>in</strong>e Zahl, $ oder _<br />

isSpace E<strong>in</strong>e Leerstelle, e<strong>in</strong>e neue Zeile, e<strong>in</strong> Return, e<strong>in</strong> Tab oder e<strong>in</strong><br />

Formularvorschub<br />

isTitleCase Spezielle zweibuchstabige groß- und kle<strong>in</strong>geschriebene Buchstaben<br />

Jede dieser Klassifikationsmerkmale gibt „true“ zurück, wenn das betreffende<br />

Zeichen zur Klassifikation gehört.<br />

Groß- und kle<strong>in</strong>geschriebene Variante e<strong>in</strong>es Buchstabens:<br />

public static char toUppercase(char zeichen)<br />

public static char toLowerCase(char zeichen)<br />

Konvertierungsmethoden zur Umwandlung von Zahlen <strong>in</strong> Zeichenketten und<br />

Zeichenketten <strong>in</strong> Zahlen:<br />

public static <strong>in</strong>t digit(char zeichen, <strong>in</strong>t radix)<br />

gibt den numerischen Wert e<strong>in</strong>es Zeichens der angegebenen Zahlendarstellung<br />

(„radix“) 72 wieder. Falls e<strong>in</strong> Zeichen ke<strong>in</strong>em Wert <strong>in</strong> der angegebenen<br />

Zahlendarstellung entspricht, wird „-1“ zurückgegeben.<br />

public static char forDigit(<strong>in</strong>t digit, <strong>in</strong>t radix)<br />

Konvertiert e<strong>in</strong>en numerischen Wert <strong>in</strong> e<strong>in</strong> Zeichen, das diesen Wert <strong>in</strong> e<strong>in</strong>er<br />

bestimmten Zahlenbasis darstellt, z.B. Character.forDigit(6,8) ergibt 6 und<br />

Character.forDigit(12,16) ergibt "c“.<br />

Die Klasse Boolean<br />

Diese Klasse ist der Objekt-Wrapper für den primitiven Typ boolean.<br />

Konstruktoren:<br />

public Boolean(boolean wert)<br />

public Boolean(Str<strong>in</strong>g str)<br />

Beschaffung e<strong>in</strong>es booleschen Werts, der <strong>in</strong> e<strong>in</strong>em Objekt abgelegt ist:<br />

public boolean booleanValue()<br />

72 z.B. 10 für dezimal, 8 für oktal, 16 für hexadezimal. Zahlenbasis kann Werte von 2 (Character.MIN_RADIX)<br />

bir 32 (Character.MAX_RADIX) umfassen.<br />

80


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Objekt-Wrapper-Varianten von true und false<br />

public f<strong>in</strong>al static Boolean FALSE;<br />

public f<strong>in</strong>al static Boolean TRUE;<br />

Die Klasse Number<br />

Die Objekt-Wrapper der Typen <strong>in</strong>t, long, float und double s<strong>in</strong>d Subklassen der<br />

abstrakten Klasse Number. Vier Methoden s<strong>in</strong>d für die Konvertierung e<strong>in</strong>er Zahl <strong>in</strong><br />

e<strong>in</strong>en bestimmten primitiven Typ zuständig:<br />

public abstract <strong>in</strong>t <strong>in</strong>tValue();<br />

public abstract long longValue();<br />

public abstract float floatValue();<br />

public abstract double doubleValue()<br />

1. Die Klasse Integer<br />

Konstruktoren:<br />

public Integer(<strong>in</strong>t wert)<br />

public Integer(Str<strong>in</strong>g s) throws NumberFormatException<br />

Die Zahlenbasis (Radix) ist 10. Falls die Zeichenkette nicht numerische Zeichen<br />

enthält, wird die Ausnahme NumberFormatException ausgeworfen.<br />

Umwandeln Zeichenkette <strong>in</strong> ganze Zahlen:<br />

public static <strong>in</strong>t parseInt(Str<strong>in</strong>g s) throws NumberFormatException<br />

public static <strong>in</strong>t parseInt(Str<strong>in</strong>g s, <strong>in</strong>t radix) throws NumberFormatException<br />

public static Integer valueOf(Str<strong>in</strong>g s) throws NumberFormatException<br />

public static Integer valueOf(Str<strong>in</strong>g s, <strong>in</strong>t radix) throws NumberFormatException<br />

Der Unterschied zwischen parseInt und valueOf liegt dar<strong>in</strong>: parseInt gibt e<strong>in</strong><br />

„<strong>in</strong>t“ zurück, valueOf e<strong>in</strong> Integer.<br />

Konvertieren e<strong>in</strong>er ganzen Zahl <strong>in</strong> e<strong>in</strong>e Zeichenkette:<br />

public static Str<strong>in</strong>g toStr<strong>in</strong>g(<strong>in</strong>t i)<br />

public static Str<strong>in</strong>g toStr<strong>in</strong>g(<strong>in</strong>t i, <strong>in</strong>t radix)<br />

Die beiden Methoden dürfen nicht mit der Instanz-Methode toStr<strong>in</strong>g verwechselt<br />

werden, die für alle Subklassen von Objekt def<strong>in</strong>iert ist.<br />

Die Konstanten Integer.M<strong>in</strong>_VALUE und Integer.MAX_VALUE:<br />

public f<strong>in</strong>al static <strong>in</strong>t MIN_VALUE<br />

public f<strong>in</strong>al static <strong>in</strong>t MAX_VALUE<br />

2. Die Klasse Long<br />

Sie ist weitgehend mit der Integer-Klasse identisch. Allerd<strong>in</strong>gs dient sie als Wrapper<br />

für long-Werte.<br />

81


3. Die Klasse Float<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Sie enthält e<strong>in</strong>en Objekt-Wrapper für den Datentyp float.<br />

Konstruktoren:<br />

public Float(float wert)<br />

public Float(double wert)<br />

public Float(Str<strong>in</strong>g s) throws NumberFormatException<br />

Konvertierung von bzw. zu Zeichenketten:<br />

public static Float valueOf(Str<strong>in</strong>g s) throws NumberFormatException<br />

public static Str<strong>in</strong>g toStr<strong>in</strong>g(float f)<br />

Überprüfen auf „Unendlich“ bzw. auf „ke<strong>in</strong>e Zahl“:<br />

public static boolean is Inf<strong>in</strong>ite(float f)<br />

public static boolean isNaN(float f) // Instanz-Variante<br />

public boolean isNaN() // Instanz-Variante<br />

Konstanten: public f<strong>in</strong>al static float MIN_VALUE<br />

public f<strong>in</strong>al static float MAX_VALUE<br />

public f<strong>in</strong>al static float NEGATIVE_INFINITY<br />

public f<strong>in</strong>al static float NaN<br />

4. Die Klasse Double<br />

Sie hat dieselbe Funktionalität wie die Float-Klasse.<br />

82


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1.4.3 Ausnahmen und Ausnahmenbehandlung<br />

Ausnahmen<br />

E<strong>in</strong>e Ausnahme (Exception) ist e<strong>in</strong>e unerwünschte Ersche<strong>in</strong>ung. E<strong>in</strong>e derartige<br />

Situation (z.B. Division durch Null) ist <strong>in</strong> e<strong>in</strong>em Programm gegebenenfalls durch e<strong>in</strong>e<br />

Fehlerbehandlungsrout<strong>in</strong>e aufzufangen.<br />

Es gibt unterschiedliche Möglichkeiten zur Fehlerbehandlung:<br />

- die <strong>in</strong>dividuelle programmierte Fehlerbehandlung, z.B.:<br />

public <strong>in</strong>t dividiere()<br />

{<br />

// ganzzahlige Division<br />

if (zweiterOperand == 0)<br />

{<br />

System.out.pr<strong>in</strong>tln("Fehler: Division durch Null");<br />

System.out.pr<strong>in</strong>tln("Divisor wird auf 1 gesetzt!");<br />

zweiterOperand = 1;<br />

}<br />

return ersterOperand / zweiterOperand;<br />

}<br />

- die von <strong>Java</strong> bereitgestellten Fehlerbehandlungen<br />

Ausnahmen s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> Objekte, die erzeugt werden, wenn e<strong>in</strong>e<br />

Ausnahmebed<strong>in</strong>gung vorliegt. Diese Objekte werden von der Methode an das<br />

aufrufende Programm zurückgegeben und müssen behandelt werden. Das<br />

Behandeln von Ausnahmen wird als Auffangen bezeichnet. Das Auffangen wird<br />

durch Plazieren von Anweisungen, die Ausnahmen erzeugen können, <strong>in</strong> e<strong>in</strong>e trycatch<br />

Block erreicht, z.B. 73 :<br />

public <strong>in</strong>t dividiere()<br />

{<br />

// ganzzahlige Division<br />

try {<br />

/* Innerhalb des try-Blocks werden diejenigen<br />

kritischen Aktionen durchgefuehrt, die<br />

Ausnahmen erzeugen koennen<br />

*/<br />

return (ersterOperand / zweiterOperand);<br />

}<br />

catch(java.lang.ArithmeticException a)<br />

{<br />

System.out.pr<strong>in</strong>tln(" Fehler: Division durch Null");<br />

System.out.pr<strong>in</strong>tln("Divisor wird auf 1 gesetzt!");<br />

zweiterOperand = 1;<br />

return (ersterOperand / zweiterOperand);<br />

}<br />

}<br />

In der catch-Klausel wird die Art der aufzufangenden Ausnahme def<strong>in</strong>iert. Dort ist<br />

e<strong>in</strong> formaler Parameter angegeben, der beim Auftreten der Ausnahme e<strong>in</strong><br />

Fehlerobjekt übernehmen soll. Fehlerobjekte s<strong>in</strong>d Instanzen der Klasse Throwable<br />

(oder e<strong>in</strong>e ihrer Unterklassen). Sie werden vom Aufrufer der Ausnahme erzeugt und<br />

als Parameter an die catch-Klausel übergeben. Das Fehlerobjekt enthält<br />

Informationen über die Art der aufgetretenen Ausnahme. Es kann dort e<strong>in</strong>e der<br />

73 PR14103<br />

83


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

zahlreichen Standardausnahmen von <strong>Java</strong> stehen oder auch selbstdef<strong>in</strong>ierte<br />

Ausnahmen. Das Ausnahme- / Fehlerobjekt besitzt e<strong>in</strong>ige nützliche Methoden, z.B.<br />

public Str<strong>in</strong>g getMessage() 74 . Diese Methode gibt Fehlermeldungen zurück.<br />

public void pr<strong>in</strong>tStackTrace(). Diese Methode druckt e<strong>in</strong>en Auszug aus<br />

dem Laufzeit-Stack.<br />

Am Ende e<strong>in</strong>es try-Blocks können beliebig viele „catch“-Klauseln stehen, so daß<br />

unterschiedliche Arten von Ausnahmen behandelt werden können.<br />

Mit Hilfe der f<strong>in</strong>ally-Klausel (letzter Bestandteil e<strong>in</strong>er try-catch-Anweisung)<br />

kann e<strong>in</strong> Programmfragment def<strong>in</strong>iert werden, das immer ausgeführt wird, wenn die<br />

zugehörige try-Klausel betreten wurde.<br />

Bsp.: Rückgabe von „Resourcen“ <strong>in</strong> der f<strong>in</strong>ally-Klausel<br />

In dem folgenden Programm stellt die f<strong>in</strong>ally-Klausel sicher, daß der Schalter<br />

tatsächlich nach dem Ende der Bearbeitung im try-catch-Block ausgeschaltet ist.<br />

class Schalter<br />

{<br />

boolean zustand = false;<br />

boolean lies() { return zustand; }<br />

void an() { zustand = true; }<br />

void aus() { zustand = false; }<br />

}<br />

public class AnAusSchalter<br />

{<br />

static Schalter schalter = new Schalter();<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

try<br />

{<br />

schalter.an();<br />

// hier kann sich Quellcode bef<strong>in</strong>den, der<br />

// Ausnahmen ausloest<br />

}<br />

catch(NullPo<strong>in</strong>terException a)<br />

{<br />

System.out.pr<strong>in</strong>tln("NullPo<strong>in</strong>terException");<br />

}<br />

catch(IllegalArgumentException a)<br />

{<br />

System.out.pr<strong>in</strong>tln("IllegalArgumentException");<br />

}<br />

f<strong>in</strong>ally<br />

{<br />

schalter.aus();<br />

}<br />

}<br />

}<br />

Globales Exception-Handl<strong>in</strong>g<br />

<strong>Java</strong> realisiert das globale Handl<strong>in</strong>g von Ausnahmen über die optionale Erweiterung<br />

e<strong>in</strong>er Methodendeklaration mit der „throws“-Klausel, z.B.:<br />

public class Me<strong>in</strong>eAusnahmenKlasse<br />

{<br />

public void e<strong>in</strong>eAusnahmenMethode() throws Me<strong>in</strong>eAusnahme<br />

{<br />

.........<br />

}<br />

}<br />

74 Sie ist <strong>in</strong> der Klasse Throwable def<strong>in</strong>iert und daher allen Exception-Objekten zugänglich.<br />

84


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Hier wird dem Compiler mitgeteilt, daß der vorliegende Code e<strong>in</strong>e Ausnahme<br />

(„Me<strong>in</strong>eAusnahme“) erzeugen könnte.<br />

Falls <strong>in</strong> der mit „throws“ gekennzeichneten Methode e<strong>in</strong>e Ausnahmesituation<br />

auftritt, dann wird die aufrufende Methode nach e<strong>in</strong>er Ausnahmebehandlung<br />

durchsucht. Enthält die aufrufende Methode e<strong>in</strong>e Ausnahmebehandlungsmethode,<br />

wird mit dieser die Ausnahme bearbeitet. Ist ke<strong>in</strong>e Rout<strong>in</strong>e vorhanden, wird deren<br />

aufrufende Methode durchsucht und so fort. Die Ausnahme wird von der<br />

Hierarchieebene, wo sie aufgetreten ist, jeweils e<strong>in</strong>e Hierarchieebene weiter nach<br />

oben gereicht. Wird die Ausnahme nirgends aufgefangen, dann bricht der <strong>Java</strong>-<br />

Interpreter normalerweise die Ausführung des Programms ab.<br />

Das Auslösen e<strong>in</strong>er Ausnahme wird im <strong>Java</strong>-Sprachgebrauch als „throw<strong>in</strong>g“<br />

bezeichnet, das Behandeln e<strong>in</strong>er Ausnahme wird „catch<strong>in</strong>g“ genannt.<br />

Das Grundpr<strong>in</strong>zip des Exception-Mechanismus:<br />

- E<strong>in</strong> Laufzeitfehler oder e<strong>in</strong>e vom Entwickler gewollte Bed<strong>in</strong>gung löst e<strong>in</strong>e Ausnahme aus.<br />

- Diese kann entweder vom Programmteil, <strong>in</strong> dem sie angelegt wurde, behandelt werden, oder sie kann<br />

weitergegeben werden.<br />

- Wird die Ausnahme weitergegeben, so hat der Empfänger erneut die Möglichkeit sie entweder zu behandeln<br />

oder selbst weiterzugeben.<br />

- Wird die Ausnahme von ke<strong>in</strong>em Programmteil behandelt, so führt sie zum Abbruch e<strong>in</strong>es Programms, und zur<br />

Ausgabe e<strong>in</strong>er Fehlermeldung.<br />

Auswertungen, die Ausnahmen auslösen, können entweder direkt <strong>in</strong> e<strong>in</strong>e try-<br />

Klausel mit optionalen catch-Anweisungen (Behandlung vor Ort) e<strong>in</strong>gefaßt oder<br />

über die throws-Klausel an den übergeordneten Programmblock weitergeleitet<br />

werden. Falls weder die „Behandlung vor Ort“ noch e<strong>in</strong>e throws-Klausel verwendet<br />

wird, liefert der Compiler bereits bei der Übersetzung e<strong>in</strong>e Fehlermeldung. E<strong>in</strong>e<br />

Ausnahme bildet die Klasse RuntimeException e<strong>in</strong>schl. ihrer Subklassen. Für sie<br />

ist weder die Fehlerbehandlung noch Weiterleitung mit der throws-Klausel<br />

notwendig.<br />

Die Fehlerklassen von <strong>Java</strong><br />

Zur Behandlung von Fehlern und Ausnahmen besitzt die Klasse Throwable zwei<br />

Subklassen: die Klassen Exception und Error. In beiden Ausnahmeklassen s<strong>in</strong>d<br />

die wichtigsten Ausnahmen und Fehler der <strong>Java</strong>-Laufzeitbibliothek bereits enthalten.<br />

Ausnahmen der Klasse Error und ihrer Klasse RuntimeError müssen nicht extra<br />

abgefangen werden. „Errors“ s<strong>in</strong>d systembed<strong>in</strong>gt, „Exceptions“ dagegen<br />

programmbed<strong>in</strong>gt und müssen behandelt werden. Es gibt fünf Typen von<br />

Ausnahmen, die <strong>in</strong> e<strong>in</strong>er throws-Klausel aufgelistet werden müssen:<br />

ClassNotFoundException<br />

IllegalAccessException<br />

InstantiationException<br />

InterruptedException<br />

NoSuchMethodException<br />

H<strong>in</strong>zu kommen verschiedene weitere Ausnahmen aus den <strong>Java</strong>-Paketen. So gibt es<br />

spezielle Fehlerklassen für die E<strong>in</strong>- und Ausgabe, die Netzwerkkommunikation oder<br />

den Zugriff auf Datenfelder. Teilweise s<strong>in</strong>d sie der Klasse „Error“ (oder ihrer<br />

Subklasse RuntimeError) zugeordnet und müssen nicht extra abgefangen und<br />

85


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

dokumentiert werden. S<strong>in</strong>d Ausnahmen der Klasse Exception zugeordnet, dann<br />

müssen sie behandelt werden (z.B. alle Ausnahmen von java.io).<br />

Die Klasse RuntimeException ist die Superklasse für die Behandlung aller<br />

Laufzeitfehler, die behandelt werden können aber nicht müssen (die Entscheidung<br />

liegt beim Programmierer).<br />

Object Throwable<br />

Abb.: Fehlerklassenhierarchie<br />

Auslösen von Ausnahmen<br />

Error AWTError<br />

86<br />

UnknownError<br />

VirtualMach<strong>in</strong>eError OutOfMemoryError<br />

L<strong>in</strong>kageError<br />

ClassNotFoundException<br />

Exception RuntimeException<br />

InternalError<br />

EOFException<br />

IOException FileNotFoundException<br />

InterruptedException<br />

UTFDataFormatException<br />

<strong>Java</strong> verfügt <strong>in</strong> se<strong>in</strong>en Standardbibliotheken über zahlreiche vorgefertigte<br />

Ausnahmen für fast alle Standardsitiuationen (z.B. Dateioperationen auf der Basis<br />

der IO-Exception). Selbstdef<strong>in</strong>ierte Ausnahmen benötigen e<strong>in</strong>e Subklasse von<br />

Exception. Das Auslösen dieser selbstdef<strong>in</strong>ierten Ausnahmen erfolgt über die throw-<br />

Anweisung: throw AusnahmeObjekt.<br />

Die Behandlung selbstausgelöseter Ausnahmen erfolgt nach den üblichen Regeln:<br />

- Suche nach e<strong>in</strong>em Ausnahmen-Handler <strong>in</strong> den umgebenden Blöcken<br />

- Bei erfolgloser Suche Weitergabe des Fehlers an den Aufrufer.<br />

Wird die Ausnahme nicht <strong>in</strong>nerhalb derselben Methode behandelt, dann ist sie mit<br />

Hilfe der "throws"-Klausel zu deklarieren und „weiter oben“ <strong>in</strong> der Aufrufkette zu<br />

behandeln.


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bsp.:<br />

public class AusnahmeMethoden<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g aurgs[])<br />

{<br />

try<br />

{<br />

throw new Exception("Hier ist me<strong>in</strong>e Ausnahme");<br />

}<br />

catch (Exception a)<br />

{<br />

System.out.pr<strong>in</strong>tln("E<strong>in</strong>gefangene Ausnahme");<br />

System.out.pr<strong>in</strong>tln("a.getMessage(): " + a.getMessage());<br />

System.out.pr<strong>in</strong>tln("a.toStr<strong>in</strong>g(): " + a.toStr<strong>in</strong>g());<br />

System.out.pr<strong>in</strong>tln("a.pr<strong>in</strong>tStackTrace(): ");<br />

a.pr<strong>in</strong>tStackTrace();<br />

}<br />

}<br />

}<br />

/* Ausgabe:<br />

E<strong>in</strong>gefangene Ausnahme<br />

a.getMessage(): Hier ist me<strong>in</strong>e Ausnahme<br />

a.toStr<strong>in</strong>g(): java.lang.Exception: Hier ist me<strong>in</strong>e Ausnahme<br />

a.pr<strong>in</strong>tStackTrace():<br />

java.lang.Exception: Hier ist me<strong>in</strong>e Ausnahme<br />

at AusnahmeMethoden.ma<strong>in</strong>(AusnahmeMethoden.java)<br />

*/<br />

Die throw-Anweisung besitzt Merkmale e<strong>in</strong>er Sprunganweisung. Sie unterbricht das<br />

Programm und verzweigt unmittelbar zur umgebenden catch-Klausel. Gibt es ke<strong>in</strong>e<br />

catch-Klausel, wird der Fehler weitergegeben. Tritt die Ausnahme <strong>in</strong>nerhalb e<strong>in</strong>er<br />

try-catch-Anweisung mit e<strong>in</strong>er f<strong>in</strong>ally-Klausel auf, wird diese noch vor der<br />

Weitergabe ausgeführt.<br />

Auch das „Wiederauswerfen“ e<strong>in</strong>er Ausnahme ist möglich, <strong>in</strong>sbesondere dann, falls<br />

e<strong>in</strong>e Ausnahme e<strong>in</strong>gefangen wurde, sie aber <strong>in</strong> e<strong>in</strong>em größeren Zusammenhang<br />

behandelt werden soll<br />

catch (Exception a)<br />

{<br />

System.out.pr<strong>in</strong>tln(“E<strong>in</strong>e Ausnahme wurde e<strong>in</strong>gefangen“);<br />

throw a;<br />

}<br />

Eigene, d.h. benutzerdef<strong>in</strong>ierte Ausnahmen können direkt von der Klasse<br />

Exception abgeleitet werden, z.B. 75 :<br />

class Me<strong>in</strong>eAusnahme extends Exception<br />

{<br />

private <strong>in</strong>t i;<br />

public Me<strong>in</strong>eAusnahme() {}<br />

public Me<strong>in</strong>eAusnahme(Str<strong>in</strong>g nachricht)<br />

{<br />

super(nachricht);<br />

}<br />

public Me<strong>in</strong>eAusnahme(Str<strong>in</strong>g nachricht, <strong>in</strong>t x)<br />

{<br />

super(nachricht);<br />

i = x;<br />

}<br />

public <strong>in</strong>t wert() { return i; }<br />

}<br />

75 Vgl. PR14140<br />

87


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class AuswurfMe<strong>in</strong>eAusnahme<br />

{<br />

public static void f() throws Me<strong>in</strong>eAusnahme<br />

{<br />

System.out.pr<strong>in</strong>tln("Auswurf von Me<strong>in</strong>eAusnahme aus f()");<br />

throw new Me<strong>in</strong>eAusnahme();<br />

}<br />

public static void g() throws Me<strong>in</strong>eAusnahme<br />

{<br />

System.out.pr<strong>in</strong>tln("Auswurf von Me<strong>in</strong>eAusnahme aus g()");<br />

throw new Me<strong>in</strong>eAusnahme("Ursprung <strong>in</strong> g()");<br />

}<br />

public static void h() throws Me<strong>in</strong>eAusnahme<br />

{<br />

System.out.pr<strong>in</strong>tln("Auswurf von Me<strong>in</strong>eAusnahme aus h()");<br />

throw new Me<strong>in</strong>eAusnahme("Ursprung <strong>in</strong> h()",13);<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

try {<br />

f();<br />

}<br />

catch (Me<strong>in</strong>eAusnahme a)<br />

{<br />

a.pr<strong>in</strong>tStackTrace();<br />

}<br />

try { g(); }<br />

catch (Me<strong>in</strong>eAusnahme a)<br />

{<br />

a.pr<strong>in</strong>tStackTrace();<br />

}<br />

try { h(); }<br />

catch (Me<strong>in</strong>eAusnahme a)<br />

{<br />

a.pr<strong>in</strong>tStackTrace();<br />

System.out.pr<strong>in</strong>tln("a.wert() = " + a.wert());<br />

}<br />

}<br />

}<br />

/* Ausgabe:<br />

Auswurf vom Me<strong>in</strong>eAusnahme aus f()<br />

Me<strong>in</strong>eAusnahme<br />

at java.lang.Throwable.(Compiled Code)<br />

at java.lang.Exception.(Compiled Code)<br />

at Me<strong>in</strong>eAusnahme.(AuswurfMe<strong>in</strong>eAusnahme.java:4)<br />

at AuswurMe<strong>in</strong>eAusnahme.f(Vererbung.java:21)<br />

at Auswurfme<strong>in</strong>eAusnahme.ma<strong>in</strong>(Vererbung.java:36)<br />

Auswurf von Me<strong>in</strong>eAusnahme aus g()<br />

Me<strong>in</strong>eAusnahme: Ursprung <strong>in</strong> g()<br />

at java.lang.Throwable.(Compiled Code)<br />

at java.lang.Exception.(Compiled Code)<br />

at Me<strong>in</strong>eAusnahme.(AuswurfMe<strong>in</strong>eAusnahme.java:7)<br />

at AuswurfMe<strong>in</strong>eAusnahme.g(AuswurfMe<strong>in</strong>eAusnahme.java:26)<br />

at AuswurfMe<strong>in</strong>eAusnahme.ma<strong>in</strong>(AuswurfMe<strong>in</strong>eAusnahme.java:43)<br />

Auswurf von Me<strong>in</strong>eAusnahme aus h()<br />

Me<strong>in</strong>eAusnahme: Ursprung <strong>in</strong> h()<br />

at java.lang.Throwable.(Compiled Code)<br />

at java.lang.Exception.(Compiled Code)<br />

at Me<strong>in</strong>eAusnahme.(AuswurfMe<strong>in</strong>eAusnahme.java:11)<br />

at AuswurfMe<strong>in</strong>eAusnahme.g(AuswurfMe<strong>in</strong>eAusnahme.java:31)<br />

at AuswurfMe<strong>in</strong>eAusnahme.ma<strong>in</strong>(AuswurfMe<strong>in</strong>eAusnahme.java:50)<br />

a.wert() = 13<br />

*/<br />

88


1.4.4 E<strong>in</strong>fache E<strong>in</strong>-, Ausgaben<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>- und Ausgabeströme der Klasse System<br />

Die Klasse System enthält drei Datenströme:<br />

public static InputStream 76 <strong>in</strong> // Standarde<strong>in</strong>gabe<br />

public static Pr<strong>in</strong>tStream 77 out // Standardausgabe<br />

public static Pr<strong>in</strong>tStream err // Standardfehlerausgabe<br />

Diese Datenströme dienen zum Lesen bzw. Schreiben <strong>in</strong> das Fenster von dem die<br />

Anwendung gestartet wurde. Die Verwendung des Stroms System.<strong>in</strong> <strong>in</strong>nerhalb von<br />

Applets ist aber nicht s<strong>in</strong>nvoll, weil die verschieden Browser diesen Datenstrom<br />

unterschiedlich behandeln. Die Ströme System.out und System.err sendet<br />

Netscape an das Fenster der <strong>Java</strong>-Konsole, der Appletviewer gibt sie <strong>in</strong> das Fenster<br />

weiter, aus dem der Appletviewer gestartet wurde,<br />

E<strong>in</strong>fache Ausgaben auf das Standard-Ausgabegerät<br />

Mit Hilfe des Kommandos „System.out.pr<strong>in</strong>tln“, das als e<strong>in</strong>ziges Argument e<strong>in</strong>e<br />

Zeichenkette erwartet, können e<strong>in</strong>fache Ausgaben auf den Bildschirm geschrieben<br />

werden. Mit Hilfe des Plus-Operators „+“ können Zeichenketten und numerische<br />

Argumente verknüpft werden, so daß man neben Text auch Zahlen ausgeben kann.<br />

76 Mit der Klasse InputStream können Leseoperationen e<strong>in</strong>es Bytestroms verwirklicht werden, vgl. 7.1.1<br />

77 Die Klasse Pr<strong>in</strong>tStream bezieht sich auf die I/O von <strong>Java</strong> 1.0<br />

89


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>fache E<strong>in</strong>gaben vom Standard-E<strong>in</strong>gabegerät<br />

Leider ist es etwas komplizierter Daten zeichenweise von der Tastatur zu lesen. Es<br />

steht zwar e<strong>in</strong> vordef<strong>in</strong>ierter E<strong>in</strong>gabestrom System.<strong>in</strong> zur Verfügung, der aber nicht<br />

die e<strong>in</strong>gelesenen Zeichen primitiver Typen konvertieren kann. Statt dessen muß e<strong>in</strong>e<br />

Instanz der Klasse „InputStreamReader“ 78 und daraus e<strong>in</strong> „BufferedReader“<br />

erzeugt werden. Dieser kann zum Lesen e<strong>in</strong>er zeilenweisen E<strong>in</strong>gabe mit<br />

Umwandlung des Ergebnisses <strong>in</strong> e<strong>in</strong>en primitiven Typ verwendet werden, z.B. 79 :<br />

"E<strong>in</strong>lesen von zwei ganzen Zahlen".<br />

import java.io.*;<br />

public class E<strong>in</strong>gZweiZahlen<br />

{<br />

// E<strong>in</strong>lesen von zwei ganzen Zahlen<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]) throws IOException<br />

{<br />

<strong>in</strong>t a, b, c;<br />

BufferedReader e<strong>in</strong> = new BufferedReader(new<br />

InputStreamReader(System.<strong>in</strong>));<br />

System.out.pr<strong>in</strong>t("Bitte a e<strong>in</strong>geben: ");<br />

a = Integer.parseInt(e<strong>in</strong>.readL<strong>in</strong>e());<br />

System.out.pr<strong>in</strong>t("Bitte b e<strong>in</strong>geben: ");<br />

b = Integer.parseInt(e<strong>in</strong>.readL<strong>in</strong>e());<br />

c = a + b;<br />

System.out.pr<strong>in</strong>tln("a + b = " + c);<br />

}<br />

}<br />

Datenströme<br />

Das grundlegende Modell für E<strong>in</strong>- und Ausgabe s<strong>in</strong>d Datenströme (Character-<br />

Streams), die im Paket "java.io" versammelt s<strong>in</strong>d. Das Datenstrom-Modell geht<br />

davon aus, daß<br />

- Programme Zeichenfolgen aus e<strong>in</strong>em Datenstrom lesen bzw. <strong>in</strong> e<strong>in</strong>en Datenstrom schreiben<br />

- e<strong>in</strong> Datenstrom unabhängig von den Fähigkeiten des jeweiligen I/O-Geräts 80 organisiert werden<br />

muß.<br />

Streams können auch verkettet werden und verschachtelt werden. Das Schachteln<br />

erlaubt die Konstruktion von Filtern, die bei der E<strong>in</strong>-/Ausgabe bestimmte<br />

Zusatzfunktionen übernehmen, z.B. das Puffern von Zeichen, das Zählen von<br />

Zeichen oder die Interpretation b<strong>in</strong>ärer Dateien.<br />

Alle Klassen zur Datene<strong>in</strong>- bzw. Datenausgabe bef<strong>in</strong>den sich im Paket java.io und<br />

s<strong>in</strong>d von den abstrakten Klassen Reader bzw. Writer 81 abgeleitet. Allgeme<strong>in</strong>e<br />

Fehlanzeige im Paket java.io ist die Ausnahme IOException, die deshalb auch<br />

von e<strong>in</strong>er Vielzahl von Methoden ausgelöst werden kann und dabei sehr<br />

unterschiedliche Bedeutung annehmen kann.<br />

Bsp.: Das folgende Programm liest e<strong>in</strong>e Zeichenfolge aus e<strong>in</strong>em E<strong>in</strong>gabestrom und<br />

schreibt die Zeichenfolge <strong>in</strong> e<strong>in</strong>en Ausgabestrom 82<br />

78 Das grundlegende Konzept für E<strong>in</strong>- und Ausgabe s<strong>in</strong>d Datenströme, die im Paket „java.io“ versammelt<br />

s<strong>in</strong>d.<br />

79 Vgl. PR14150<br />

80 Hauptspeicher, Festplatte, Drucker, Netzwerk<br />

81 vgl. 7.6<br />

82 vgl. PR14150<br />

90


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

import java.io.*;<br />

public class EchoE<strong>in</strong>Aus extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

InputStreamReader isr = new InputStreamReader(System.<strong>in</strong>);<br />

BufferedReader e<strong>in</strong> = new BufferedReader(isr);<br />

Str<strong>in</strong>g e<strong>in</strong>gabeZeile = null;<br />

OutputStreamWriter osw = new OutputStreamWriter(System.out);<br />

Pr<strong>in</strong>tWriter aus = new Pr<strong>in</strong>tWriter(System.out);<br />

while (true)<br />

{<br />

aus.pr<strong>in</strong>t("Gib e<strong>in</strong>e Zeichenkette e<strong>in</strong>: ");<br />

aus.flush();<br />

try {<br />

e<strong>in</strong>gabeZeile = e<strong>in</strong>.readL<strong>in</strong>e();<br />

}<br />

catch (IOException e)<br />

{<br />

aus.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

System.exit(0);<br />

}<br />

if (e<strong>in</strong>gabeZeile == null)<br />

{<br />

aus.pr<strong>in</strong>tln();<br />

aus.flush();<br />

break;<br />

}<br />

aus.pr<strong>in</strong>tln(e<strong>in</strong>gabeZeile);<br />

}<br />

}<br />

}<br />

Für die E<strong>in</strong>gabe wurde herangezogen:<br />

- InputStream <strong>in</strong> der Klasse System aus dem Paket java.lang<br />

- die abstrakte Klasse InputStream des Pakets "java.io"<br />

- die Klasse InputStreamReader des Pakets "java.io"<br />

- die Methode "Str<strong>in</strong>g readL<strong>in</strong>e()" mit der Klasse BufferedReader des Pakets java.io<br />

Für die Ausgabe kann ebenso verfahren werden. Man zieht <strong>in</strong> diesem<br />

Zusammenhang zur Ausgabe heran:<br />

- die Klasse Pr<strong>in</strong>tStream (Subklasse der abstrakten Klasse OutputStream)<br />

- die Klasse BufferedWriter (Subklasse von Writer). Es gibt aber ke<strong>in</strong> Gegenstück zu "Str<strong>in</strong>g<br />

readL<strong>in</strong>e()".<br />

- die Klasse Pr<strong>in</strong>tWriter (Subklasse von Writer) für pr<strong>in</strong>tln(...)<br />

91


E<strong>in</strong>gabe und Ausgabe mit Dateien<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Zur E<strong>in</strong>-, Ausgabe von bzw. aus Dateien stehen die aus den Klassen Reader bzw.<br />

Writer abgeleiteten Klassen FileReader bzw. FileWriter zur Verfügung.<br />

Bsp.: E<strong>in</strong>lesen e<strong>in</strong>er E<strong>in</strong>gabe-Datei<br />

import java.io.*;<br />

public class E<strong>in</strong>gabeDatei extends Object<br />

{<br />

private BufferedReader e<strong>in</strong>;<br />

E<strong>in</strong>gabeDatei(Str<strong>in</strong>g dName) throws Exception<br />

{<br />

try {<br />

e<strong>in</strong> = new BufferedReader(new FileReader(dName));<br />

}<br />

catch (FileNotFoundException a)<br />

{<br />

// Der Konstruktor von FileReader war nicht erfolgreich<br />

System.out.pr<strong>in</strong>tln("Kann nicht geoeffnet werden: " + dName);<br />

throw a;<br />

}<br />

catch (Exception a)<br />

{<br />

// Alle anderen Ausnahmen schliessen die Datei<br />

try {<br />

e<strong>in</strong>.close();<br />

}<br />

catch (IOException a1)<br />

{<br />

System.out.pr<strong>in</strong>tln("e<strong>in</strong>.close() nicht erfolgreich");<br />

}<br />

throw a;<br />

}<br />

f<strong>in</strong>ally { /* nicht geeignet fuer close() */ }<br />

}<br />

Str<strong>in</strong>g holeZeile() throws IOException<br />

{<br />

Str<strong>in</strong>g s;<br />

try {<br />

s = e<strong>in</strong>.readL<strong>in</strong>e();<br />

}<br />

catch (IOException a)<br />

{<br />

System.out.pr<strong>in</strong>tln("readL<strong>in</strong>e() nicht erfolgreich");<br />

s = "Fehlanzeige";<br />

}<br />

return s;<br />

}<br />

void bere<strong>in</strong>igen()<br />

{<br />

// Freigabe der Syntax-Resourcen<br />

try {<br />

e<strong>in</strong>.close();<br />

}<br />

catch(IOException a2)<br />

{<br />

System.out.pr<strong>in</strong>tln("e<strong>in</strong>.close() nicht erfolgreich");<br />

}<br />

}<br />

}<br />

92


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das folgende Programm bearbeitet die E<strong>in</strong>gabedatei.<br />

import java.io.*;<br />

public class BearbeiteE<strong>in</strong>gabeDatei extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

try {<br />

// Erzeugen e<strong>in</strong>er Instanz<br />

E<strong>in</strong>gabeDatei e<strong>in</strong> =<br />

new E<strong>in</strong>gabeDatei("BearbeiteE<strong>in</strong>gabeDatei.java");<br />

Str<strong>in</strong>g s;<br />

<strong>in</strong>t i = 1;<br />

while ((s = e<strong>in</strong>.holeZeile()) != null)<br />

System.out.pr<strong>in</strong>tln("" + i++ + ": " + s);<br />

e<strong>in</strong>.bere<strong>in</strong>igen();<br />

}<br />

catch (Exception a)<br />

{<br />

System.out.pr<strong>in</strong>tln("E<strong>in</strong>gefangen <strong>in</strong> ma<strong>in</strong>(), a.pr<strong>in</strong>tStackTrace()");<br />

a.pr<strong>in</strong>tStackTrace();<br />

}<br />

}<br />

}<br />

Umlenken von Standarde<strong>in</strong>gabe, Standardausgabe und Standardfehlerausgabe<br />

In <strong>Java</strong> 1.1 ermöglichen die folgenden Methoden das Umlenken:<br />

- setIn(InputStream)<br />

- setOut(Pr<strong>in</strong>tStream)<br />

- setErr(Pr<strong>in</strong>tStream)<br />

Bsp.: Demonstration der Umlenkung von Standarde<strong>in</strong>gabe und Standardausgabe <strong>in</strong><br />

<strong>Java</strong> 1.1 83<br />

import java.io.*;<br />

class Umlenken<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

try<br />

{<br />

BufferedInputStream e<strong>in</strong> =<br />

new BufferedInputStream(new FileInputStream("Umlenken.java"));<br />

// produziert "deprecation"-Nachrichten, System.setOut() und<br />

// System.setErr() erfordern e<strong>in</strong> Pr<strong>in</strong>tStream-Objekt als Argument<br />

Pr<strong>in</strong>tStream aus = new Pr<strong>in</strong>tStream( new BufferedOutputStream(<br />

new FileOutputStream("test.aus")));<br />

System.setIn(e<strong>in</strong>); System.setOut(aus); System.setErr(aus);<br />

BufferedReader br =<br />

new BufferedReader(new InputStreamReader(System.<strong>in</strong>));<br />

Str<strong>in</strong>g s;<br />

while ((s = br.readL<strong>in</strong>e()) != null)<br />

System.out.pr<strong>in</strong>tln(s);<br />

aus.close();<br />

}<br />

catch(IOException a)<br />

{<br />

a.pr<strong>in</strong>tStackTrace();<br />

}<br />

}<br />

}<br />

83 vgl. PR14150<br />

93


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2. Hauptbestandteile der Sprache<br />

2.1 Token<br />

Token bedeuten <strong>in</strong> <strong>Java</strong> dasselbe wie Worte und Zeichensetzung für die<br />

menschliche Sprache. Wenn <strong>Java</strong> den Quellcode mit dem <strong>Java</strong>-Compiler (javac)<br />

kompiliert, f<strong>in</strong>det e<strong>in</strong>e Zerlegung des Quellcodes <strong>in</strong> kle<strong>in</strong>e Bestandteile, Symbole<br />

oder Token genannt, statt. Token müssen sich <strong>in</strong> s<strong>in</strong>nvolle E<strong>in</strong>heiten und gültige<br />

Arten e<strong>in</strong>ordnen lassen. Das übernimmt der sog. Parser des javac, der Quelltext <strong>in</strong><br />

Bytecode übersetzt und zusätzlich noch Leerzeichen und Kommentare (aus dem<br />

Quelltext) entfernt.<br />

Aus Token setzen sich die Ausdrucksformen von <strong>Java</strong> zusammen. Es gibt <strong>in</strong> <strong>Java</strong><br />

fünf Arten von Token: Bezeichner oder Identifizierer, Schlüsselwörter, Literale,<br />

Operatoren, Trennzeichen.<br />

Token Beschreibung Bsp.<br />

Schlüsselworte Alle Wörter, die e<strong>in</strong> wesentlicher Teil der public, class, static, void, Str<strong>in</strong>g,<br />

<strong>Java</strong>-Sprachdef<strong>in</strong>ition s<strong>in</strong>d<br />

else, if, this, etc.<br />

Bezeichner, Identifiziere Namen für Klassen,Objekte, Variablen,<br />

Konstanten, Methoden, etc.; Namen s<strong>in</strong>d<br />

zusammengesetzt aus Unicode-Zeichen.<br />

An erster Stelle e<strong>in</strong>es Bezeichners darf<br />

ke<strong>in</strong>e Zahl stehen.<br />

Literal Mit e<strong>in</strong>em Literal können Variablen und<br />

Konstanten bestimmte Werte zugewiesen<br />

werden. Die können sämtliche <strong>in</strong> der<br />

<strong>Java</strong>-Sprachdef<strong>in</strong>ition erlaubte Arten von<br />

Werten (numerische Werte, boolesche<br />

Werte, Zeichen, Zeichenketten) se<strong>in</strong><br />

“Hallo <strong>Java</strong>“, 13, false, true<br />

Trennzeichen Symbol zum Anzeigen für Trennungen<br />

und Zusammenfassungen von Code<br />

( ) { } [ ] ; . ,<br />

Operatoren Zeichen bzw. Zeichenkomb<strong>in</strong>ationen zur<br />

Angabe e<strong>in</strong>er auszuführenden Operation<br />

mit e<strong>in</strong>er oder mehreren Variablen oder<br />

Konstanten<br />

+ - * / , >>>


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Zeichen transformiert. E<strong>in</strong>e ASCII-Kodierung wird e<strong>in</strong>fach mit Voranstellen der<br />

Zeichenfolge „\u00“ und folgender Hexadezimalzahl <strong>in</strong> das passende Unicode-<br />

Zeichen übersetzt. Dies def<strong>in</strong>iert <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e Escape-Sequenz, mit der alle Unicode-<br />

Zeichen verschlüsselt werden können. Durch die „Escape-Sequenz-Darstellung“ des<br />

Quelltextes <strong>in</strong> <strong>Java</strong> ist die Verwendung von Umlauten und anderen Sonderzeichen <strong>in</strong><br />

Bezeichnern möglich.<br />

Zwei Bezeichner gelten <strong>in</strong> <strong>Java</strong> als identisch, wenn ihre Unicode-Darstellung<br />

übere<strong>in</strong>stimmend ist. Deshalb muß auch <strong>in</strong> <strong>Java</strong> unbed<strong>in</strong>gt zwischen Groß- und<br />

Kle<strong>in</strong>schreibung unterschieden werden.<br />

2.1.1 Schlüsselworte<br />

Es gibt bestimmte Buchstabenkomb<strong>in</strong>ationen, die <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e besondere<br />

Bedeutung haben. Diese Buchstabenfolgen werden <strong>in</strong> <strong>Java</strong> Schlüsselworte genannt<br />

abstract boolean break byte case cast<br />

catch char class const cont<strong>in</strong>ue default<br />

do double else extends false f<strong>in</strong>al<br />

f<strong>in</strong>ally float for future generic goto<br />

if implements import <strong>in</strong>ner <strong>in</strong>stanceof <strong>in</strong>t<br />

<strong>in</strong>terface long native new null operator<br />

outer package private protected public rest<br />

return short static super switch synchronized<br />

this throw throws transient true try<br />

var void volatile while<br />

Abb.: Reservierte <strong>Java</strong> Schlüsselworte<br />

95


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2.1.2 Bezeichner und Namenskonventionen<br />

Bezeichner bzw. Identifizierer (identifier) s<strong>in</strong>d Worte, die vom Programmierer<br />

gewählt, zu Token werden und die Variablen, Konstanten, Klassen, Objekte,<br />

Beschriftungen und Methoden darstellen. Bezeichner dürfen nicht mit <strong>Java</strong>-<br />

Schlüsselworten identisch se<strong>in</strong>.<br />

Es gibt <strong>in</strong> <strong>Java</strong> e<strong>in</strong>ige Regeln zur Namensvergabe, die unbed<strong>in</strong>gt e<strong>in</strong>gehalten<br />

werden müssen:<br />

- Bezeichner bestehen aus Unicode-Buchstaben und Zahlen <strong>in</strong> unbeschränkter Länge.<br />

- Das erste Zeichen e<strong>in</strong>es Bezeichners muß e<strong>in</strong> Buchstabe, der Unterstrich „_“ oder das Zeichen „$“ se<strong>in</strong>. Alle<br />

folgenden Zeichen s<strong>in</strong>d entweder Buchstaben oder Zahlen.<br />

- Zwei Token gelten nur dann als derselbe Bezeichner, wenn sie dieselbe Länge haben, und jedes Zeichen im<br />

ersten Token genau mit dem korrespondierenden Zeichen des zweiten Token übere<strong>in</strong>stimmt, d.h. den<br />

vollkommen identischen Unicode-Wert hat. <strong>Java</strong> unterscheidet Groß- und Kle<strong>in</strong>schreibung.<br />

Es hat sich e<strong>in</strong>gebürgert, e<strong>in</strong>ige Namenskonventionen <strong>in</strong> <strong>Java</strong> e<strong>in</strong>zuhalten:<br />

- Man sollte möglichst „sprechende“ Bezeichner wählen (Ausnahme s<strong>in</strong>d Schleifen, wo für Zählvariablen<br />

meistens nur e<strong>in</strong> Buchstabe (z.B. i, j) verwendet wird.<br />

- Konstanten (Elemente mit dem „Modifizierer“ „f<strong>in</strong>al“) sollten vollständig groß geschrieben werden.<br />

- Identifizierer von Klassen sollten mit e<strong>in</strong>em Großbuchstaben beg<strong>in</strong>nen und anschließend kle<strong>in</strong> geschrieben<br />

werden. Wenn sich e<strong>in</strong> Bezeichner aus mehreren Wörtern zusammensetzt, dürfen diese nicht getrennt werden.<br />

Die jeweiligen Anfangsbuchstaben <strong>in</strong>nerhalb des gesamten Bezeichners werden jedoch groß geschrieben.<br />

- Die Identifizierer von Variablen, Methoden und Elementen beg<strong>in</strong>nen mit Kle<strong>in</strong>buchstaben und werden auch<br />

anschließend kle<strong>in</strong> geschrieben. Wenn e<strong>in</strong> Bezeichner sich aus mehreren Wörtern zusammensetzt, dürfen<br />

diese nicht getrennt werden. Die jeweiligen Anfangsbuchstaben der folgenden Wörter können jedoch<br />

<strong>in</strong>nerhalb des Gesamtbezeichners groß geschrieben werden.<br />

2.1.3 Literale<br />

Literale s<strong>in</strong>d Token, die für zu speichernde Werte der Datentypen byte, short,<br />

<strong>in</strong>t, long, float, double, boolean und char stehen. Literale werden auch zur<br />

Darstellung von Werten benutzt, die <strong>in</strong> Zeichenketten gespeichert werden.<br />

Es gibt: Boolesche Literale, Zeichenliterale, Zeichenkettenliterale, Gleitpunktliterale,<br />

ganzzahlige Literale.<br />

1 Ganzzahlige Literale<br />

Die Datentypen „<strong>in</strong>t“ und „long“ können dezimal, hexadezimal und oktal<br />

beschrieben werden. Die Vore<strong>in</strong>stellung ist dezimal und gilt immer dann, wenn Werte<br />

ohne weitere Änderung dargestellt werden. Hexadezimale Darstellung beg<strong>in</strong>nt immer<br />

mit der Sequenz 0x oder 0X 86 . Oktale Darstellungen beg<strong>in</strong>nen mit e<strong>in</strong>er führenden<br />

Null. Negativen Ganzzahlen wird e<strong>in</strong> M<strong>in</strong>uszeichen vorangestellt. Ganzzahlige<br />

Literale haben gemäß Vore<strong>in</strong>stellung den Typ „<strong>in</strong>t“. Durch Anhängen vom „l“ bzw.<br />

„L“ kann man jedoch explizit den Typ „long“ wählen.<br />

86 Die Zahlen 0 bis 15 werden durch die Buchstaben „A“ bis „F“ bzw. „a“ bis „f“ dargestellt (Groß- oder<br />

Kle<strong>in</strong>schreibung ist hier nicht relevant.<br />

96


2. Gleitpunktliterale<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Gleitpunktliterale bestehen aus mehreren Teilen. Sie ersche<strong>in</strong>en <strong>in</strong> folgender<br />

Reihenfolge:<br />

Teil Nötig? Beispiele<br />

Ganzzahliger Teil Nicht, wenn der gebrochene Teil<br />

vorhanden ist<br />

0, 1, 2, ... , 9, 131140<br />

Dezimalpunkt Nicht, wenn e<strong>in</strong> Exponent vorhanden<br />

ist. Muß vorliegen, wenn es e<strong>in</strong>en<br />

Dezimalpunkt gibt<br />

Gebrochener Teil Darf nicht vorhanden se<strong>in</strong>, wenn es 0, 1, 1311, 41421, 9944,<br />

ke<strong>in</strong>en Dezimalpunkt gibt. Muß<br />

vorhanden se<strong>in</strong>, wenn es ke<strong>in</strong>en<br />

ganzzahligen Teil gibt<br />

718281828<br />

Exponent Nur, wenn es ke<strong>in</strong>en Dezimalpunkt<br />

gibt<br />

E23, E-19, E6, e+307<br />

Typensuffix Ne<strong>in</strong>. Bei Abwesenheit e<strong>in</strong>es<br />

Typensuffix wird angenommen, daß<br />

es sich um e<strong>in</strong>e Zahl doppelter<br />

Genauigkeit handelt.<br />

f, F, d, D<br />

Bsp.: Typensuffix für Ganzzahlen bzw. Gleitpunktzahlen<br />

class Literale<br />

{<br />

char c = 0xffff; // max. hex. Wert fuer char<br />

byte b = 0x7f; // max. hex. Wert fuer byte<br />

short s = 0x7fff; // max. hex. Wert fuer short<br />

<strong>in</strong>t i1 = 0x2f; // hexadezimal <strong>in</strong> Kle<strong>in</strong>buchstaben<br />

<strong>in</strong>t i2 = 0X2F; // hexadezimal <strong>in</strong> Grossbuchstaben<br />

// hexadeimale und oktale Werte mit long<br />

long n1 = 200L; // "long"-Suffix<br />

long n2 = 200l; // "long"-suffix<br />

long n3 = 200;<br />

// float- und double-Literale<br />

float f1 = 1;<br />

float f2 = 1F; // "float"-Suffix<br />

float f3 = 1f; // "float"-Suffix<br />

float f4 = 1e-45f; // wissenschaftl. Schreibweise<br />

float f5 = 1e+9f; // "float"-Suffix<br />

double d1 = 1d; // "double"-Suffix<br />

double d2 = 1D; // "double"-Suffix;<br />

double d3 = 47e47d; // wissenschaftl. Schreibweise<br />

}<br />

3. Boolesche Literale<br />

Es gibt zwei Boolesche Literale: true und false. Es gibt ke<strong>in</strong>en Nullwert und ke<strong>in</strong><br />

numerisches Äquivalent.<br />

97


4. Zeichenliterale<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Sie werden <strong>in</strong> e<strong>in</strong>zelne, hochgestellte Anführungszeichen gesetzt. Als e<strong>in</strong>zelne<br />

Zeichen gelten alle druckbaren Zeichen mit Ausnahme des B<strong>in</strong>destrichs „-“ und des<br />

Backslash „\“. Bei Escape-Zeichenliteralen folgen den Anführungszeichen der<br />

Backslash und dem Backslash e<strong>in</strong>e der folgenden Zeichen:<br />

- b, t, n, f, r,


2.1.4 Trennzeichen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Trennnzeichen s<strong>in</strong>d Token, die aus e<strong>in</strong>em e<strong>in</strong>zigen Zeichen bestehen und andere<br />

Token trennen. <strong>Java</strong> kennt 9 Trennzeichen:<br />

( Wird sowohl zum Öffnen e<strong>in</strong>er Parameterliste für e<strong>in</strong>e Methode als auch zur Festlegung e<strong>in</strong>es<br />

Vorrangs für Operationen <strong>in</strong> e<strong>in</strong>em Ausdruck benutzt.<br />

) Wird sowohl zum Schließen e<strong>in</strong>er Parameterliste für e<strong>in</strong>e Methode als auch zur Festlegung e<strong>in</strong>es<br />

Vorrangs für Operationen <strong>in</strong> e<strong>in</strong>em Ausdruck benutzt<br />

{ Wird zu Beg<strong>in</strong>n e<strong>in</strong>es Blocks mit Anweisungen oder e<strong>in</strong>er Initialisierungsliste gesetzt<br />

} Wird an das Ende e<strong>in</strong>es Blocks mit Anweisungen oder e<strong>in</strong>er Initialisierungsliste gesetzt<br />

[ Steht vor e<strong>in</strong>em Ausdruck, der als Index für e<strong>in</strong> Datenfeld (Array) steht<br />

] Folgt e<strong>in</strong>em Ausdruck, der als Index für e<strong>in</strong> Datenfeld dient<br />

; Dient sowohl zum Beenden e<strong>in</strong>er Ausdrucksanweisung als auch zum Trennen der Teile e<strong>in</strong>er for-<br />

Anweisung.<br />

, wird <strong>in</strong> vielen Zusammenhängen als Begrenzer verwendet<br />

. Wird sowohl als Dezimalpunkt als auch zum Trennen solcher D<strong>in</strong>ge wie Paketnamen von<br />

Klassennamen oder Variablennamen benutzt.<br />

Abb.: Die <strong>Java</strong>-Trennzeichen<br />

99


2.1.5 Operatoren<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Operatoren geben an, welche Operation mit e<strong>in</strong>em oder mehreren gegebenen<br />

Operanden durchgeführt werden soll. Es gibt <strong>in</strong> <strong>Java</strong> 37 Zeichensequenzen, die<br />

Token darstellen, welche als Operatoren benutzt werden.<br />

Arithmetische Operatoren<br />

Arithmetische Operatoren benutzen nur zwei Operanden. Diese s<strong>in</strong>d entweder<br />

ganzzahlige Werte oder Gleitpunktzahlen. Als Rückgabe e<strong>in</strong>er arithmetischen<br />

Operation erhält man e<strong>in</strong>en neuen Wert, dessen Datentyp sich folgendermaßen<br />

ergibt:<br />

- Zwei ganzzahlige Datentypen (byte, short, <strong>in</strong>t oder long) als Operanden ergeben immer e<strong>in</strong>en<br />

ganzzahligen Datentyp als Ergebnis. Dabei kann als Datentyp <strong>in</strong>t oder long entstehen, byte und<br />

short s<strong>in</strong>d nicht möglich. Der Datentyp long entsteht nur, wenn e<strong>in</strong>er der beiden Operanden<br />

bereits vom Datentyp long war oder das Ergebnis von der Größe her nur als long dargestellt<br />

werden kann.<br />

- Zwei Gleitpunktzahlentypen als Operanden ergeben immer e<strong>in</strong>en Gleitpunktzahlentyp als Ergebnis. Die Anzahl<br />

der Stellen des Ergebnisses ist immer das Maximum der Stellenanzahl der beiden Operanden.<br />

- Falls die Operanden e<strong>in</strong> ganzzahliger Typ und e<strong>in</strong>e Gleitpunktzahlentyp s<strong>in</strong>d, dann ist das Ergebnis immer e<strong>in</strong><br />

Gleitpunktzahlentyp.<br />

Operator Bedeutung Beispiel<br />

+ Additionsoperator 13 + 11<br />

- Subtraktionsoperator 13 - 11<br />

* Multiplikationsoperator 13 * 11<br />

/ Divisionsoperator 13 / 11<br />

% Modulo-Operator 13 % 11<br />

Abb.: Die arithmetischen <strong>Java</strong>-Operatoren<br />

E<strong>in</strong>stellige arithmetische Operatoren<br />

Es gibt zwei e<strong>in</strong>stellige (d.h. mit nur e<strong>in</strong>em Operanden) arithmetische Operatoren <strong>in</strong><br />

<strong>Java</strong>:<br />

- E<strong>in</strong>stellige arithmetische Negierung: -<br />

- Das Gegenteil der arithmetischen Negierung: +<br />

Arithmetische Zuweisungsoperatoren<br />

Neben dem direkten Zuweisungsoperator gibt es die arithmetischen<br />

Zuweisungsoperatoren. Diese s<strong>in</strong>d eigentlich nur e<strong>in</strong>e Abkürzung für arithmetische<br />

Operationen mit ganzen Zahlen und Gleitpunktzahlen. Das Ergebnis e<strong>in</strong>er<br />

Zuweisung über e<strong>in</strong>en arithmetischen Zuweisungsoperator steht immer auf der<br />

l<strong>in</strong>ken Seite.<br />

Operator Bedeutung<br />

+= Additions- und Zuweisungsoperator<br />

-= Subtraktions- und Zuweisungsoperator<br />

*= Multiplikations- und Zuweisungsoperator<br />

100


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

/= Divisions- und Zuweisungsoperator<br />

%= Modulo- und Zuweisungsoperator<br />

= Direkter Zuweisungsoperator<br />

Abb.: Die arithmetischen Zuweisungsoperatoren<br />

Inkrement- / Dekrement-Operatoren<br />

Inkrement- und Dekrement-Operatoren s<strong>in</strong>d e<strong>in</strong>stellige Operatoren und werden nur<br />

<strong>in</strong> Verb<strong>in</strong>dung mit e<strong>in</strong>em ganzzahligen Wert oder e<strong>in</strong>er Gleitpunktzahl benutzt.<br />

Der Inkrement-Operator (++) erhöht den Wert des Operanden um 1. Steht der<br />

Operator vor dem Operanden, erfolgt die Erhöhung des Werts, bevor der Wert dem<br />

Operanden zugewiesen wird. Wenn er h<strong>in</strong>ter dem Operanden steht, erfolgt die<br />

Erhöhung, nachdem der Wert bereits zugewiesen wurde.<br />

Der Dekrement-Operator (--) erniedrigt den Wert des Operanden um 1. Steht der<br />

Operator vor dem Operanden, erfolgt die Erniedrigung des Werts, bevor der Wert<br />

dem Operanden zugewiesen wird. Wenn er h<strong>in</strong>ter dem Operanden steht, erfolgt die<br />

Erniedrigung, nachdem der Wert bereits zugewiesen wurde.<br />

Bitweise arithmetische Operatoren<br />

Bitweise Arithmetik wird im wesentlichen zum Setzen und Testen e<strong>in</strong>zelner Bits und<br />

Komb<strong>in</strong>ationen e<strong>in</strong>zelner Bits <strong>in</strong>nerhalb e<strong>in</strong>er Variablen benutzt.<br />

Operator Beschreibung<br />

& Bitweiser AND-Operator<br />

| Bitweiser OR-Operator<br />

^ Bitweiser XOR-Operator<br />

~ Bitweiser Komplement-Operator<br />

Abb.: Bitoperatoren <strong>in</strong> <strong>Java</strong><br />

Bitweise Verschiebungsoperatoren<br />

Bitweise Verschiebungsoperatoren verschieben die Bits <strong>in</strong> e<strong>in</strong>er ganzen Zahl.<br />

Operator Beschreibung<br />

> Operator für bitweise Verschiebung nach rechts<br />

>>> Operator für b<strong>in</strong>äre Verschiebung nach rechts mit Füllnullen<br />

Abb.: Die bitweisen Verschiebungsoperatoren<br />

Bsp.: Bitweises Manipulieren 88<br />

import java.util.*;<br />

public class BitManipulation<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

88 PR21502<br />

101


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Random rand = new Random();<br />

<strong>in</strong>t i = rand.nextInt();<br />

<strong>in</strong>t j = rand.nextInt();<br />

pB<strong>in</strong>Int("-1",-1);<br />

pB<strong>in</strong>Int("+1",+1);<br />

<strong>in</strong>t maxpos = 2147483647;<br />

pB<strong>in</strong>Int("maxpos", maxpos);<br />

<strong>in</strong>t maxneg = -2147483648;<br />

pB<strong>in</strong>Int("maxneg",maxneg);<br />

pB<strong>in</strong>Int("i",i);<br />

pB<strong>in</strong>Int("~i",~i);<br />

pB<strong>in</strong>Int("-i",-i);<br />

pB<strong>in</strong>Int("j",j);<br />

pB<strong>in</strong>Int("i & j",i & j);<br />

pB<strong>in</strong>Int("i | j",i | j);<br />

pB<strong>in</strong>Int("i ^ j",i ^ j);<br />

pB<strong>in</strong>Int("i > 5",i >> 5);<br />

pB<strong>in</strong>Int("(~i) >> 5",(~i) >> 5);<br />

pB<strong>in</strong>Int("i >>> 5",i >>> 5);<br />

pB<strong>in</strong>Int("(~i) >>> 5", (~i) >>> 5);<br />

long l = rand.nextLong();<br />

long m = rand.nextLong();<br />

pB<strong>in</strong>Long("-1L",-1L);<br />

pB<strong>in</strong>Long("+1L",+1L);<br />

long ll = 9223372036854775807L;<br />

pB<strong>in</strong>Long("maxpos", ll);<br />

long lln = -9223372036854775807L;<br />

pB<strong>in</strong>Long("maxneg",lln);<br />

pB<strong>in</strong>Long("l",l);<br />

pB<strong>in</strong>Long("~l",~l);<br />

pB<strong>in</strong>Long("-l",-l);<br />

pB<strong>in</strong>Long("m",m);<br />

pB<strong>in</strong>Long("l & m",l & m);<br />

pB<strong>in</strong>Long("l | m",l | m);<br />

pB<strong>in</strong>Long("l ^ m",l ^ m);<br />

pB<strong>in</strong>Long("l > 5",l >> 5);<br />

pB<strong>in</strong>Long("(~l) >> 5",(~l) >> 5);<br />

pB<strong>in</strong>Long("l >>> 5",l >>> 5);<br />

pB<strong>in</strong>Long("(~l) >>> 5", (~l) >>> 5);<br />

}<br />

static void pB<strong>in</strong>Int(Str<strong>in</strong>g s, <strong>in</strong>t i)<br />

{<br />

System.out.pr<strong>in</strong>tln(s + ", <strong>in</strong>t: " + i + ", b<strong>in</strong>aer: ");<br />

System.out.pr<strong>in</strong>t(" ");<br />

for (<strong>in</strong>t j = 31; j >= 0; j--)<br />

if (((1 = 0; j--)<br />

if (((1L


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Ausgabe zu dieser Anwendung zeigt für den Bereich „<strong>in</strong>t“ jeweils die <strong>in</strong>terne<br />

Zahlendarstellung:<br />

-1, <strong>in</strong>t: -1, b<strong>in</strong>aer:<br />

11111111111111111111111111111111<br />

+1, <strong>in</strong>t: 1, b<strong>in</strong>aer:<br />

00000000000000000000000000000001<br />

maxpos, <strong>in</strong>t: 2147483647, b<strong>in</strong>aer:<br />

01111111111111111111111111111111<br />

maxneg, <strong>in</strong>t: -2147483648, b<strong>in</strong>aer:<br />

10000000000000000000000000000000<br />

i, <strong>in</strong>t: -1465644750, b<strong>in</strong>aer:<br />

10101000101001000000100100110010<br />

~i, <strong>in</strong>t: 1465644749, b<strong>in</strong>aer:<br />

01010111010110111111011011001101<br />

-i, <strong>in</strong>t: 1465644750, b<strong>in</strong>aer:<br />

01010111010110111111011011001110<br />

j, <strong>in</strong>t: -1273964081, b<strong>in</strong>aer:<br />

10110100000100001101100111001111<br />

i & j, <strong>in</strong>t: -1610610430, b<strong>in</strong>aer:<br />

10100000000000000000100100000010<br />

i | j, <strong>in</strong>t: -1128998401, b<strong>in</strong>aer:<br />

10111100101101001101100111111111<br />

i ^ j, <strong>in</strong>t: 481612029, b<strong>in</strong>aer:<br />

00011100101101001101000011111101<br />

i > 5, <strong>in</strong>t: -45801399, b<strong>in</strong>aer:<br />

11111101010001010010000001001001<br />

(~i) >> 5, <strong>in</strong>t: 45801398, b<strong>in</strong>aer:<br />

00000010101110101101111110110110<br />

i >>> 5, <strong>in</strong>t: 88416329, b<strong>in</strong>aer:<br />

00000101010001010010000001001001<br />

(~i) >>> 5, <strong>in</strong>t: 45801398, b<strong>in</strong>aer:<br />

00000010101110101101111110110110<br />

Bitweise Zuweisungsoperatoren<br />

Bitweise Zuweisungsoperatoren verwenden e<strong>in</strong>en Wert, führen e<strong>in</strong>e entsprechende<br />

bitweise Operation mit dem zweiten Operanden durch und legen das Ergebnis als<br />

Inhalt des ersten Operanden ab.<br />

Operator Beschreibung<br />

&= Bitweiser AND-Zuweisungsoperator<br />

|= Bitweiser OR-Zuweisungsoperator<br />

^= Bitweiser XOR-Zuweisungsoperator<br />

= Zuweisungsoperator für die bitweise Verschiebung nach rechts<br />

>>>= Zuweisungsoperator für die bitweise Verschiebung nach rechts mit Füllnullen<br />

Abb.: Die bitweisen Zuweisungsoperatoren<br />

103


Vergleichsoperatoren<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Vergleichsoperatoren haben zwei Operanden und vergleichen diese (zwei<br />

Ganzzahlen oder zwei Gleitpunktzahlen) 1 . Als Rückgabewert der Operation entsteht<br />

e<strong>in</strong> boolescher Wert (true oder false).<br />

Operator Bedeutung<br />

== Gleichheitsoperator<br />

!= Ungleichheitsoperator<br />

< Kle<strong>in</strong>er-als-Operator<br />

> Größer-als-Operator<br />

= Größer-als-oder-gleich-Operator<br />

Abb.: Die <strong>Java</strong>-Vergleichsoperatoren<br />

Die relationalen Operatoren „==“ und „!=“ arbeiten mit allen Objekten. Ihre<br />

Anwendung zeigt häufig e<strong>in</strong> „verwirrendes Ergebnis“, z.B. 90 :<br />

public class GleichheitsTest<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

Integer i1 = new Integer(13);<br />

Integer i2 = new Integer(13);<br />

System.out.pr<strong>in</strong>tln(i1 == i2); // false<br />

System.out.pr<strong>in</strong>tln(i1 != i2); // true<br />

}<br />

}<br />

Der Inhalt der Objekte ist zwar gleich, die Referenzen auf die Objekte s<strong>in</strong>d nicht<br />

gleich. Falls der aktuelle Infalt auf Gleichheit überprüft werden soll, steht die<br />

Methode equals() 91 bereit, z.B.:<br />

public class EqualsMethode<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

Integer i1 = new Integer(13);<br />

Integer i2 = new Integer(13);<br />

System.out.pr<strong>in</strong>tln(i1.equals(i2)); // true<br />

}<br />

}<br />

89 Die Werte zweier Variablen vom Typ char können ebenfalls mit den Vergleichsoperatoren verglichen<br />

werden. Es werden die Variablen vom Typ char bei der Verwendung e<strong>in</strong>es Vergleichsoperators wie ganze 16-<br />

Bit-Zahlen entsprechend ihrer Unicode-Codierung behandelt.<br />

90 Vgl. PR21500<br />

91 Viele <strong>in</strong> der <strong>Java</strong>-Bibliorhek bereitgestellte Klassen implementieren die Methode equals()<br />

104


Logische Vergleichsoperatoren<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die logischen Vergleichsoperatoren werden nur auf boolesche Operatoren<br />

angewandt und erzeugen nur boolesche Ergebnisse.<br />

Operator Beschreibung<br />

&& Logischer AND-Operator<br />

|| Logischer OR-Operator<br />

! Logischer NOT-Operator<br />

Abb.: Logische Vergleichsoperatoren<br />

2.1.6 Kommentare, e<strong>in</strong>gebettete Dokumentation<br />

Es gibt drei Arten von Kommentaren<br />

- E<strong>in</strong>zeilige Kommentare beg<strong>in</strong>nen mit // und enden mit dem Ende der Zeile<br />

- Mehrzeilige Kommentare beg<strong>in</strong>nen mit /* und enden mit */. Sie können sich über mehrere Zeilen<br />

erstrecken.<br />

- Dokumentationskommentare beg<strong>in</strong>nen mit /** und enden mit */. Sie können sich ebenfalls über<br />

mehrere Zeilen erstrecken und s<strong>in</strong>d spezielle Kommentare, die für das javadoc-System benutzt<br />

werden. <strong>Java</strong>doc dient zum Erzeugen von API-Dokumentationen aus anderem <strong>Java</strong>-Quellcode.<br />

105


2.2 Typen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> Typ gibt <strong>in</strong> e<strong>in</strong>er Computersprache an, wie etwas (z.B. e<strong>in</strong>e Variable) im<br />

Speicher des Rechners dargestellt wird. In <strong>Java</strong> gibt es vier verschiedene Arten von<br />

Typen: „primitive Datentypen“, Datenfelder (Arrays) , Klassen und Schnittstellen<br />

2.2.1 Primitive Datentypen<br />

<strong>Java</strong> besitzt 8 primitive Datentypen.<br />

Bezeichnung Typ Beschreibung<br />

byte 8 Bits Kle<strong>in</strong>ster Wertebereich. Mit Vorzeichen. Wird zum Darstellen von<br />

Ganzzahlwerten (ganzzahliges Zweierkomplement) von (-2 hoch 7 = -<br />

128) bis (+2 hoch 7 = 128) verwendet.<br />

short 16 Bits Wertebereich mit Vorzeichen. Wird zum Darstellen von<br />

Ganzzahlwerten (ganzzahliges Zweierkomplement) von (-2 hoch 15 =<br />

-32167) bis (+2 hoch 15 - 1 = 32.167) verwendet.<br />

<strong>in</strong>t 32 Bits Standardwertebereich. Wird zum Darstellen von Ganzzahlwerten<br />

(ganzzahliges Zweierkomplement) von (-2 hoch 31 = -2.147.483.648)<br />

bis (+2 hoch 31 = 2.147.483.647) verwendet.<br />

long 64 Bits Größter Wertebereich. Wird zum Darstellen von Ganzzahlwerten<br />

(ganzzahliges Zweierkomplement) von (-2 hoch 63) bis (+2 hoch 63)<br />

verwendet.<br />

float 32 Bits Kürzester Wertebereich mit Vorzeichen zur Darstellung von<br />

Gleitpunktzahlenwerten. Dies entspricht Gleitpunktzahlen mit e<strong>in</strong>facher<br />

Genauigkeit, die den IEEE-754-1985-Standard benutzen. Es existiert<br />

e<strong>in</strong> Literal zur Darstellung von plus/m<strong>in</strong>us unendlich sowie der Wert<br />

NaN (Not a Number) zur Darstellung von nicht def<strong>in</strong>ierten Ergebnissen<br />

double 64 Bits Größter Wertebereich mit Vorzeichen zur Darstellung von<br />

Gleitpunktzahlenwerten. Der Wertebereich liegt zwischen +/-10 hoch<br />

317. Auch diese Gleitpunktzahlen benutzen den IEEE-754-1985-<br />

Standard. Es existiert wie beim Typ float e<strong>in</strong> Literal zur Darstellung von<br />

plus/m<strong>in</strong>us unendlich sowie der Wert NaN (Not a Number) zur<br />

Darstellung von nicht def<strong>in</strong>ierten Ergebnissen<br />

char 16 Bits Darstellung e<strong>in</strong>es Zeichens des Unicode-Zeichensatzes. Zur<br />

Darstellung von alphanumerischen Zeichen wird dieselbe Kodierung<br />

wie beim ASCII-Zeichensatz verwendet, aber das höchste Bit ist auf 0<br />

gesetzt. Der Datentyp ist als e<strong>in</strong>ziger primitiver <strong>Java</strong>-Datentyp<br />

vorzeichenlos. Der Maximalwert ist \uFFFF.<br />

E<strong>in</strong>er char-Variablen kann, da sie 2 Bytes lang ist, e<strong>in</strong>e Ganzzahl<br />

zwischen 0 und 65535 ohne Konvertierung zugewiesen werden. Die<br />

Umkehrung – also die Zuweisung von char-Zeichen an andere<br />

Datentypen – funktioniert nur für <strong>in</strong>t problemlos. Für andere<br />

Datentypen ist ke<strong>in</strong>e direkte Zuweisung möglich.<br />

boolean 1 Bit Der boolschesche Datentyp umfaßt die Werte: true oder false<br />

(Defaultwert). Logische Vergleiche s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> vom Typ boolean.<br />

Auch boolesche Variablen s<strong>in</strong>d dem Datentyp boolean zugeordnet.<br />

Werte vom Typ boolean s<strong>in</strong>d zu allen anderen Datentypen<br />

<strong>in</strong>kompatibel und lassen sich nicht durch Cast<strong>in</strong>g <strong>in</strong> andere Typen<br />

überführen.<br />

Abb.: Primitive Datentypen der <strong>Java</strong>-Sprache<br />

106


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2.2.2 Operationen mit primitiven Datentypen<br />

Operationen mit booleschen Variablen<br />

Operation Name Bedeutung<br />

= Zuweisung E<strong>in</strong>er booleschen Variable wird der Wert true oder false<br />

zugewiesen<br />

== Gleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide boolesche<br />

Operanden denselben Wert (true oder false) haben.<br />

Anderenfalls wird false zurückgegeben.<br />

!= Ungleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide boolesche<br />

Operanden unterschiedliche Werte (true oder false) haben.<br />

Anderenfalls wird false zurückgeben.<br />

! Logisches NOT Falls der Operand false ist, wird true zurückgegeben<br />

& AND Rückgabewert ist true, falls beide Operanden true s<strong>in</strong>d<br />

| OR Rückgabewert ist false, falls beide Operanden false s<strong>in</strong>d.<br />

^ XOR Rückgabewert ist true, falls genau e<strong>in</strong> Operand true ist<br />

(exklusives Oder)<br />

&& Logisches AND Rückgabe von true nur dann, wenn die beiden Operanden<br />

true s<strong>in</strong>d.<br />

|| Logisches OR Rückgabe von false nur dann, wenn beide Operanden<br />

false s<strong>in</strong>d.<br />

?: if-then-else Diese Operation benötigt e<strong>in</strong>en booleschen Ausdruck vor dem<br />

Fragezeichen. Falls er true ist, wird der Wert vor dem<br />

Doppelpunkt zurückgegeben, ansonsten der Wert h<strong>in</strong>ter dem<br />

Doppelpunkt.<br />

Abb.: Operationen mit booleschen Variablen<br />

Operationen mit Zeichenvariablen<br />

Zeichenvariablen können Operanden <strong>in</strong> jeder ganzzahligen Operation se<strong>in</strong> und<br />

werden wie ganze 16-Bit-Zahlen ohne Vorzeichen behandelt.<br />

Operation Name Bedeutung<br />

= E<strong>in</strong>er Zeichenvariablen wird e<strong>in</strong> Wert zugewiesen<br />

== Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide Operanden<br />

denselben Wert (Unicode-Werte stimmen übere<strong>in</strong>) haben.<br />

Anderenfalls wird false zurückgegeben.<br />

!= Ungleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide boolesche<br />

Operanden unterschiedliche Werte ( Bezogen auf die<br />

Unicode-Darstellung) haben. Anderenfalls wird false<br />

zurückgeben<br />

= Relational Operatoren zum Vergleich <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

+,- Vorzeichen Vorzeichenoperatoren bei e<strong>in</strong>em Operanden<br />

+,-,*,/ B<strong>in</strong>äre Arithmetik Die Zeichenvariablen gehen <strong>in</strong> die Berechnung mit ihren<br />

Unicode-Werten e<strong>in</strong>.<br />

+=,-=,*=,/= Zuweisung Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Zuweisungen<br />

++,-- B<strong>in</strong>äre Arithmetik Inkrement- und Dekrement-Operatoren für den Unicode-Wert<br />

von Zeichenvariablen<br />

107


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

,>>> Verschiebung Bitweise Verschiebeoperatoren: Operatoren für bitweises<br />

Verschieben nach l<strong>in</strong>ks, für bitweises Verschieben nach rechts<br />

und für das bitweise Verschieben nach rechts mit Füllnullen.<br />

=, Verschiebung und Bitweise Verschiebungs- und Zuweisungsoperatoren (nach<br />

>>>= Zuweisung<br />

l<strong>in</strong>ks, nach rechts und nach rechts mit Füllnullen<br />

~ Bitweises NOT E<strong>in</strong>stellige bitweise Komplementbildung. Wenn e<strong>in</strong> Zeichen<br />

komplementiert wird, dann werden alle se<strong>in</strong>e Bits <strong>in</strong>vertiert.<br />

& Bitweises AND Falls AND mit 2 Zeichenvariablen benutzt wird und das<br />

Ergebnis <strong>in</strong> e<strong>in</strong>em dritten Zeichen abgelegt wird, dann hat das<br />

resultierende Zeichen nur für die Bits den E<strong>in</strong>trag 1, wenn alle<br />

beiden Operanden an der gleichen Stelle Bits mit dem Wert 1<br />

hatten<br />

| Bitweises OR Falls OR mit 2 Zeichenvariablen benutzt wird und das<br />

Ergebnis <strong>in</strong> e<strong>in</strong>em dritten Zeichen abgelegt wird, dann hat das<br />

resultierende Zeichen nur für die Bits den E<strong>in</strong>trag 1, wenn<br />

^ Bitweises exklusives<br />

OR<br />

e<strong>in</strong>er der Operanden an dieser Position e<strong>in</strong>e 1 hatte<br />

Falls XOR mit 2 Zeichenvariablen benutzt wird und das<br />

Resultat <strong>in</strong> e<strong>in</strong>em 3. Zeichen abgelegt wird, dann hat das<br />

resultierende Zeichen nur für die Bits den E<strong>in</strong>trag 1, wenn das<br />

zugehörige Bit <strong>in</strong> genau e<strong>in</strong>em der beiden Operanden gesetzt<br />

ist.<br />

&=,|=,^= Bitweise Zuweisung Bitweise AND-, OR-, exklusive OR (XOR)- und<br />

Zuweisungsoperatoren<br />

Abb.: Operationen mit Zeichenvariablen<br />

Operationen mit Gleitpunktzahlen<br />

Operation Name Bedeutung<br />

=,+=,-=,/= Zuweisung E<strong>in</strong>er Gleitpunktzahl wird e<strong>in</strong> Wert zugewiesen<br />

== Gleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide Operanden<br />

denselben Wert haben. Anderenfalls wird false<br />

zurückgegeben<br />

!= Ungleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide Operanden<br />

unterschiedliche Werte haben. Anderenfalls wird false<br />

zurückgeben<br />

= Relational Operatoren zum Vergleich <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur<br />

+,- Vorzeichen Vorzeichenoperatoren bei e<strong>in</strong>em Operanden<br />

+,-,*,/ B<strong>in</strong>äre Arithmetik Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Operatoren<br />

+=,-=,*=,/= Zuweisung Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Zuweisungen<br />

++,-- B<strong>in</strong>äre Arithmetik Inkrement- und Dekrementoperatoren für den Wert der<br />

Variablen.<br />

Abb.: Operationen mit den Typen float und double<br />

<strong>Java</strong> erzeugt ke<strong>in</strong>e Ausnahmen bei der Benutzung der Gleitpunktarithmetik. E<strong>in</strong><br />

Überlauf 92 oder das Teilen aller möglichen Zahlen (außer „Null durch Null“) führt zur<br />

Ausgabe von positiven bzw. negativen „unendlichen“ Werten. Das Teilen von „Null<br />

durch Null“ ergibt den Wert „NaN“ (ke<strong>in</strong>e Zahl). E<strong>in</strong> Unterlauf 93 gibt e<strong>in</strong>en speziellen<br />

92 d.h.: Größeres Ergebnis von e<strong>in</strong>er Operation als durch den Wertebereich des jeweiligen Typs ausgedrückt<br />

werden kann.<br />

93 d.h.: kle<strong>in</strong>eres Ergebnis (- außer Null -) von e<strong>in</strong>er Operation als durch den Wertebereich des jeweiligen Typs<br />

ausgedrückt werden kann.<br />

108


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Wert aus: „positiv oder negativ Null“. Dieser Wert kann mit Vergleichsoperatoren<br />

ausgewertet werden (bewirkt false).<br />

Operationen mit ganzzahligen Variablen (bzw. ganzzahligen Ausdrücken)<br />

Operation Name Bedeutung<br />

=,+=,-=,/= Zuweisung E<strong>in</strong>er ganzzahligen Variablen wird e<strong>in</strong> Wert zugewiesen<br />

== Gleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide Operanden<br />

denselben Wert haben. Anderenfalls wird false<br />

zurückgegeben<br />

!= Ungleichheit Durchführung e<strong>in</strong>es Vergleichs <strong>in</strong>nerhalb e<strong>in</strong>er Kontrollstruktur.<br />

Rückgabe ist true, wenn beide Operanden<br />

unterschiedliche Werte haben. Anderenfalls wird false<br />

zurückgeben<br />

= Relational Weitere Operatoren zum Vergleich <strong>in</strong>nerhalb e<strong>in</strong>er<br />

Kontrollstruktur<br />

+,- Vorzeichen Vorzeichenoperatoren bei e<strong>in</strong>em Operanden<br />

+,-,*,/ B<strong>in</strong>äre Arithmetik Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Operatoren<br />

+=,-=,*=,/= Zuweisung Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Zuweisungen<br />

++,-- B<strong>in</strong>äre Arithmetik Additions-, Subtraktions-, Multiplikations-, Divisions-<br />

Operatoren<br />

,>>> Bitweise Verschiebeoperatoren: Operatoren für bitweises<br />

Verschieben nach l<strong>in</strong>ks, für bitweises Verschieben nach rechts<br />

und für das bitweise Verschieben nach rechts mit Füllnullen<br />

=,<br />

Bitweise Verschiebungs- und Zuweisungsoperatoren (nach<br />

>>>=<br />

l<strong>in</strong>ks, nach rechts und nach rechts mit Füllnullen<br />

~ Bitweises NOT E<strong>in</strong>stellige bitweise Operation<br />

& Bitweises AND Falls AND mit 2 Ganzzahlen benutzt wird und das Ergebnis <strong>in</strong><br />

e<strong>in</strong>em dritten Ganzzahl abgelegt wird, dann hat die<br />

| Bitweises OR<br />

resultierende Ganzzahl nur für die Bits den E<strong>in</strong>trag 1, wenn<br />

alle beiden Operanden an der gleichen Stelle Bits mit dem<br />

Wert 1 hatten<br />

Falls OR mit 2 Ganzzahlen benutzt wird und das Ergebnis <strong>in</strong><br />

e<strong>in</strong>er dritten Ganzzahl abgelegt wird, dann hat die<br />

resultierende Ganzzahl nur für die Bits den E<strong>in</strong>trag 1, wenn<br />

^ Biweises exklusives<br />

OR<br />

e<strong>in</strong>er der Operanden an dieser Position e<strong>in</strong>e 1 hatte<br />

Falls XOR mit 2 Ganzzahlen benutzt wird und das Resultat <strong>in</strong><br />

e<strong>in</strong>er 3. Ganzzahl abgelegt wird, dann hat die resultierende<br />

Ganzzahl nur für die Bits den E<strong>in</strong>trag 1, wenn das zugehörige<br />

Bit <strong>in</strong> genau e<strong>in</strong>em der beiden Operanden gesetzt ist.<br />

&=,|=,^= Bitweise Zuweisung Inkrement- und Dekrementoperatoren für den Wert der<br />

Variablen<br />

Abb.: Operationen mit ganzzahligen Variablen<br />

Ganzzahlige Variable werden <strong>in</strong> <strong>Java</strong> als „Zweierkomplement“-Zahlen mit Vorzeichen<br />

verwendet.<br />

109


2.2.3 Datenfelder (Arrays)<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> Datenfeld (Array) ist e<strong>in</strong>e Ansammlung von Objekten e<strong>in</strong>es bestimmten Typs 1 ,<br />

die über e<strong>in</strong>en laufenden Index adressierbar s<strong>in</strong>d. Gegenüber „normalen Objekten“<br />

haben Arrays zwei wesentliche E<strong>in</strong>schränkungen:<br />

1. Arrays haben ke<strong>in</strong>e Konstruktoren. Statt dessen wird der Operator new mit spezieller Syntax<br />

aufgerufen.<br />

2. Es können ke<strong>in</strong>e Subklassen e<strong>in</strong>es Datenfelds def<strong>in</strong>iert werden.<br />

Datenfelder gehören zu den Referenzvariablen 1 . Arrays können jeden Wertetyp<br />

(primitiver Typ oder Objekt) enthalten, jedoch können <strong>in</strong> e<strong>in</strong>em Array ke<strong>in</strong>e<br />

unterschiedlichen Typen gespeichert werden.<br />

Arrays <strong>in</strong> <strong>Java</strong> s<strong>in</strong>d Objekte und unterscheiden sich von Datenfeldern <strong>in</strong> anderen<br />

Programmiersprachen durch folgende Merkmale:<br />

- Array-Variable s<strong>in</strong>d Referenzen<br />

- Arrays besitzen Methoden und Instanz-Variable<br />

- Arrays werden zur Laufzeit erzeugt<br />

2.2.3.1 Deklarieren, Erstellen von Array-Objekten<br />

In <strong>Java</strong> umfaßt das Erstellen e<strong>in</strong>es Datenfelds drei Schritte:<br />

1. Deklaration e<strong>in</strong>er Variablen zur Aufnahme e<strong>in</strong>es Datenfelds.<br />

Array-Variable zeigen den Objekttyp an, den das Datenfeld aufnimmt und den<br />

namen des Arrays, gefolgt von leeren eckigen Klammern „[]“, z.B: <strong>in</strong>t x[].<br />

Alternativ dazu kann e<strong>in</strong>e Array-Variable auch so (Klammern nach dem Typ)<br />

festgelegt se<strong>in</strong>, z.B. <strong>in</strong>t[] x.<br />

2. Erstellen e<strong>in</strong>es neuen Array-Objekts und Zuweisen e<strong>in</strong>er Array-Variablen.<br />

Das kann erfolgen<br />

- mit new, z.B. Str<strong>in</strong>g[] namen = new Str<strong>in</strong>g[10];<br />

Hier wird e<strong>in</strong> neues Datenfeld von Str<strong>in</strong>gs mit 10 Elementen erstellt. Beim Erstellen<br />

e<strong>in</strong>es Array-Objekts mit new ist anzugeben, wieviele Elemente das Array<br />

aufnehmen soll. Alle Elemente des Array werden automatisch <strong>in</strong>itialisiert (0 für<br />

numerische Datenfelder, false für boolesche, ‘\0‘ für Zeichen-Arrays und<br />

„null“ für alles andere.<br />

Bsp.: Erzeugen von Datenfeldern mit „new“<br />

a) Aufnahme von Werten primitiver Typen<br />

import java.util.*;<br />

public class FeldPrim<br />

{<br />

static Random rand = new Random();<br />

static <strong>in</strong>t zRand(<strong>in</strong>t mod)<br />

{<br />

return Math.abs(rand.nextInt()) % mod;<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

94 Es kann sich dabei um primitive Variablentypen (byte, char, short, <strong>in</strong>t, long, float, double, boolean), aber auch<br />

um andere Datenfelder (verschachtelte Arrays) oder Objekte handeln.<br />

95 Es gibt drei Arten von Referenzvariablen: Klassen, Schnittstellen und Datenfelder<br />

110


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

<strong>in</strong>t[] a;<br />

// Die Groesse des Array wird zur Laufzeit<br />

// zufaellig bestimmt<br />

a = new <strong>in</strong>t[zRand(20)];<br />

ausgabe("Laenge von a = " + a.length);<br />

for (<strong>in</strong>t i = 0; i < a.length; i++)<br />

ausgabe("a[" + i + "] = " + a[i]);<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

b) Aufnahme von Objekten<br />

E<strong>in</strong> Datenfeld, dessen Komponenten ke<strong>in</strong>e primitiven Typen aufnehmen<br />

sollen, muß immer mit „new“ gefüllt werden.<br />

import java.util.*;<br />

public class FeldObj<br />

{<br />

static Random rand = new Random();<br />

static <strong>in</strong>t zRand(<strong>in</strong>t mod)<br />

{<br />

return Math.abs(rand.nextInt()) % mod;<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

Integer[] a;<br />

// Die Groesse des Array wird zur Laufzeit<br />

// zufaellig bestimmt<br />

a = new Integer[zRand(20)];<br />

ausgabe("Laenge von a = " + a.length);<br />

for (<strong>in</strong>t i = 0; i < a.length; i++)<br />

{<br />

a[i] = new Integer(zRand(500));<br />

ausgabe("a[" + i + "] = " + a[i]);<br />

}<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

c) Variable Argumente<br />

Das zweite Format <strong>in</strong> der Feld<strong>in</strong>itialisierung bestimmt e<strong>in</strong>e bequeme<br />

syntaktische Form für den „Aufruf von Methoden“, die den gleichen Effekt<br />

besitzt wie die „Argumentenliste <strong>in</strong> C“. Über e<strong>in</strong>e solche Argumentenliste<br />

kann e<strong>in</strong>e unbekannte Menge von Argumenten e<strong>in</strong>es unbekannten Typs<br />

behandelt werden. Da alle Klassen von der Klasse Object abstammen,<br />

kann e<strong>in</strong>e Methode mit e<strong>in</strong>em Datenfeld als Argument verwendet werden,<br />

das aus Objekten vom Typ Object besteht, z.B.<br />

class A<br />

{<br />

<strong>in</strong>t i;<br />

}<br />

public class VarArgs<br />

{<br />

static void f(Object[] x)<br />

{<br />

111


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

for (<strong>in</strong>t i = 0; i < x.length; i++)<br />

System.out.pr<strong>in</strong>tln(x[i]);<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

f(new Object[] {<br />

new Integer(40), new VarArgs(),<br />

new Float(3.14), new Double(11.11)<br />

});<br />

f(new Object[] { "e<strong>in</strong>s", "zwei", "drei" });<br />

f(new Object[] { new A(), new A(), new A() });<br />

}<br />

}<br />

- durch direktes Initialisieren des Array-Inhalts, z.B.: Str<strong>in</strong>g[] namen =<br />

{“juergen“, “bernd“, “liesel“, “dieter“, “hans“, “vera“,<br />

“christian“, “theo“, “emil“, “karl“};<br />

Alle Elemente der <strong>in</strong> der geschweiften Klammer stehenden Elemente müssen vom<br />

gleichen Typ se<strong>in</strong><br />

3. Speichern von Elementen im Array<br />

Zur Speicherung e<strong>in</strong>es Werts <strong>in</strong> e<strong>in</strong>em Array, wird der Array-Ausdruck „subscript“<br />

benutzt, z.B.: x[subscript] . „subscript“ ist die Stelle (Position) für den Zugriff<br />

auf e<strong>in</strong>e Datenfeld-Element. Das Array-Subskript muß vom Typ <strong>in</strong>t se<strong>in</strong>. Wegen<br />

der vom Compiler vorgenommenen automatischen Typenkonvertierungen s<strong>in</strong>d auch<br />

short, byte, char zulässig. Indexausdrücke werden vom Laufzeitsystem auf<br />

E<strong>in</strong>haltung der Array-Grenzen überprüft.<br />

2.2.3.2 Zugriff auf Datenfeld-Elemente, Ändern von Datenfeld-Elementen<br />

Datenfeld-Subskripte beg<strong>in</strong>nen mit 0. Alle Array-Subskripte werden beim<br />

Kompilieren geprüft, ob sie sich <strong>in</strong>nerhalb der Grenzem des Array bef<strong>in</strong>den (Größer<br />

als 0, kle<strong>in</strong>er als die Länge des Datenfelds).<br />

Str<strong>in</strong>g ort[] = new Str<strong>in</strong>g[10];<br />

ort[10] = “D<strong>in</strong>kesbuehl“;<br />

ist falsch (Fehler beim Kompilieren). Das <strong>in</strong> „ort“ gespeicherte Array hat nur 10 ab 0<br />

numerierte Elemente.<br />

Wird das Array-Subskript zur Laufzeit berechnet und resultiert daraus e<strong>in</strong> Wert<br />

außerhalb der Array-Grenzen, dann erzeugt der <strong>Java</strong>-Interpreter e<strong>in</strong>en Fehler 96 . Die<br />

Länge e<strong>in</strong>es Datenfelds kann mit der Instanzvariablen length getestet werden, z.B.:<br />

<strong>in</strong>t laenge = ort.length;.<br />

Zum Zuweisen e<strong>in</strong>es Werts wird h<strong>in</strong>ter dem Zugriffsausdruck die<br />

Zuweisungsanweisung gestellt. Falls e<strong>in</strong>em Array-Element e<strong>in</strong> Wert zugewiesen<br />

wird, dann wird auf das betreffende Objekt e<strong>in</strong>e Referenz erzeugt. Datenfelder mit<br />

primitiven Typen (z.B. <strong>in</strong>t, float) kopieren die Werte von e<strong>in</strong>em Element <strong>in</strong> e<strong>in</strong><br />

anderes.<br />

96 Er weist auf e<strong>in</strong>e „Ausnahme“ h<strong>in</strong>.<br />

112


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2.2.3.3 Anwendungen mit e<strong>in</strong>dimensionaler Datenfeldern<br />

1. Sammeln<br />

Datenfelder s<strong>in</strong>d die wohl nützlichsten Objekte <strong>in</strong> <strong>Java</strong>, mit denen Objekte <strong>in</strong> leicht<br />

zugänglichen Listen gesammelt werden können.<br />

2. Suchen<br />

a) sequentielle Suche<br />

b) b<strong>in</strong>äre Suche<br />

3. Sortieren 97<br />

Aufgabenstellung: Schreibe e<strong>in</strong> Programm, das die <strong>in</strong> e<strong>in</strong>em Datenfeld („array“) gespeicherten ganzen<br />

Zahlen nach e<strong>in</strong>em e<strong>in</strong>fachen Sortierverfahren („Sortieren durch austauschen, Bubble Sort“) <strong>in</strong><br />

aufsteigende Sortierreihenfolge br<strong>in</strong>gt.<br />

Lösungsverfahren (Algorithmus): Man kann jeweils den ersten Schlüssel gegen alle weiteren Schlüssel<br />

im Arbeitsspeicherfeld vergleichen und so an der ersten Position den kle<strong>in</strong>sten Schlüssel nach (N-1)<br />

Vergleichen ermitteln. Danach vergleicht man jeweils den Schlüssel aus der zweiten Position mit allen<br />

nachfolgenden Schlüsslwerten. Nach (N-2) Vergleichen steht der zweitkle<strong>in</strong>ste Sachlüssel an der<br />

zweiten Position. Bei Fortsetzung dieser Verfahrensweise ist schließlich nur noch e<strong>in</strong> e<strong>in</strong>ziger<br />

Schlüssel vorhanden, der dann auf der richtigen, der letzten Position steht.<br />

Bsp.:<br />

1 2 3 4<br />

37 22 18 9 9 9 9 9 9 9 9<br />

22 37 37 37 37 22 18 18 18 18 18<br />

18 18 22 22 22 37 37 37 22 22 22<br />

9 9 9 18 18 18 22 22 37 37 25<br />

25 25 25 25 25 25 25 25 25 25 37<br />

Abb.: Tabelle mit 5 Schlüsseln zur Demonstration des Bubble-Sort<br />

97 PR22301<br />

113


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Vorschlag für die Implementierung:<br />

import java.util.*;<br />

class BubbleSort<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

<strong>in</strong>t[] x;<br />

x = new <strong>in</strong>t[10];<br />

Random zufallsZahl = new Random();<br />

// Initialisieren des Array x<br />

for (<strong>in</strong>t i = 0; i < 10; i++)<br />

{<br />

x[i] = zufallsZahl.nextInt();<br />

}<br />

// Ausgabe des noch nicht sortierten x<br />

System.out.pr<strong>in</strong>tln("Vor dem Sortieren:");<br />

for (<strong>in</strong>t i = 0; i < 10; i++)<br />

{<br />

System.out.pr<strong>in</strong>tln("x["+i+"] = " + x[i]);<br />

}<br />

boolean sortiert = false;<br />

// Sortiere das Feld x<br />

while (!sortiert)<br />

{<br />

sortiert = true;<br />

for (<strong>in</strong>t i=0; i < 9; i++)<br />

{<br />

if (x[i] > x[i+1])<br />

{<br />

<strong>in</strong>t temp = x[i];<br />

x[i] = x[i+1];<br />

x[i+1] = temp;<br />

sortiert = false;<br />

}<br />

}<br />

}<br />

// Gib das sortierte Feld x aus<br />

System.out.pr<strong>in</strong>tln();<br />

System.out.pr<strong>in</strong>tln("Nach dem Sortieren:");<br />

for (<strong>in</strong>t i = 0; i < 10; i++) {<br />

System.out.pr<strong>in</strong>tln("x["+i+"] = " + x[i]);<br />

}<br />

}<br />

}<br />

114


2.2.3.4 Mehrdimensionale Datenfelder<br />

Zweidimensionale Datenfelder<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> zweidimensionale Feld entspricht e<strong>in</strong>er zweidimensionalen Wertetabelle, z.B.:<br />

S0 S1 S2 S3<br />

Z0 1 2 3 4<br />

Z1 1 2 3 4<br />

Z2 1 2 3 4<br />

Z3 1 2 3 4<br />

Z4 1 2 3 4<br />

Das vorliegende Datenfeld umfaßt 4 Zeilen und 3 Spalten. E<strong>in</strong> Datenfeld „M“ mit 4<br />

Zeilen und 5 Spalten ist folgendermaßen aufgebaut.<br />

M[0][0] M[0][1] M[0][2] M[0][3] M[0][4]<br />

M[1][0] M[1][1] M[1][2] M[1][3] M[1][4]<br />

M[2][0] M[2][1] M[2][2] M[2][3] M[2][4]<br />

M[3][0] M[3][1] M[3][2] M[3][3] M[3][4]<br />

Zweidimensionale Datenfelder werden, wie das folgende Beispiel zeigt, auf gleiche<br />

Weise erstellt und <strong>in</strong>itialisiert wie e<strong>in</strong>dimensionale Felder.<br />

class E<strong>in</strong>heitsmatrix<br />

{<br />

publich static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

double[][] EM;<br />

EM = new double[4][4];<br />

for (<strong>in</strong>t zeile = 0; zeile < 4; zeile++)<br />

{<br />

for (<strong>in</strong>t spalte = 0; spalte < 4; spalte++)<br />

{<br />

if (zeile != spalte)<br />

{<br />

EM[zeile][spalte] = 0.0;<br />

}<br />

else {<br />

EM[zeile][spalte] = 1.0;<br />

}<br />

}<br />

}<br />

}<br />

}<br />

115


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Da mehrdimensionale Arrays als geschachtelte Arrays gespeichert werden, ist es<br />

möglich, „nicht-rechteckige“ Arrays zu erzeugen, z.B.:<br />

public class Ke<strong>in</strong>RechteckFeld<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

<strong>in</strong>t a[][] = { {0},<br />

{1,2},<br />

{3,4,5},<br />

{6,7,8,9}<br />

};<br />

for (<strong>in</strong>t i = 0; i < a.length; i++)<br />

{<br />

for (<strong>in</strong>t j = 0; j < a[i].length; j++)<br />

{<br />

System.out.pr<strong>in</strong>t(a[i][j] + " ");<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

}<br />

}<br />

Bsp.: Das 8-Damen-Problem 98<br />

Aufgabenstellung: Acht Damen sollen so auf e<strong>in</strong>em Schachbrett positioniert werden, daß sie sich nicht<br />

schlagen können, d.h.: Zwei Damen stehen nie <strong>in</strong> derselben Zeile oder Spalte oder Diagonale.<br />

Algorithmus zur Lösung: Zu Beg<strong>in</strong>n wird e<strong>in</strong> zweidimensionales Feld mit 0 gefüllt.<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

Danach wird zufällig im zweidimensionalen Feld e<strong>in</strong>e „Dame“ gesetzt. Das Setzen der Dame wird<br />

durch e<strong>in</strong>e 9 markiert.<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 9 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

0 0 0 0 0 0 0 0<br />

98 vgl. PR22305<br />

116


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Durch das Positionieren der Dame s<strong>in</strong>d Positionierungen von weiteren Damen <strong>in</strong> derselben Zeile und<br />

Spalte wie die soeben positionierte Dame, aber auch <strong>in</strong> den zugehörigen Diagonalen nicht erlaubt. Die<br />

nicht mehr zulässigen Positionen werden mit 1 markiert.<br />

1 0 0 1 0 0 1 0<br />

0 1 0 1 0 1 0 0<br />

0 0 1 1 1 0 0 0<br />

1 1 1 9 1 1 1 1<br />

0 0 1 1 1 0 0 0<br />

0 1 0 1 0 1 0 0<br />

1 0 0 1 0 0 1 0<br />

0 0 0 1 0 0 0 1<br />

Damen dürfen jetzt nur noch auf die mit 0 markierten Komponenten des zweidimensionalen Felds<br />

gebracht werden. Das geschieht solange bis alle Komponenten des zweidimensionalen Felds mit 1<br />

oder 9 gefüllt s<strong>in</strong>d. Wurden beim Füllen des Felds <strong>in</strong>sgesamt 8 Damen positioniert, dann wurde e<strong>in</strong>e<br />

Lösung erreicht, die so aussehen könnte:<br />

1 1 1 1 1 1 9 1<br />

1 9 1 1 1 1 1 1<br />

1 1 1 1 1 9 1 1<br />

1 1 9 1 1 1 1 1<br />

9 1 1 1 1 1 1 1<br />

1 1 1 9 1 1 1 1<br />

1 1 1 1 1 1 1 9<br />

1 1 1 1 9 1 9 1<br />

Vorschlag zur Implementierung:<br />

import java.util.*;<br />

public class Damen<br />

{<br />

// Konstanten<br />

f<strong>in</strong>al <strong>in</strong>t N = 8;<br />

// Variable<br />

boolean fuellen;<br />

boolean ausgeben;<br />

Random rand = new Random();<br />

<strong>in</strong>t zeile, spalte;<br />

<strong>in</strong>t[][] brett;<br />

<strong>in</strong>t aktZahl = 0;<br />

<strong>in</strong>t[] positionen = new <strong>in</strong>t[N];<br />

// Methoden<br />

<strong>in</strong>t zRand(<strong>in</strong>t mod)<br />

{<br />

return Math.abs(rand.nextInt() % mod);<br />

}<br />

public void <strong>in</strong>itialisiere()<br />

{<br />

fuellen = false;<br />

ausgeben = false;<br />

aktZahl = 0;<br />

brett = new <strong>in</strong>t[N][N];<br />

for (<strong>in</strong>t i = 0; i < N; i++)<br />

for (<strong>in</strong>t j = 0; j < N; j++)<br />

{<br />

brett[i][j] = 0;<br />

}<br />

}<br />

public void nimmPosition()<br />

{<br />

do {<br />

zeile = zRand(N);<br />

// System.out.pr<strong>in</strong>tln(zeile);<br />

117


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

spalte = zRand(N);<br />

// System.out.pr<strong>in</strong>tln(spalte);<br />

} while (brett[zeile][spalte] != 0);<br />

brett[zeile][spalte] = 9;<br />

aktZahl++;<br />

}<br />

public void bewertePosition()<br />

{<br />

for (<strong>in</strong>t i = 0; i < 8; i++)<br />

{<br />

if (i != spalte) brett[zeile][i] = 1;<br />

}<br />

for (<strong>in</strong>t i = 0; i < 8; i++)<br />

{<br />

if (i != zeile) brett[i][spalte] = 1;<br />

}<br />

<strong>in</strong>t lDzeile = zeile;<br />

<strong>in</strong>t lDspalte = spalte;<br />

// Beruecksichtigung der nach l<strong>in</strong>ks laufenden Diagonale<br />

while ((lDzeile > 0) && (lDspalte > 0))<br />

{<br />

lDzeile--;<br />

lDspalte--;<br />

}<br />

do {<br />

if ((lDzeile != zeile) && (lDspalte != spalte))<br />

{<br />

brett[lDzeile][lDspalte] = 1;<br />

}<br />

lDzeile++;<br />

lDspalte++;<br />

} while ((lDzeile < 8) && (lDspalte < 8));<br />

// ausgabe();<br />

<strong>in</strong>t rDzeile = zeile;<br />

<strong>in</strong>t rDspalte = spalte;<br />

// Beruecksichtiung der nach rechts laufenden Diagonale<br />

while ((rDzeile > 0) && (rDspalte < 7))<br />

{<br />

rDzeile--;<br />

rDspalte++;<br />

}<br />

do {<br />

if ((rDzeile != zeile) && (rDspalte != spalte))<br />

{<br />

brett[rDzeile][rDspalte] = 1;<br />

}<br />

rDzeile++;<br />

rDspalte--;<br />

} while ((rDzeile < 8) && (rDspalte >= 0));<br />

}<br />

public void pruefe()<br />

{<br />

<strong>in</strong>t nullen = 0;<br />

<strong>in</strong>t anzDamen = 0;<br />

for (<strong>in</strong>t i = 0; i < 8; i++)<br />

for (<strong>in</strong>t j = 0; j < 8; j++)<br />

{<br />

if (brett[i][j] == 0) nullen++;<br />

if (brett[i][j] == 9) anzDamen++;<br />

}<br />

if (nullen == 0) fuellen = true;<br />

if (anzDamen == 8) ausgeben = true;<br />

}<br />

public void ausgabe()<br />

{<br />

System.out.pr<strong>in</strong>tln();<br />

for (<strong>in</strong>t i = 0; i < 8; i++)<br />

118


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

for (<strong>in</strong>t j = 0; j < 8; j++)<br />

{<br />

System.out.pr<strong>in</strong>t(brett[i][j] + " ");<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

<strong>in</strong>t k = 0;<br />

for (<strong>in</strong>t i = 0; i < brett.length; i++)<br />

for (<strong>in</strong>t j = 0; j < brett[i].length; j++)<br />

{<br />

if (brett[i][j] == 9) positionen[k++] = j;<br />

}<br />

for (k = 0; k < N; k++)<br />

System.out.pr<strong>in</strong>t(positionen[k]+" ");<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

public void erzeugeDamen()<br />

{<br />

do<br />

{<br />

<strong>in</strong>itialisiere();<br />

do {<br />

nimmPosition();<br />

// ausgabe();<br />

bewertePosition();<br />

// ausgabe();<br />

if (aktZahl > 4) pruefe();<br />

} while (!fuellen);<br />

} while (!ausgeben);<br />

ausgabe();<br />

}<br />

}<br />

public class Damentest<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Damen d = new Damen();<br />

d.erzeugeDamen();<br />

}<br />

}<br />

Multdimensionale Datenfelder<br />

Zweidimensionale Datenfelder bilden nicht das Ende. <strong>Java</strong> kann Felder mit 3, 4 oder<br />

mehr Dimensionen unterstützen. Es handelt sich dabei allerd<strong>in</strong>gs um e<strong>in</strong> Array mit<br />

Arrays (die wiederum Arrays enthalten können usw. über beliebig viele<br />

Dimensionen) 99 .<br />

Bsp.: Mehrdimensionale Felder<br />

import java.util.*;<br />

public class MehrdimFeld<br />

{<br />

static Random rand = new Random();<br />

static <strong>in</strong>t zRand(<strong>in</strong>t mod)<br />

{<br />

return Math.abs(rand.nextInt()) % mod;<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

// 1. Bsp: Erzeugen e<strong>in</strong>es mehrdimensionalen Felds<br />

99 Im <strong>Java</strong> werden multidimensionale Arrays streng genommen nicht unterstützt<br />

119


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

// mit Werten primitiver Typen<br />

<strong>in</strong>t[][] a1 = {<br />

{ 1, 2, 3, },<br />

{ 4, 5, 6, },<br />

};<br />

for (<strong>in</strong>t i = 0; i < a1.length; i++)<br />

for (<strong>in</strong>t j = 0; j < a1[i].length; j++)<br />

ausgabe("a1[" + i + "][" + j + "] = " + a1[i][j]);<br />

// 2. Bsp.: Dreidimensionales Feld mit fester Laenge<br />

<strong>in</strong>t[][][] a2 = new <strong>in</strong>t[2][2][4];<br />

for (<strong>in</strong>t i = 0; i < a2.length; i++)<br />

for (<strong>in</strong>t j = 0; j < a2[i].length; j++)<br />

for (<strong>in</strong>t k = 0; k < a2[i][j].length;k++)<br />

ausgabe("a2[" + i + "][" + j + "][" + k + "] = "<br />

+ a2[i][j][k]);<br />

// 3. Bsp.: Dreidimensionales Feld mit variablen Laengen<br />

<strong>in</strong>t[][][] a3 = new <strong>in</strong>t[zRand(7)][][];<br />

for (<strong>in</strong>t i = 0; i < a3.length; i++)<br />

{<br />

a3[i] = new <strong>in</strong>t[zRand(5)][];<br />

for (<strong>in</strong>t j = 0; j < a3[i].length; j++)<br />

{<br />

a3[i][j] = new <strong>in</strong>t[zRand(5)];<br />

}<br />

}<br />

for (<strong>in</strong>t i = 0; i < a3.length; i++)<br />

for (<strong>in</strong>t j = 0; j < a3[i].length; j++)<br />

for (<strong>in</strong>t k = 0; k < a3[i][j].length;k++)<br />

ausgabe("a3[" + i + "][" + j + "][" + k + "] = "<br />

+ a3[i][j][k]);<br />

// Mehrdimensionales Feld mit nicht primitiven Objekten<br />

Integer[][] a4 = {<br />

{ new Integer(1), new Integer(2) },<br />

{ new Integer(3), new Integer(4) },<br />

{ new Integer(5), new Integer(6) },<br />

};<br />

for (<strong>in</strong>t i = 0; i < a4.length; i++)<br />

for (<strong>in</strong>t j = 0; j < a4[i].length; j++)<br />

ausgabe("a4[" + i + "][" + j + "] = " + a4[i][j]);<br />

// Array mit nicht primitiven Objekten der stueckweise<br />

// aufgebaut wird<br />

Integer[][] a5;<br />

a5 = new Integer[3][];<br />

for (<strong>in</strong>t i = 0; i < a5.length; i++)<br />

{<br />

a5[i] = new Integer[3];<br />

for (<strong>in</strong>t j = 0; j < a5[i].length; j++)<br />

a5[i][j] = new Integer(i * j);<br />

}<br />

for (<strong>in</strong>t i = 0; i < a5.length; i++)<br />

for (<strong>in</strong>t j = 0; j < a5[i].length; j++)<br />

ausgabe("a5[" + i + "][" + j + "] = " + a5[i][j]);<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

120


2.2.3.5 Die Klasse Arrays<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Seit dem JDK1.2 gibt es die Klasse Arrays um Paket java.util mit nützlichen<br />

Methoden zum Zugriff auf Arrays:<br />

public static void fill(<strong>in</strong>t[] a, <strong>in</strong>t wert)<br />

public static void b<strong>in</strong>arySearch(<strong>in</strong>t[] a, <strong>in</strong>t schl)<br />

public static void sort(<strong>in</strong>t[] a)<br />

public static boolean equals(<strong>in</strong>t[] a1, <strong>in</strong>t [] a2)<br />

121


2.3 Ausdrücke<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> Ausdruck ist das Ergebnis e<strong>in</strong>er Verknüpfung von Operanden und Operatoren<br />

nach den syntaktischen Regeln der Sprache. Ausdrücke werden üblicherweise zur<br />

Durchführung von Operationen (Manipulationen) an Variablen oder Werten<br />

verwendet.<br />

Ausdrücke gehören zu den kle<strong>in</strong>sten ausführbaren E<strong>in</strong>heiten e<strong>in</strong>es Programms. Sie<br />

dienen zur Verzuweisung an Variable, zur Durchführung numerischer berechnungen<br />

und zur Formulierung logischer Bed<strong>in</strong>gungen.<br />

E<strong>in</strong> Ausdruck besteht immer aus m<strong>in</strong>destens e<strong>in</strong>em Operanden, auf dem der<br />

Operator angewandt wird. Nach dem Typ der Operanden unterscheidet man<br />

numerische, relationale, logische, bitweise Operatoren. Jeder Ausdruck hat e<strong>in</strong>en<br />

Rückgabewert, der durch die Anwendung des Operators auf die Operanden entsteht.<br />

Der Typ des Rückgabewerts bestimmt sich aus den Typen der Operanden und der<br />

Art des verwendeten Operators.<br />

2.3.1 Arithmetische Ausdrücke<br />

Jede Programmiersprache hat e<strong>in</strong>en Mechanismus für arithmetische Berechnungen.<br />

In <strong>Java</strong> werden solche Berechnungen <strong>in</strong> arithmetischen Ausdrücken durchgeführt.<br />

2.3.2 Bewertung von Ausdrücken<br />

Bei der Bewertung von Ausdrücken spielen Operatorassoziativität, Operatorvorrang<br />

und Bewertungsreihenfolge e<strong>in</strong>e Rolle.<br />

Operatorassoziativität<br />

Alle arithmetischen Operatoren assoziieren von l<strong>in</strong>ks nach rechts, d.h.: Falls<br />

derselbe Operator <strong>in</strong> e<strong>in</strong>em Ausdruck mehr als e<strong>in</strong>mal vorkommt, dann wird der am<br />

weitesten l<strong>in</strong>ks stehende zuerst bewertet, gefolgt von dem rechts daneben<br />

stehenden, usw. Die Assoziativitätsregel bestimmt, wie Komb<strong>in</strong>ationen des gleichen<br />

Operators bewertet werden können.<br />

Priorität<br />

<strong>Java</strong> hält sich, wie die grundlegende Arithmetik, strikt an die Reglen der<br />

Vorrangigkeit. Die multiplikativen Operatoren (*, / und %) haben Vorrang vor den<br />

additiven Operatoren (+ und -). Immer wenn die Bewertungsreihenfolge von<br />

Operatoren <strong>in</strong> e<strong>in</strong>em Ausdruck geändert werden soll, müssen Klammern benutzt<br />

werden. Jeder Ausdruck <strong>in</strong> Klammern wird zuerst bewertet. Der Vorrang der<br />

e<strong>in</strong>stelligen arithmetischen Operatoren steht über allen anderen arithmetischen<br />

Operatoren.<br />

122


Bewertungsreihenfolge<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Vorrangregeln helfen bei der Bewertung, welche Operatoren <strong>in</strong> e<strong>in</strong>em Ausdruck<br />

zuerst benutzt werden und welche Operanden zu welchen Operatoren gehören. Die<br />

Regeln für die Bewertungsreihenfolge helfen festzulegen, wann welche Operanden<br />

bewertet werden. Die drei folgenden Regeln bestimmen, wie e<strong>in</strong> Ausdruck bewertet<br />

wird:<br />

- Bei allen b<strong>in</strong>ären Operatoren wird der l<strong>in</strong>ke Operand vor dem rechten bewertet.<br />

- Zuerst werden die Operanden, danach die Operatoren bewertet.<br />

- Falls mehrere Parameter, die durch Kommata vone<strong>in</strong>ander getrennt s<strong>in</strong>d, durch e<strong>in</strong>en<br />

Methodenaufruf zur Verfügung gestellt werden, werden diese Parameter von l<strong>in</strong>ks nach rechts<br />

bewertet.<br />

2.3.3 Typkonvertierungen<br />

<strong>Java</strong> ist e<strong>in</strong>e typisierte Sprache. Es f<strong>in</strong>den gründliche Typüberprüfungen statt, und es<br />

gelten strikte Beschränkungen für die Konvertierung von Werten e<strong>in</strong>es Typs zu<br />

e<strong>in</strong>em anderen. Unter „Cast<strong>in</strong>g“ versteht man die Umwandlung von e<strong>in</strong>em Datentyp<br />

<strong>in</strong> e<strong>in</strong>en anderen.<br />

<strong>Java</strong> unterstützt explizite Konvertierungen und „ad hoc“-Konvertierungen.<br />

Ad-hoc-Konvertierungen. Hier gibt es folgende Regeln für numerische Datentypen:<br />

- Bei Operationen mit ausschl. ganzzahligen Operanden wird, falls e<strong>in</strong>er der beiden Operanden den<br />

Datentyp long hat, der andere ebenfalls zu long konvertiert; ansonsten werden beide Operanden<br />

zu <strong>in</strong>t konvertiert. Das Ergebnis ist dann ebenfalls vom Typ <strong>in</strong>t. Ist allerd<strong>in</strong>gs der ausgegebene<br />

Wert zu groß, um im Wertebereich von <strong>in</strong>t dargestellt zu werden, wird der Typ long verwendet.<br />

- Bei Operationen mit wenigstens e<strong>in</strong>em Gleitpunkt-Operanden wird, wenn e<strong>in</strong>er der Operanden den<br />

Datentyp double hat, der andere ebenfalls zu double konvertiert. Das Ergebnis ist dann ebenfalls<br />

vom Datentyp double, anderenfalls werden beide Operanden zum Datentyp float konvertiert.<br />

Das Ergebnis ist ebenfalls vom Typ float.<br />

Explizite Konvertierungen. Sie s<strong>in</strong>d immer nötig, wenn e<strong>in</strong>e Umwandlung <strong>in</strong> e<strong>in</strong>en<br />

anderen Datentyp gewünscht wird und diese nicht „ad hoc“ e<strong>in</strong>tritt. „Cast<strong>in</strong>g“ muß<br />

dann angewendet werden. Der zugehörige (Festlegungs-)Operator besteht aus<br />

e<strong>in</strong>em Typnamen <strong>in</strong> runden Klammern. Er ist e<strong>in</strong> e<strong>in</strong>stelliger Operator mit hoher<br />

Priorität und steht vor se<strong>in</strong>en Operanden. Er hat immer die folgende Form:<br />

„(Datentyp) Wert“. Der (Festlegungs-)Operator bestimmt den Wert se<strong>in</strong>es<br />

Operanden, der auf den <strong>in</strong> Klammern bezeichneten Typ festgelegt wird. Es gibt<br />

folgende Cast<strong>in</strong>g-Operatoren:<br />

Operator Beispiel Erläuterung<br />

(byte) (byte) (x/y) Wandelt das Errgebnis von x/y <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp byte<br />

um<br />

(short) (short) x Wandelt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp short um<br />

(<strong>in</strong>t) (<strong>in</strong>t) (x/y) Wandelt das Ergebnis von x/y <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp <strong>in</strong>t<br />

(long) (long) x Wandelt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp long um<br />

(float) (float) x Wandelt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp float um<br />

(double) (double) x Wandelt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp double um<br />

(char) (char) x Wandelt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp char um<br />

(boolean) (boolean) 0 Wandelt 0 <strong>in</strong> e<strong>in</strong>en booleschen Datentyp um<br />

123


Abb.: Cast<strong>in</strong>g-Operatoren<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Cast<strong>in</strong>g hat e<strong>in</strong>e höhere Priorität als Arithmetik. Deshalb müssen arithmetische<br />

Operationen <strong>in</strong> Verb<strong>in</strong>dung mit Cast<strong>in</strong>g <strong>in</strong> Klammern gesetzt werden<br />

Nicht alle Konvertierungen s<strong>in</strong>d möglich. Variable e<strong>in</strong>es arithmetischen Typs können<br />

auf jeden anderen arithmetischen Typ festgelegt werden. Boolesche Werte können<br />

nicht auf irgende<strong>in</strong>en anderen Wert festgelegt werden. Die Umkehrung funktioniert<br />

mit E<strong>in</strong>schränkungen: 0 und 1 lassen sich <strong>in</strong> boolesche Werte konvertieren.<br />

Bsp. 100 : Konvertieren primitiver Typen<br />

public class KonvPrim<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

char z = ’a’;<br />

System.out.pr<strong>in</strong>tln("char z = ’" + z + ’\’’);<br />

System.out.pr<strong>in</strong>tln("Unicode von z: " + (<strong>in</strong>t) z);<br />

<strong>in</strong>t i = 17;<br />

System.out.pr<strong>in</strong>tln("<strong>in</strong>t i = " + i);<br />

long l = 4L;<br />

System.out.pr<strong>in</strong>tln("long l = " + l);<br />

double d = 17.3;<br />

System.out.pr<strong>in</strong>tln("double d = " + d);<br />

float f = 4.5F;<br />

System.out.pr<strong>in</strong>tln("float f = " + f);<br />

double sd;<br />

float sf;<br />

long sl;<br />

<strong>in</strong>t si;<br />

sd = i + l + d + f;<br />

System.out.pr<strong>in</strong>tln("sd = i + l + d + f = " + sd);<br />

// sf = i + l + d + f;<br />

/* Inkompatibler Typ! */<br />

// System.out.pr<strong>in</strong>tln("sf = i + l + d + f = " + sf);<br />

sf = (float) (i + l + d + f);<br />

// sl = i + l + d + f;<br />

/* Inkompatibler Typ! */<br />

// System.out.pr<strong>in</strong>tln("sl = i + l + d + f = " + sl);<br />

sl = i + l + (long) d + (long) f;<br />

System.out.pr<strong>in</strong>tln("sl = l + i + (long) d + (long) f = " + sl);<br />

sl = (long) (i + l + d + f);<br />

System.out.pr<strong>in</strong>tln("sl = (long) (i + l + d + f) = " + sl);<br />

// si = i + l + d + f;<br />

/* Inkompatibler Typ! */<br />

// System.out.pr<strong>in</strong>tln("si = i + l + d + f = " + si);<br />

si = i + (<strong>in</strong>t) l + (<strong>in</strong>t) d + (<strong>in</strong>t) f;<br />

System.out.pr<strong>in</strong>tln("sl = l + (<strong>in</strong>t) i + (<strong>in</strong>t) d + (<strong>in</strong>t) f = " + sl);<br />

si = (<strong>in</strong>t) (i + l + d + f);<br />

System.out.pr<strong>in</strong>tln("sl = (<strong>in</strong>t) (i + l + d + f) = " + si);<br />

}<br />

}<br />

Konvertieren von Objekten. Mit E<strong>in</strong>schränkungen lassen sich Klassen<strong>in</strong>stanzen <strong>in</strong><br />

Instanzen anderer Klassen konvertieren. Die Klassen müssen allerd<strong>in</strong>gs durch<br />

Vererbung mite<strong>in</strong>ander verbunden se<strong>in</strong>. Allgeme<strong>in</strong> gilt: E<strong>in</strong> Objekt e<strong>in</strong>er Klasse kann<br />

auf se<strong>in</strong>e Superklasse festgelegt werden. Spezifische Informationen der Subklasse<br />

gehen dabei verloren. Das Konvertieren erfolgt immer nach folgender Form:<br />

(Klassenname) Objekt.<br />

Bsp. 101 : Konvertieren Datentyp Object<br />

100 vgl. PR23301<br />

124


import java.applet.Applet;<br />

import java.awt.*;<br />

import java.util.Vector;<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class MittleresDrittel extends Applet<br />

{<br />

<strong>in</strong>t appletHoehe;<br />

<strong>in</strong>t appletBreite;<br />

Vector endpunkt = new Vector();<br />

public void <strong>in</strong>it()<br />

{<br />

Dimension d = getSize();<br />

appletHoehe = d.height - 1;<br />

appletBreite = d.width - 1;<br />

// Anhaengen an Liste<br />

endpunkt.addElement(new Float(0.0f));<br />

endpunkt.addElement(new Float(1.0f));<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

float x1, x2;<br />

Float tempFloat;<br />

g.setColor(Color.yellow);<br />

g.fillRect(0,0,appletBreite,appletHoehe);<br />

g.setColor(Color.black);<br />

for (<strong>in</strong>t i = 0; i < appletHoehe; i+=5)<br />

{<br />

// Zeichne die L<strong>in</strong>ien<br />

for (<strong>in</strong>t j = 0; j < endpunkt.size(); j+=2)<br />

{<br />

tempFloat = (Float) endpunkt.elementAt(j);<br />

x1 = tempFloat.floatValue();<br />

tempFloat = (Float) endpunkt.elementAt(j+1);<br />

x2 = tempFloat.floatValue();<br />

g.drawL<strong>in</strong>e(Math.round(x1 * appletBreite),i,<br />

Math.round(x2 * appletBreite),i);<br />

}<br />

// Entferne das mittlere Drittel aus den L<strong>in</strong>ien<br />

schneideausSegment();<br />

tempFloat = (Float) endpunkt.elementAt(0);<br />

x1 = tempFloat.floatValue();<br />

System.out.pr<strong>in</strong>tln(x1);<br />

tempFloat = (Float) endpunkt.elementAt(1);<br />

x2 = tempFloat.floatValue();<br />

System.out.pr<strong>in</strong>tln(x2);<br />

if (Math.round(x1*appletBreite) ==<br />

Math.round(x2*appletBreite)) break;<br />

}<br />

}<br />

public void schneideausSegment()<br />

{<br />

<strong>in</strong>t <strong>in</strong>dex = 0;<br />

float luecke;<br />

Float tempFloat1, tempFloat2;<br />

<strong>in</strong>t stop = endpunkt.size();<br />

for (<strong>in</strong>t i = 0; i < stop; i += 2)<br />

{<br />

schneideausMittleresDrittel(<strong>in</strong>dex,<strong>in</strong>dex+1);<br />

<strong>in</strong>dex += 4;<br />

}<br />

}<br />

public void schneideausMittleresDrittel(<strong>in</strong>t l<strong>in</strong>ks, <strong>in</strong>t rechts)<br />

{<br />

float luecke;<br />

101 PR23302<br />

125


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

float x1, x2;<br />

Float tempFloat1, tempFloat2;<br />

// Zugriff an der angegebenen Position<br />

tempFloat1 = (Float) endpunkt.elementAt(l<strong>in</strong>ks);<br />

tempFloat2 = (Float) endpunkt.elementAt(rechts);<br />

luecke = tempFloat2.floatValue() - tempFloat1.floatValue();<br />

x1 = tempFloat1.floatValue() + luecke/3.0f;<br />

x2 = tempFloat2.floatValue() - luecke/3.0f;<br />

// E<strong>in</strong>fuegen an der angegebenen Stelle <strong>in</strong> der Liste<br />

endpunkt.<strong>in</strong>sertElementAt(new Float(x2),rechts);<br />

endpunkt.<strong>in</strong>sertElementAt(new Float(x1),rechts);<br />

}<br />

}<br />

2.3.4 Vergleichsoperatoren<br />

<strong>Java</strong> hat e<strong>in</strong>e Menge von Operatoren für das Vergleichen von zwei oder mehr<br />

Größen. Diese Operatoren lassen sich aufteilen <strong>in</strong><br />

- relationale Operatoren. Sie s<strong>in</strong>d zum Ordnen von Größen bestimmt, ob etwa e<strong>in</strong> Wert größer oder<br />

kle<strong>in</strong>er als e<strong>in</strong> anderer ist.<br />

- Gleichheitsoperatoren. Sie sagen nur aus, ob zwei Werte gleich s<strong>in</strong>d<br />

2.3.5 Logische Ausdrücke<br />

Logische Operationen können auf zwei verschiedene Arten ausgeführt werden:<br />

- Short-turn-Operatoren (logisches AND && und logisches OR ||). Sie operieren nur mit booleschen Variablen.<br />

- Bitweise Operatoren. Sie operieren mit jedem Bit zweier ganzzahliger Operanden.<br />

126


2.4 Anweisungen<br />

2.4.1 Blöcke und Anweisungen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Methoden und statische Initialisatoren werden <strong>in</strong> <strong>Java</strong> durch Anweisungsblöcke<br />

def<strong>in</strong>iert. E<strong>in</strong> Anweisungsblock besteht <strong>in</strong> der Regel aus e<strong>in</strong>er Reihe von<br />

Anweisungen, die <strong>in</strong> geschweiften Klammern stehen. Das bedeutet: Es können <strong>in</strong><br />

diesem Block lokale Variablen deklariert werden, die außerhalb des Blocks nicht<br />

verfügbar s<strong>in</strong>d, und deren Existenz erlischt, wenn der Block ausgeführt wurde.<br />

2.4.2 Leere Anweisungen<br />

In <strong>Java</strong> können leere Anweisungen erstellt werden. Für den Compiler sieht e<strong>in</strong>e leere<br />

Anweisung nur wie e<strong>in</strong> zusätzliches Semikolon aus.<br />

2.4.3 Benannte Anweisungen<br />

Jede Anweisung darf <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e „Benennung“ haben. Die „Benennung“ hat die<br />

gleichen Eigenschaften wie jeder andere Bezeichner. Die Reichweite der<br />

„Benennung“ erstreckt sich über den ganzen Block. Der Benennung folgt e<strong>in</strong><br />

Doppelpunkt.<br />

„Benennungen“ werden nur von den Sprunganweisungen break und cont<strong>in</strong>ue<br />

benutzt.<br />

2.4.4 Deklarationen<br />

E<strong>in</strong>e Deklarationsanweisung def<strong>in</strong>iert e<strong>in</strong>e Variable, egal ob Klasse, Schnittstelle,<br />

Datenfeld, Objekt oder primitiver Typ. Das Format e<strong>in</strong>er solchen Anweisung hängt<br />

davon ab, welcher der 5 verschiedenen Formen deklariert wird.<br />

Typname variablenName;<br />

bzw.<br />

Typname variablenName = <strong>in</strong>itialerWert;<br />

127


2.4.5 Ausdrucksanweisungen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

In <strong>Java</strong> gibt es sieben verschiedene Arten von Ausdrucksanweisungen:<br />

Ausdrucksanweisung Beispiel<br />

Zuordnung<br />

x=13;<br />

Prä-Inkrement<br />

++wert;<br />

Prae-Dekrement<br />

--wert;<br />

Post-Inkrement<br />

wert++;<br />

Post-Dekrement<br />

wert--;<br />

Methodenaufruf<br />

System.out.pr<strong>in</strong>tln(“Aller Anfang ist schwer!“);<br />

Zuweisungsausdruck byte x = new byte;<br />

Abb.: Die sieben Ausdrucksanweisungen <strong>in</strong> <strong>Java</strong><br />

Bsp.: Demonstrationsprogramm zur Wirkungsweise der Inkrement- und Dekrement-<br />

Operatoren 102<br />

// Demonstration der Operatoren ++ und -public<br />

class AutoInkr<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t i = 1;<br />

ausgabe("i: " + i);<br />

ausgabe("++i: " + ++i); // Pre-Inkrement<br />

ausgabe("i++: " + i++); // Post-Inkrement<br />

ausgabe("i: " + i);<br />

ausgabe("--i: " + --i); // Pre-Dekrement<br />

ausgabe("i--: " + i--); // Post-Inkrement<br />

ausgabe("i: " + i);<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

/* Ausgabe<br />

i: 1<br />

++i: 2<br />

i++: 2<br />

i: 3<br />

--i: 2<br />

i--: 2<br />

i: 1<br />

*/<br />

102 vgl. PR24500<br />

128


2.4.6 Auswahlanweisungen<br />

if-Anweisungen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e if-Anweisung testet e<strong>in</strong>e boolesche Variable oder e<strong>in</strong>en Ausdruck zur<br />

Feststellung, ob e<strong>in</strong>e Anweisung oder e<strong>in</strong> Anweisungsblock ausgeführt werden soll.<br />

Hat die boolesche Variable den Wert true, wird der Block ausgeführt. Falls nicht,<br />

spr<strong>in</strong>gt die Programmkontrolle zur nächsten Anweísung h<strong>in</strong>ter dem Block.<br />

if (boolscher_Ausdruck)<br />

anweisung 103<br />

if-else-Anweisungen<br />

Ergänzt if um e<strong>in</strong>en else-Teil. Dieser else-Teil reicht die Kontrolle an e<strong>in</strong>e<br />

Anweisung oder Block weiter, wenn der boolesche Wert im if-Teil der Anweisung<br />

false war.<br />

if (boolscher_Ausdruck)<br />

anweisung<br />

else<br />

anweisung<br />

Bsp.: Demonstrationsprogramm zur if-Anweisung 104<br />

import java.lang.*;<br />

public class IfDemo extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t i;<br />

<strong>in</strong>t abs;<br />

// if - else<br />

i = 13;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

if (i >= 0)<br />

{<br />

abs = i;<br />

}<br />

else {<br />

abs = -i;<br />

}<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

i = -13;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

if (i >= 0)<br />

{<br />

abs = i;<br />

}<br />

else {<br />

abs = -i;<br />

}<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

103 „anweisung“ bedeutet: E<strong>in</strong>e e<strong>in</strong>fache Anweisung, die nur von e<strong>in</strong>em Semikolon abgeschlossen ist bzw.<br />

e<strong>in</strong>e zusammengesetzte Folge von anweisungen, die von { ... } umschlossen ist.<br />

104 Vgl. PR24601<br />

129


if<br />

i = 13;<br />

abs = i;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

if (abs < 0)<br />

{<br />

abs = -abs;<br />

}<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

i = -13;<br />

abs = i;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

if (abs < 0)<br />

{<br />

abs = -abs;<br />

}<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

// Konditionaloperator<br />

i = -13;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

abs = ( i < 0 ? -i : i);<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

i = 13;<br />

System.out.pr<strong>in</strong>tln("i = " + i);<br />

abs = ( i < 0 ? -i : i);<br />

System.out.pr<strong>in</strong>tln("abs = " + abs);<br />

}<br />

}<br />

switch-Anweisungen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e switch-Anweisung ermöglicht die Weitergabe des Kontrollflusses an e<strong>in</strong>e von<br />

vielen Anweisungen <strong>in</strong> ihrem Block mit Unteranweisungen (ist abhängig vom Wert<br />

des Ausdrucks <strong>in</strong> der switch-Anweisung).<br />

switch (<strong>in</strong>tegraler_Selektor)<br />

{<br />

case <strong>in</strong>tegraler_Wert1: anweisung; break;<br />

case <strong>in</strong>tegraler_Wert2: anweisung; break;<br />

case <strong>in</strong>tegraler_Wert3: anweisung; break;<br />

.....<br />

default: anweisung;<br />

}<br />

E<strong>in</strong> <strong>in</strong>tegraler_Selektor ist e<strong>in</strong> Ausdruck zur Produktion e<strong>in</strong>es <strong>in</strong>tegralen Werts 105 .<br />

„switch“ vergleicht das Ergebnis e<strong>in</strong>er Auswertung vom <strong>in</strong>tegralen Selektor mit jedem<br />

<strong>in</strong>tegralen Wert. Falls e<strong>in</strong> passender Wert gefunden wird, wird die zugehörige<br />

Anweisung (e<strong>in</strong>fach oder zusammengesetzt) ausgeführt. Anderenfalls kommt es zur<br />

Ausführung der bei „default“ angegebenen Anweisung. Die „break“-Anweisung ist<br />

optional. Fehlt sie, dann werden die folgenden Anweisungen ausgeführt, bis e<strong>in</strong><br />

„break“ auftritt.<br />

105 Integrale Werte s<strong>in</strong>d bspw. vom Typ „<strong>in</strong>t“, „char“. Nicht<strong>in</strong>tegrale Typen. Z.B. float, Str<strong>in</strong>g, müssen über e<strong>in</strong>e<br />

Serie von „if“-Anweisungen „switch“ simulieren<br />

130


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bsp.: Demonstrationsprogramm zur switch-Anweisung 106<br />

import java.lang.*;<br />

public class SwitchDemo extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t dezimal = 10;<br />

System.out.pr<strong>in</strong>t("dezimal = " + dezimal + " hex: ");<br />

switch (dezimal)<br />

{<br />

case 0:<br />

case 1:<br />

case 2:<br />

case 3:<br />

case 4:<br />

case 5:<br />

case 6:<br />

case 7:<br />

case 8:<br />

case 9:<br />

System.out.pr<strong>in</strong>t("" + dezimal);<br />

break;<br />

case 10:<br />

System.out.pr<strong>in</strong>t("A");<br />

break;<br />

case 11:<br />

System.out.pr<strong>in</strong>t("B");<br />

break;<br />

case 12:<br />

System.out.pr<strong>in</strong>t("C");<br />

break;<br />

case 13:<br />

System.out.pr<strong>in</strong>t("D");<br />

break;<br />

case 14:<br />

System.out.pr<strong>in</strong>t("E");<br />

break;<br />

case 15:<br />

System.out.pr<strong>in</strong>t("F");<br />

break;<br />

default:<br />

System.out.pr<strong>in</strong>t("Ke<strong>in</strong>e gueltige Hex-Ziffer");<br />

break;<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

}<br />

2.4.7 Iterationsanweisungen<br />

while-Anweisung<br />

Die while-Anweisung testet e<strong>in</strong>e boolesche Variable oder e<strong>in</strong>en Ausdruck. Ist er<br />

true, wird die Unteranweisung oder der Block solange ausgeführt, bis sich der Wert<br />

false e<strong>in</strong>stellt. Ist die Variable oder der Ausdruck false, wird die Kontrolle an die<br />

106 vgl. PR24601<br />

131


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

nächste Anweisung nach der Unteranweisung oder nach dem Block der while-<br />

Anweisung weitergegeben.<br />

while (boolescher_Ausdruck)<br />

anweisung<br />

Bsp. 107 :<br />

public class WhileDemo extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

double a = 2.0;<br />

<strong>in</strong>t n = 10;<br />

System.out.pr<strong>in</strong>tln("a = " + a);<br />

System.out.pr<strong>in</strong>tln("n = " + n);<br />

<strong>in</strong>t absn = (n < 0) ? -n : n;<br />

double aHochn = 1.0;<br />

<strong>in</strong>t i = 1;<br />

while (i


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

if (n == 0)<br />

{<br />

break;<br />

}<br />

aHochn *= a;<br />

i++;<br />

} while (i


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

for (<strong>in</strong>itialisierung; boolescher_Ausdruck; naechster_Schritt)<br />

anweisung<br />

Bsp.:<br />

public class ForDemo extends Object<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

double a = 2.0;<br />

<strong>in</strong>t n = 10;<br />

System.out.pr<strong>in</strong>tln("a = " + a);<br />

System.out.pr<strong>in</strong>tln("n = " + n);<br />

<strong>in</strong>t absn = (n < 0) ? -n : n;<br />

double aHochn = 1.0;<br />

for (<strong>in</strong>t i = 1; i


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bsp. 109 : „break“ und „cont<strong>in</strong>ue“ <strong>in</strong>nerhalb von „for“- bzw. „while“-Schleifen<br />

public class BreakundCont<strong>in</strong>ue<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

for (<strong>in</strong>t i = 0; i < 100; i++)<br />

{<br />

if (i == 13) break; // raus aus der Schleife<br />

if (i % 9 != 0) cont<strong>in</strong>ue; // naechster Schleifendurchlauf<br />

System.out.pr<strong>in</strong>tln(i);<br />

}<br />

<strong>in</strong>t i = 0;<br />

// e<strong>in</strong>e "unendliche Schleife<br />

while (true)<br />

{<br />

i++;<br />

<strong>in</strong>t j = i * 27;<br />

if (j == 1269) break; // raus aus der Schleife<br />

if (i % 10 != 0) cont<strong>in</strong>ue; // zurueck an den Anfang der Schleife<br />

System.out.pr<strong>in</strong>tln(i);<br />

}<br />

}<br />

}<br />

Marken (labels)<br />

E<strong>in</strong>e Markierung bzw. e<strong>in</strong> „label“ bewirkt <strong>in</strong> Verb<strong>in</strong>dung mit der „break“- bzw.<br />

„cont<strong>in</strong>ue“-Anweisung e<strong>in</strong>e Unterbrechnug des Schleifendurchgangs und e<strong>in</strong>en<br />

Sprung zu der dem „label“ folgenden Anweisung. S<strong>in</strong>nvollerweise steht dann e<strong>in</strong><br />

„label“ am Anfang der Schleifen, z.B.:<br />

label1:<br />

äußere_Iteration<br />

{<br />

<strong>in</strong>nere_Iteration<br />

{<br />

// ...<br />

break; // 1. Fall<br />

// ...<br />

cont<strong>in</strong>ue; // 2. Fall<br />

// ...<br />

cont<strong>in</strong>ue label1; // 3. Fall<br />

// ...<br />

break label1; // 4. Fall<br />

}<br />

}<br />

Im 1. Fall bricht „break“ aus der <strong>in</strong>neren Iteration heraus und führt <strong>in</strong> die äußere<br />

Iteration. Im 2. Fall verzweigt „cont<strong>in</strong>ue“ auf den Anfang der <strong>in</strong>neren Iteration. Im 3.<br />

Fall führt „cont<strong>in</strong>ue label1“ aus der <strong>in</strong>neren und äußeren Iteration heraus auf<br />

„label1“. Die Iteration wird mit dem Anfang der äußeren Iteration fortgesetzt. Im 4.<br />

Fall bricht „break label1“ aus der <strong>in</strong>neren Iteration heraus auf label1. Es kommt<br />

aber nicht zu e<strong>in</strong>em erneuten E<strong>in</strong>tritt <strong>in</strong> die Iterationen, sondern zu e<strong>in</strong>em Ausbruch<br />

aus beiden Iterationen.<br />

Bsp. 110 : Marken im Zusammenhang mit „for“- bzw. „while“-Schleifen<br />

109 PR24800<br />

135


110 PR24800<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

1. Marken im Zusammenhang mit „for“<br />

public class MarkiertesFor<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t i = 0;<br />

aussen: // hier soll ke<strong>in</strong>e Anweisung stehen<br />

for (; true; ) // Endlos-Schleife<br />

{<br />

<strong>in</strong>nen: // hier soll ke<strong>in</strong>e Anweisung stehen<br />

for (; i < 10; i++)<br />

{<br />

ausgabe("i = " + i);<br />

if (i == 2)<br />

{<br />

ausgabe("cont<strong>in</strong>ue");<br />

cont<strong>in</strong>ue;<br />

}<br />

if (i == 3)<br />

{<br />

ausgabe("break");<br />

i++;<br />

break;<br />

}<br />

if (i == 7)<br />

{<br />

ausgabe("cont<strong>in</strong>ue aussen");<br />

i++;<br />

cont<strong>in</strong>ue aussen;<br />

}<br />

if (i == 8)<br />

{<br />

ausgabe("break aussen");<br />

break aussen;<br />

}<br />

for (<strong>in</strong>t k = 0; k < 5; k++)<br />

{<br />

if (k == 3)<br />

{<br />

ausgabe("cont<strong>in</strong>ue <strong>in</strong>nen");<br />

cont<strong>in</strong>ue <strong>in</strong>nen;<br />

}<br />

}<br />

}<br />

}<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

/* Ausgabe<br />

i = 0<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

i = 1<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

i = 2<br />

cont<strong>in</strong>ue<br />

i = 3<br />

break<br />

i = 4<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

i = 5<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

136


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

i = 6<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

i = 7<br />

cont<strong>in</strong>ue <strong>in</strong>nen<br />

i = 8<br />

break aussen<br />

*/<br />

2. Marken im Zusammenhang mit „while“<br />

public class MarkiertesWhile<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t i = 0;<br />

aussen:<br />

while (true)<br />

{<br />

ausgabe("Aeussere While-Schleife");<br />

while (true)<br />

{<br />

i++;<br />

ausgabe("i = " + i);<br />

if (i == 1)<br />

{<br />

ausgabe("cont<strong>in</strong>ue");<br />

cont<strong>in</strong>ue;<br />

}<br />

if (i == 3)<br />

{<br />

ausgabe("cont<strong>in</strong>ue aussen");<br />

cont<strong>in</strong>ue aussen;<br />

}<br />

if (i == 5)<br />

{<br />

ausgabe("break");<br />

break;<br />

}<br />

if (i == 7)<br />

{<br />

ausgabe("break aussen");<br />

break aussen;<br />

}<br />

}<br />

}<br />

}<br />

static void ausgabe(Str<strong>in</strong>g s)<br />

{<br />

System.out.pr<strong>in</strong>tln(s);<br />

}<br />

}<br />

/* Ausgabe<br />

Aeussere While-Schleife<br />

i = 1<br />

cont<strong>in</strong>ue<br />

i = 2<br />

i = 3<br />

cont<strong>in</strong>ue aussen<br />

Aeussere While-Schleife<br />

i = 4<br />

i = 5<br />

break<br />

Aeussere While-Schleife<br />

i = 6<br />

i = 7<br />

break aussen<br />

*/<br />

137


eturn-Anweisung<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Alle Funktionen haben e<strong>in</strong>en e<strong>in</strong>deutigen Typ, der gleichzeitig Typ des<br />

Rückgabewerts ist. Mögliche Typen für die Rückgabe s<strong>in</strong>d primitive Typen,<br />

Datenfelder (Arrays), Klassen, Schnittstellen. Es gibt e<strong>in</strong>en speziellen Typ für e<strong>in</strong>e<br />

Funktion ohne Rückgabewert: „void“.<br />

Der Rückgabewert ist der Wert e<strong>in</strong>er return-Anweisung.<br />

throw-Anweisung<br />

E<strong>in</strong>e throw-Anweisung erzeugt e<strong>in</strong>e Laufzeit-Ausnahme.<br />

2.4.9 Synchronisationsanweisungen<br />

Sie wird für den Umgang mit „Multithread<strong>in</strong>g“ benutzt.<br />

2.4.10 Schutzanweisungen<br />

<strong>Java</strong> kennt drei Schutzanweisungen: try, catch, f<strong>in</strong>ally. Sie werden zur<br />

Handhabung von Ausnahmen <strong>in</strong> e<strong>in</strong>er Methode benutzt, die e<strong>in</strong>e Ausnahmesituation<br />

hervorrufen kann.<br />

2.4.11 Unerreichbare Anweisungen<br />

Es ist das Schreiben e<strong>in</strong>er Methode mit Codezeilen möglich, die nie erreicht werden<br />

können, z.B. Zeilen zwischen e<strong>in</strong>er bed<strong>in</strong>gungslosen return-Anweisung und der<br />

nächsten Bezeichnung oder dem Ende e<strong>in</strong>es Blocks. Solche Anweisungen erzeugen<br />

e<strong>in</strong>en Fehler beim Kompilieren.<br />

138


2.5 Klassen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Klassen def<strong>in</strong>ieren Zustand und Verhalten von Objekten. Jedes <strong>Java</strong>-Programm<br />

besteht aus e<strong>in</strong>er Sammlung von Klassen. Alle Klassen <strong>in</strong> <strong>Java</strong> haben e<strong>in</strong>e<br />

geme<strong>in</strong>same Oberklasse, die Klasse Object. Auch <strong>Java</strong> selbst (als<br />

Entwicklungsplattform) ist aus Klassen aufgebaut, die mit dem JDK frei verfügbar<br />

s<strong>in</strong>d. Das eigentliche RUNTIME-Modul besteht aus der Datei <strong>Java</strong> Core Classes<br />

(classes.zip), die normalerweise nicht entpackt wird und im Unterverzeichnis<br />

\lib des JDK vohanden ist. Die Datei enthält den vollständigen kompilierten Code<br />

von <strong>Java</strong>.<br />

Jede Klasse besteht formal aus zwei Teilen: der Deklaration und dem Body (Körper).<br />

Generell haben Klassendeklarationen folgendes Format:<br />

Modifizierer class NeueKlasse extends NameSuperklasse<br />

implements NameSchnittstelle<br />

Es gibt vier Eigenschaften e<strong>in</strong>er Klasse, die <strong>in</strong> e<strong>in</strong>er Deklaration def<strong>in</strong>iert werden<br />

können: Modifizierer, Klassenname, Superklasse, Schnittstellen<br />

Modifizierer<br />

Sie stehen am Beg<strong>in</strong>n der Klassendeklaration und legen fest, wie die Klasse<br />

während der weiteren Entwicklung gehandhabt werden kann. Klassen haben e<strong>in</strong>en<br />

vore<strong>in</strong>gestellten, „freundlichen“ Defaultstatus. Er wird immer dann verwendet, wenn<br />

ke<strong>in</strong> Modifizierer am Anfang e<strong>in</strong>er Klassendef<strong>in</strong>ition steht. „Freundlich“ bedeutet: Die<br />

Klasse darf erweitert und von anderen Klassen benutzt werden, aber nur von<br />

Objekten <strong>in</strong>nerhalb desselben Pakets. Die Grunde<strong>in</strong>stellung bezieht sich also auf die<br />

Sichtbarkeit von anderen Klassen und deren Objekten. Falls davon abgewichen<br />

werden soll, ist e<strong>in</strong>er der folgenden Modifizierer zu verwenden: public , f<strong>in</strong>al,<br />

abstract.<br />

Öffentliche Klassen – der Modifizierer public. E<strong>in</strong>e Klasse wird als öffentlich<br />

deklariert, wenn man den Modifizierer public vor die Klassendeklaration setzt. Alle<br />

Objekte dürfen auf public-Klassen zugreifen, d.h.: Sie können von allen Objekten<br />

benutzt und erweitert werden, ganz egal zu welchem Paket sie gehören.. Die<br />

Deklaration e<strong>in</strong>er öffentlichen Klasse muß immer identisch se<strong>in</strong> mit dem Namen,<br />

unter dem die Quelle dieser Datei gespeichert ist.<br />

F<strong>in</strong>ale Klassen – der Modifizierer f<strong>in</strong>al. F<strong>in</strong>ale Klassen dürfen ke<strong>in</strong>e Subklassen<br />

haben. Der Modifizierer f<strong>in</strong>al muß am Beg<strong>in</strong>n der Klassendeklaration gesetzt se<strong>in</strong>.<br />

Abstrakte Klassen – der Modifizierer abstract. Von e<strong>in</strong>er derartig beschriebenen<br />

Klasse wird nie e<strong>in</strong>e direkte Instanz benötigt und kann auch nie e<strong>in</strong>e Instanz gebildet<br />

werden. Sie darf ke<strong>in</strong>e Implementierung e<strong>in</strong>er Methode enthalten. In e<strong>in</strong>er abstrakten<br />

Klasse gibt es m<strong>in</strong>destens e<strong>in</strong>e nicht vollständig angegebene Methode.<br />

Der Klassenname<br />

Jede Klasse benötigt e<strong>in</strong>en Namen.<br />

Superklasse und das Schlüsselwort extends<br />

Wird der Name e<strong>in</strong>er Klasse nach dem Schlüsselwort extend angegeben, dann wird damit diese Klasse als<br />

Superklasse spezifiziert, auf der e<strong>in</strong>e neue Klasse aufbaut. Durch Erweiterung der Superklasse entsteht e<strong>in</strong>e neue<br />

Kopie dieser Klasse, an der Veränderungen möglich s<strong>in</strong>d. Die neue Klasse erbt alle Daten und Methoden, die <strong>in</strong><br />

der Orig<strong>in</strong>alklasse def<strong>in</strong>iert wurden.<br />

139


2.6 Methoden<br />

2.6.1 Die Deklaration<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Deklarationen von Methoden haben folgendes Aussehen 111 :<br />

Zugriffsspezifizierer Modifizierer Returnwert NameMethode(Parameter)<br />

throws Exceptionliste<br />

Methodenunterschrift 112 . Unter Unterschrift e<strong>in</strong>er Methode versteht man e<strong>in</strong>e<br />

Komb<strong>in</strong>ation aus Teilen der Def<strong>in</strong>ition: dem Namen der Methode, dem Rückgabetyp<br />

und den verschiedenen Parametern.<br />

2.6.2 Die Zugriffsspezifizierung<br />

Freundliche Methoden – der vore<strong>in</strong>gestellte Defaultstatus.<br />

Öffentliche Methoden – der Zugriffsspezifizierer public.<br />

Geschützt Methoden – der Zugriffsspezifizierer protected.<br />

Prvate Methoden – der Zugriffsspezifizierer private.<br />

Privat geschützt – die Zugriffsspezifizierer private und protected <strong>in</strong><br />

Komb<strong>in</strong>ation. Methoden, die als private protected deklariert wurden, s<strong>in</strong>d<br />

sowohl für e<strong>in</strong>e Klasse als auch für e<strong>in</strong>e Subklasse vefügbar, aber nicht für den Rest<br />

des Pakets oder auch für Klassen außerhalb des Pakets. Das bedeutet: Subklassen<br />

e<strong>in</strong>er gegebenen Klasse können Methoden, die private protected deklariert<br />

wurden aufrufen. Instanzen der Subklasse können dies aber nicht.<br />

2.6.3 Die Methodenmodifizierer<br />

Klassenmethoden – der Modifizierer static.<br />

Abstrakte Methoden – der Modifizierer abstract<br />

F<strong>in</strong>ale Methoden – der Modifizierer f<strong>in</strong>al. Das Schlüsselwort f<strong>in</strong>al vor e<strong>in</strong>er<br />

Methodendeklaration verh<strong>in</strong>dert, daß irgendwelche Subklassen die derzeitige Klasse<br />

dieser Methode überschreiben. Methoden, die auf ke<strong>in</strong>em Fall geändert werden<br />

sollen, sollten deshalb immer als f<strong>in</strong>al deklariert werden.<br />

111 Kursiv Geschriebenes ist optional<br />

112 Oft wird für denselben Zusammenhang der Begriff „methodensignatur“ verwendet.<br />

140


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Native Methoden – der Modifizierer native. Native Methoden s<strong>in</strong>d Methoden, die<br />

nicht <strong>in</strong> <strong>Java</strong> geschrieben s<strong>in</strong>d, aber dennoch <strong>in</strong>nerhalb von <strong>Java</strong> verwendet werden<br />

sollen. Der Modifizierer native wird vor der Methode deklariert, der Body (Körper) der<br />

Methode wird durch e<strong>in</strong> Semikolon ersetzt.<br />

Methoden synchronisieren – der Modifizierer synchronized. Wird das<br />

Schlüsselwort sychronized vor e<strong>in</strong>e Methodendeklaration gesetzt, dann werden<br />

Datenverletzungen verh<strong>in</strong>dert, die entstehen können, wenn zwei Methoden<br />

gleichzeitig versuchen auf dieselben Daten zuzugreifen.<br />

2.6.4 Rückgabewerte von Methoden<br />

Rückgabewerte von<strong>Java</strong>-Methoden können von jedem erlaubten Datentyp 113 se<strong>in</strong>.<br />

E<strong>in</strong>e Methode muß immer e<strong>in</strong>en Wert zurückgeben (und zwar genau den Datentyp,<br />

der <strong>in</strong> der Deklaration angegeben wurde), es sei denn, sie wurde mit void deklariert.<br />

Die Methode hat dann ke<strong>in</strong>en Rückgabewert.<br />

2.6.5 Methodenname und Parameterliste<br />

Bzgl. der Methodennamen gelten die gleichen Regeln wie bei allen Token.<br />

E<strong>in</strong>e Parameterliste hat folgende Struktur: Datentyp variablenname, Datentyp<br />

variablenname, .... Die Anzahl der Parameter ist beliebig und kann Null se<strong>in</strong>.<br />

113 Nicht nur primitive Datentypen, sondern auch komplexe Objekte.<br />

141


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3. Grafische Benutzeroberflächen und Applets<br />

3.1 Ereignisbehandlung unter grafischen Benutzeroberflächen<br />

Mit Hilfe e<strong>in</strong>facher Benutzerschnittstellen Graphical User Interface (GUI))<br />

lassen sich E<strong>in</strong>- und Ausgaben 114 bequem gestalten. Generell sollte E<strong>in</strong>-/Ausgabe <strong>in</strong><br />

<strong>Java</strong> über e<strong>in</strong> "GUI" <strong>in</strong> Abhängigkeit von den vom Betriebssystem registrierten<br />

Ereignisarten und Zustandsänderungen erfolgen.<br />

3.1.1 Gestaltung von GUI mit Hilfe der AWT-Klassen<br />

<strong>Java</strong> enthält e<strong>in</strong> e<strong>in</strong>fach zu bedienendes System für Gestaltung grafische<br />

Benutzeroberflächen: das Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit (AWT). Die Fähigkeiten des<br />

AWT umfassen:<br />

- Grafische Operationen zum Zeichnen von L<strong>in</strong>ien oder Füllen von Flächen und zur Ausgabe von Text<br />

- Methode zur Steuerung des Programmablaufs auf der Basis von Nachrichten für Tatstatur-, Mausund<br />

Fensterereignisse.<br />

- Dialogelemente zur Kommunikation mit dem Anwender und Funktion zum Design von Dialogboxen.<br />

- Grafikfunktionen zur Darstellung von Bitmaps und Ausgabe von "Sound".<br />

Zum E<strong>in</strong>b<strong>in</strong>den der Grafikfähigkeiten dient die Anweisung<br />

import java.awt.*;<br />

zu Beg<strong>in</strong>n der Klassendef<strong>in</strong>ition. Danach stehen alle Klassen aus dem Paket<br />

java.awt zur Verfügung.<br />

Zur Ausgabe von grafischen Elementen benötigt e<strong>in</strong>e Anwendung e<strong>in</strong> Fenster, das<br />

e<strong>in</strong>e Applikation (im Gegensatz zu e<strong>in</strong>em Applet) selbst erzeugen muß. Das AWT<br />

enthält verschiedene Fensterklassen:<br />

Component Conta<strong>in</strong>er<br />

Panel Applet<br />

W<strong>in</strong>dow Dialog FileDialog<br />

142<br />

Frame<br />

Component Abstrakte Klasse mit der Aufgabe: Repäsentation von Programmelementen, die<br />

e<strong>in</strong>e Größe und Position haben und die auf e<strong>in</strong>e Vielzahl von Ereignissen reagieren<br />

können bzw. Ereignisse senden können<br />

Conta<strong>in</strong>er Abstrakte Klasse mit der Aufgabe: Aufnahme von Komponenten <strong>in</strong>nerhalb anderer<br />

Komponenten. Conta<strong>in</strong>er stellt für das H<strong>in</strong>zufügen bzw. Entfernen von<br />

Komponenten Methoden bereit und realisiert mit Hilfe von "Layout-Manager"-<br />

Klassen Positionierung und Anordnung von Komponenten.<br />

Panel Ist die konkrete Klasse mit den Eigenschaften von Component und Conta<strong>in</strong>er. Sie<br />

114 Standarde<strong>in</strong>- und Standardausgabe spielen <strong>in</strong> <strong>Java</strong> nur im Rahmen des „Debugg<strong>in</strong>g“ e<strong>in</strong>e Rolle.


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

erbt alle Eigenschaften von Conta<strong>in</strong>er, kann Komponenten aufnehmen und mit<br />

Hilfe des Layoutmanagers auf dem Bildschirm anordnen.<br />

Applet Erweitert die Funktionalität der Klasse Applet um Methoden, die für das Ausführen<br />

von Applets von Bedeutung s<strong>in</strong>d. Damit entsteht e<strong>in</strong> Programmelement, das e<strong>in</strong>e<br />

Größe und e<strong>in</strong>e Position hat, auf Ereignisse reagieren kann und <strong>in</strong> der Lage ist,<br />

weitere Komponenten aufzunehmen.<br />

W<strong>in</strong>dow Bestimmt e<strong>in</strong> Top-Level-W<strong>in</strong>dow ohne Rahmen, Titelleiste und Menü. Sie ist für<br />

Anwendungen geeignet, die Rahmenelemente selbst zeichnen oder volle Kontrolle<br />

über das gesamte Fenster benötigen.<br />

Frame Repräsentiert e<strong>in</strong> Top-Level-W<strong>in</strong>dow mit Rahmen, Titelleiste und optionalem Menü.<br />

Dialog Realisiert modale und nicht modale Dialoge.<br />

FileDialog Stellt e<strong>in</strong> Standard-Dateidialog des jeweiligen Systems bereit. Dieser kann beim<br />

Laden oder Speichern e<strong>in</strong>er datei zur E<strong>in</strong>gabe oder zur Auswahl e<strong>in</strong>es<br />

Date<strong>in</strong>amens verwendet werden.<br />

Abb. Fensterklassen-Hierarchie<br />

Zur Anzeige e<strong>in</strong>es Fensters auf dem Bildschirm muß e<strong>in</strong>e der Fensterklassen,<br />

W<strong>in</strong>dow, Frame, Dialog, Applet, FileDialog <strong>in</strong>stanziert werden. Zum Ableiten<br />

e<strong>in</strong>er eigenen Fensterklasse wird <strong>in</strong> der Regel die Klasse Frame oder Dialog<br />

verwendet, die beibe aus der Klasse W<strong>in</strong>dow abgeleitet s<strong>in</strong>d.<br />

Bsp. 115 : E<strong>in</strong>-, Ausgabe über Textfelder <strong>in</strong> e<strong>in</strong>em ersten GUI<br />

E<strong>in</strong> erstes GUI soll aus e<strong>in</strong>em editierbaren und e<strong>in</strong>em nicht editierbaren Textfeld bestehen.<br />

Den beiden Textfeldern soll jeweils e<strong>in</strong> Label mit der Beschriftung „E<strong>in</strong>gabestr<strong>in</strong>g:“ bzw.<br />

„Ausgabestr<strong>in</strong>g“ zugeordnet se<strong>in</strong>. Diese Komponenten sollen automatisch von l<strong>in</strong>ks nach<br />

rechts und von oben nach unten angeordnet werden <strong>in</strong> e<strong>in</strong>em Panel, das selbst wiederum<br />

e<strong>in</strong>ziges Objekt <strong>in</strong> e<strong>in</strong>em Fenster (Frame) mit dem Titel „Echo“ ist.<br />

import java.lang.*;<br />

import java.awt.*;<br />

public class EchoMitBeno<br />

{<br />

// E<strong>in</strong>lesen und Ausgeben von Zeichenketten ueber<br />

// e<strong>in</strong>e grafische Benutzeroberflaeche<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

Label e<strong>in</strong>gabeTextFeldLabel = new Label("E<strong>in</strong>gabestr<strong>in</strong>g:");<br />

e<strong>in</strong>gabeTextFeld.setEditable(true);<br />

TextField ausgabeTextFeld = new TextField(20);<br />

Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />

ausgabeTextFeld.setEditable(false);<br />

Panel panel = new Panel();<br />

panel.add(e<strong>in</strong>gabeTextFeldLabel);<br />

panel.add(e<strong>in</strong>gabeTextFeld);<br />

panel.add(ausgabeTextFeldLabel);<br />

panel.add(ausgabeTextFeld);<br />

Frame fenster = new Frame("Echo");<br />

fenster.add(panel);<br />

fenster.pack();<br />

fenster.setVisible(true);<br />

}<br />

}<br />

Die Implementierung des vorliegenden Programms zeigt das folgende<br />

Ausgabefenster:<br />

115 PR14160<br />

143


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das vorliegende Beispiel zeigt noch e<strong>in</strong>ige Mängel:<br />

- Zwar kann <strong>in</strong> das für die E<strong>in</strong>gabe vorgesehene Textfeld e<strong>in</strong> Str<strong>in</strong>g e<strong>in</strong>gegeben werden, das zweite<br />

Textfeld ist allerd<strong>in</strong>gs nicht zugänglich. Es passiert somit nicht gerade viel. Es werden noch ke<strong>in</strong>e<br />

Ereignisse aufgefangen und behandelt.<br />

- Noch nicht e<strong>in</strong>mal kann das Fenster geschlossen werden, und die Applikation muß (nach dem<br />

Schließen des Frame) mit "CTRL-C" explizit abgebrochen werden.<br />

3.1.2 Ereignisbehandlung unter grafischen Benutzeroberflächen<br />

Im Mittelpunkt der Programmierung unter e<strong>in</strong>er GUI steht die Kommunikation<br />

zwischen System und Anwendungsprogramm. Die Anwendung wird über alle Arten<br />

von Ereignissen und Zustandsänderungen vom System durch Versenden von<br />

Nachrichten (z.B. über Mausklick, Tastature<strong>in</strong>gaben, Veränderungen an Größe und<br />

Lage der Fenster) <strong>in</strong>formiert. Die Reaktion auf die Nachrichten erfolgt <strong>in</strong> spezielllen<br />

Ereignisempfängern (EventListeners), die das zum Ereignis passende Empfänger-<br />

Interface implementieren. Damit e<strong>in</strong> Ereignisempfänger Nachrichten e<strong>in</strong>er<br />

bestimmten Ereignisquelle erhält, muß er sich bei der Quelle registrieren lassen,<br />

d.h.: Es muß e<strong>in</strong>e EventListener-Klasse geschrieben, <strong>in</strong>stanziert und bei der<br />

Ereignisquelle registriert werden. Zum Empfang von Nachrichten muß e<strong>in</strong> Objekt<br />

e<strong>in</strong>e Reihe von Methoden implementieren, die von der Nachrichtenquelle, bei der es<br />

sich registriert hat, aufgerufen werden können. Die Ereignisempfänger stellen diese<br />

Methoden durch Implementierung von Interfaces bereit, die aus der Klasse<br />

EventListener des Pakets java.util abgeleitet s<strong>in</strong>d.<br />

Ereignistypen. Im JDK 1.1 werden Ereignistypen durch e<strong>in</strong>e Hierarchie von<br />

Ereignisklassen repräsentiert, die alle aus der Klasse java.util.EventObject 116<br />

abgeleitet s<strong>in</strong>d.<br />

116 Speichert das Objekt, das die Nachricht ausgelöst hat und gibt durch Aufruf von "public Object getSource()"<br />

das Objekt an.<br />

144


EventObject<br />

AWTEvent<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

ComponentEvent ActionEvent AdjustmentEvent ItemEvent TextEvent<br />

FocusEvent InputEvent Conta<strong>in</strong>erEvent W<strong>in</strong>dowEvent<br />

KeyEvent MouseEvent<br />

Abb.: Spezifische Ereignisklassen<br />

Die Hierarchie der AWT-spezifischen Ereignisklassen beg<strong>in</strong>nt mit der Klasse<br />

AWTEvent und bef<strong>in</strong>det sich im Paket java.awt. AWTEvent ist Superklasse aller<br />

Ereignisklassen des AWT, die sich im Paket java.awt.event bef<strong>in</strong>den. Dieses<br />

Paket ist <strong>in</strong> jede Klasse e<strong>in</strong>zubeziehen, die sich mit dem Event-Handl<strong>in</strong>g von AWT-<br />

Anwendungen beschäftigt.<br />

EventListener-Interface. Je Ereignisklasse gibt es e<strong>in</strong> EventListener-Interface. Es<br />

def<strong>in</strong>iert e<strong>in</strong>e seperate Methode für jede Ereignisart der Ereignisklasse. So besitzt<br />

bspw. das Interface MouseListener die Methoden mouseClicked,<br />

mouseEntered, mouseExited, mousePressed und mouseReleased, die beim<br />

E<strong>in</strong>treffen des jeweiligen Ereignis aufgerufen werden.<br />

EventListener<br />

FocusListener ActionListener AdjustementListener ItemListener<br />

KeyListener<br />

MouseListener<br />

MouseMotionListener<br />

ComponentListener<br />

Conta<strong>in</strong>erListener<br />

W<strong>in</strong>dowListener<br />

Abb.: Hierarchie der EventListener-Interfaces<br />

Jede der Methoden e<strong>in</strong>es Listener-Interface enthält als e<strong>in</strong>ziges Argument e<strong>in</strong> Objekt<br />

vom zugehörigen Ereignistyp. Alle Methoden s<strong>in</strong>d vom Typ void.<br />

145


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.1.3 Anwendung lokaler Klassen für die Ereignisbehandlung<br />

Im GUI-Objekt, das e<strong>in</strong>en Event-Handler benötigt wird e<strong>in</strong>e lokale Klasse zur<br />

Implementierung des passenden Interface angegeben. Lokale Klassen werden lokal<br />

zu e<strong>in</strong>er anderen Klasse erzeugt. Sie s<strong>in</strong>d nur <strong>in</strong>nerhalb dieser Klasse def<strong>in</strong>iert und<br />

sichtbar. Objekte der lokalen Klasse können nur aus der erzeugenden Klasse<br />

produziert werden. Die lokale Klasse kann aber auf alle Instanzmerkmale der<br />

erzeugenden Klasse zugreifen.<br />

E<strong>in</strong>e Variante lokale Klassen s<strong>in</strong>d anonyme Klassen. Sie werden ebenfalls lokal zu<br />

e<strong>in</strong>er anderen Klasse erzeugt, kommen aber ohne Klassennamen aus. Dazu werden<br />

sie bei der Übergabe e<strong>in</strong>es Objekts an e<strong>in</strong>e Methode oder als Rückgabewert e<strong>in</strong>er<br />

Methode <strong>in</strong>nerhalb e<strong>in</strong>er e<strong>in</strong>zigen Anwendung def<strong>in</strong>iert und <strong>in</strong>stanziert. Damit e<strong>in</strong>er<br />

anonymen Klasse überhaupt e<strong>in</strong>e s<strong>in</strong>nvolle Aufgabe zugeführt werden kann, muß sie<br />

aus e<strong>in</strong>er anderen Klasse abgeleitet se<strong>in</strong> oder e<strong>in</strong> bestehendes Interface<br />

implementieren.<br />

Bsp.: ActionListener-Interface für die Übernahme e<strong>in</strong>es Textfeld-Inhalts <strong>in</strong> e<strong>in</strong><br />

Textfeld zur Ausgabe<br />

Falls das Textfeld für die Ausgabe den im Textfeld für die E<strong>in</strong>gabe angegebenen Text<br />

wiedergeben soll, muß e<strong>in</strong> ActionListener (e<strong>in</strong>e zusätzlich <strong>in</strong>nere, anonyme Klasse) mit der<br />

Methode public void actionPerformed (ActionEvent a) def<strong>in</strong>iert werden. Diese<br />

Methode umfaßt Aufrufe der Methoden getText() und setText() der Klasse TextField.<br />

Darüber kann <strong>in</strong> das E<strong>in</strong>gabetextfeld e<strong>in</strong>gegebener Text <strong>in</strong> das Ausgabefeld ausgegeben<br />

werden. Da die "Methode actionPerformed" der anonymen <strong>in</strong>neren Klasse auf<br />

"e<strong>in</strong>gabeTextFeld" bzw. "ausgabeTextFeld" zugreift, ist außerhalb von ma<strong>in</strong>()<br />

anzugeben:<br />

private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

private static TextField ausgabeTextFeld = new TextField(20);<br />

Zum Schließen des Fensters wird über e<strong>in</strong>e anonyme <strong>in</strong>nere Klasse e<strong>in</strong><br />

W<strong>in</strong>dowAdapter (e<strong>in</strong>e Art W<strong>in</strong>dowListener) mit der Methode "public void<br />

w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)" def<strong>in</strong>iert und an den "Frame" e<strong>in</strong>gekettet.<br />

Wird der Frame geschlossen, dann wird diese Methode aufgerufen, die über<br />

System.exit(0) die Applikation beendet.<br />

E<strong>in</strong>e Adapterklasse implementiert e<strong>in</strong> Interface mit mehreren Mehoden und erlaubt<br />

es somit abgeleiteten Klassen, nur noch die Methoden zu überlagern, die tatsächlich<br />

von Interesse s<strong>in</strong>d. Passende Adapterklasssen stellt das Paket java.awt.event bereit,<br />

z.B. FocusAdapter, KeyAdapter, MouseAdapter, MouseMotionAdapter,<br />

ComponentAdapter, Conta<strong>in</strong>erAdapter, W<strong>in</strong>dowAdapter. Die Registrierung<br />

erfolgt mit der Methode addW<strong>in</strong>dowListener, die <strong>in</strong> den Klassen Dialog und<br />

Frame zur Verfügung steht.<br />

Bsp. 117 : Textfeldbearbeitung mit "ActionListener-Interface" und<br />

W<strong>in</strong>dowAdapter<br />

import java.lang.*;<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class EchoMitBeno extends Object<br />

{<br />

// E<strong>in</strong>lesen und Ausgeben von Zeichenketten ueber<br />

// e<strong>in</strong>e grafische Benutzeroberflaeche<br />

117 PR14160<br />

146


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

private static TextField ausgabeTextFeld = new TextField(20);<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Frame fenster = new Frame("Echo");<br />

fenster.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

// TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

Label e<strong>in</strong>gabeTextFeldLabel = new Label("E<strong>in</strong>gabestr<strong>in</strong>g:");<br />

e<strong>in</strong>gabeTextFeld.setEditable(true);<br />

e<strong>in</strong>gabeTextFeld.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent ae)<br />

{<br />

Str<strong>in</strong>g s = e<strong>in</strong>gabeTextFeld.getText();<br />

ausgabeTextFeld.setText(s);<br />

}<br />

});<br />

// TextField ausgabeTextFeld = new TextField(20);<br />

Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />

ausgabeTextFeld.setEditable(false);<br />

Panel panel = new Panel();<br />

panel.add(e<strong>in</strong>gabeTextFeldLabel);<br />

panel.add(e<strong>in</strong>gabeTextFeld);<br />

panel.add(ausgabeTextFeldLabel);<br />

panel.add(ausgabeTextFeld);<br />

// Frame fenster = new Frame("Echo");<br />

fenster.add(panel);<br />

fenster.pack();<br />

fenster.setVisible(true);<br />

}<br />

}<br />

Alternativ zur vorliegenden Realisierung der Ereignisbehandlung über e<strong>in</strong>e anonyme<br />

Klasse, kann auch e<strong>in</strong> Listener über e<strong>in</strong>e lokale Klasse implementiert werden.<br />

Gewöhnlich ist die Anwendung e<strong>in</strong>e Subklasse von Frame.<br />

import java.lang.*;<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class Vorl11b extends Frame<br />

{<br />

private static Label e<strong>in</strong>gabeTextFeldLabel = new Label("E<strong>in</strong>gabestr<strong>in</strong>g:");<br />

private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

private static Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />

private static TextField ausgabeTextFeld = new TextField(20);<br />

public Vorl11b()<br />

{<br />

e<strong>in</strong>gabeTextFeld.setEditable(true);<br />

ausgabeTextFeld.setEditable(false);<br />

Panel panel = new Panel();<br />

panel.add(e<strong>in</strong>gabeTextFeldLabel);<br />

panel.add(e<strong>in</strong>gabeTextFeld);<br />

panel.add(ausgabeTextFeldLabel);<br />

panel.add(ausgabeTextFeld);<br />

e<strong>in</strong>gabeTextFeld.addActionListener(new TFL());<br />

add(panel);<br />

pack();<br />

setVisible(true);<br />

}<br />

147


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

class TFL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent ae)<br />

{<br />

Str<strong>in</strong>g s = e<strong>in</strong>gabeTextFeld.getText();<br />

ausgabeTextFeld.setText(s);<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Vorl11b vorl11b = new Vorl11b();<br />

vorl11b.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

}<br />

}<br />

Schließlich kann das Interface auch direkt implementiert werden.<br />

Zweckmäßigerweise ist dann die Anwendung e<strong>in</strong>e Subklasse von Frame.<br />

import java.lang.*;<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class Vorl11a extends Frame implements ActionListener<br />

{<br />

private static Label e<strong>in</strong>gabeTextFeldLabel = new Label("E<strong>in</strong>gabestr<strong>in</strong>g:");<br />

private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

private static Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />

private static TextField ausgabeTextFeld = new TextField(20);<br />

public Vorl11a()<br />

{<br />

e<strong>in</strong>gabeTextFeld.setEditable(true);<br />

ausgabeTextFeld.setEditable(false);<br />

Panel panel = new Panel();<br />

panel.add(e<strong>in</strong>gabeTextFeldLabel);<br />

panel.add(e<strong>in</strong>gabeTextFeld);<br />

panel.add(ausgabeTextFeldLabel);<br />

panel.add(ausgabeTextFeld);<br />

e<strong>in</strong>gabeTextFeld.addActionListener(this);<br />

add(panel);<br />

pack();<br />

setVisible(true);<br />

}<br />

public void actionPerformed(ActionEvent ae)<br />

{<br />

System.out.pr<strong>in</strong>tln(ae.getActionCommand());<br />

Str<strong>in</strong>g s = e<strong>in</strong>gabeTextFeld.getText();<br />

ausgabeTextFeld.setText(s);<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Vorl11a vorl11a = new Vorl11a();<br />

vorl11a.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

}<br />

}<br />

148


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.1.4 Externe und <strong>in</strong>terne Darstellung von numerischen Werten<br />

Numerische Werte werden<br />

- extern (z.B. im Textfeld e<strong>in</strong>es GUI) durch Zeichenketten dargestellt<br />

- <strong>in</strong>tern als Werte von e<strong>in</strong>em der elementaren Datentypen byte, short, <strong>in</strong>t, long,<br />

float oder double oder als Objekte von e<strong>in</strong>em der Referenzdatentypen (Wrapper-<br />

Klassen) Byte, Short, Integer, Long oder Double. Diese Klassen stellen<br />

Methoden zur Umwandlung von numerischen Werten <strong>in</strong> Zeichenketten und<br />

umgekehrt zur Verfügung. Da nicht jede beliebige Zeichenkette als <strong>in</strong>terne<br />

Darstellung e<strong>in</strong>er Zahl <strong>in</strong>terpretiert werden kann, kann beim Versuch der<br />

Umwandlung e<strong>in</strong>e NumberFormatExpression auftreten, die normalerweise mit<br />

e<strong>in</strong>er try-catch-Anweisung entsprechend behandelt werden sollte.<br />

Bsp.: E<strong>in</strong>lesen und Ausgeben von numersichen Werten<br />

import java.lang.*;<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class EchoZahl extends Object<br />

{<br />

// E<strong>in</strong>lesen und Ausgeben von Zeichenketten ueber<br />

// e<strong>in</strong>e grafische Benutzeroberflaeche<br />

private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

private static TextField ausgabeTextFeld = new TextField(20);<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Frame fenster = new Frame("Echo");<br />

fenster.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

// TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />

Label e<strong>in</strong>gabeTextFeldLabel = new Label("Zahlene<strong>in</strong>gabe:");<br />

e<strong>in</strong>gabeTextFeld.setEditable(true);<br />

e<strong>in</strong>gabeTextFeld.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent ae)<br />

{<br />

Double dRef = null;<br />

Str<strong>in</strong>g s = e<strong>in</strong>gabeTextFeld.getText();<br />

try {<br />

dRef = new Double(s);<br />

}<br />

catch (NumberFormatException nfe)<br />

{<br />

System.err.pr<strong>in</strong>tln(nfe.toStr<strong>in</strong>g());<br />

}<br />

double d = dRef.doubleValue();<br />

d++;<br />

Str<strong>in</strong>g s1 = Double.toStr<strong>in</strong>g(d);<br />

Str<strong>in</strong>g s2 = Str<strong>in</strong>g.valueOf(d);<br />

ausgabeTextFeld.setText(s2);<br />

}<br />

});<br />

// TextField ausgabeTextFeld = new TextField(20);<br />

149


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />

ausgabeTextFeld.setEditable(false);<br />

Panel panel= new Panel();<br />

panel.add(e<strong>in</strong>gabeTextFeldLabel);<br />

panel.add(e<strong>in</strong>gabeTextFeld);<br />

panel.add(ausgabeTextFeldLabel);<br />

panel.add(ausgabeTextFeld);<br />

// Frame fenster = new Frame("Echo");<br />

fenster.add(panel);<br />

fenster.pack();<br />

fenster.setVisible(true);<br />

}<br />

}<br />

3.1.5 Low-Level-Events<br />

Von der Klasse ComponenEvent s<strong>in</strong>d Event-Klassen für "Low-Level"-Ereignisse<br />

abgeleitet. Sie s<strong>in</strong>d für den Transfer von elementaren Nachrichten zuständig, die von<br />

Fenstern und Dialogelementen stammen.<br />

Component-Events<br />

Wird e<strong>in</strong>e Komponente verschoben oder ihre Größe bzw. ihr Anzeigezustand<br />

verändert, dann wird e<strong>in</strong> Componen-Event generiert. Da Fenster und alle<br />

Dialogelemente aus der Klasse Component abgeleitet s<strong>in</strong>d, gelten die hier<br />

angegebenen Ereignisse für nahezu alle GUI-Elemente.<br />

Der Empfänger für ComponentEvent muß das Interface ComponentListener<br />

implementieren und bekommt Events des Typs ComponentEvent übergeben.<br />

ComponentEvent erweiter AWTEvent und stellt neben getID, getSource die<br />

Methode public Component getComponent() bereit, mit der die Komponente<br />

ermittelt werden kann, die die Nachricht ausgelöst hat. Die Registrierung der<br />

Empfängerklasse erfolgt mit public void addComponentListener(ComponentListener<br />

l).<br />

Ereignismethode Bedeutung<br />

componentShown E<strong>in</strong>e Komponente wurde sichtbar<br />

componentHidden E<strong>in</strong>e Komponente wurde unsichtbar<br />

componentMoved E<strong>in</strong>e Komponente wurde verschoben<br />

componentResized Die Größe der Komponente hat sich verändert<br />

Abb.: Übersicht zu den Methoden von ComponentListener<br />

W<strong>in</strong>dow-Events<br />

E<strong>in</strong> W<strong>in</strong>dowEvent wird generiert, falls sich am Status e<strong>in</strong>es Fensters e<strong>in</strong>e Änderung<br />

ergeben hat, die für das Anwenderprogramm <strong>in</strong>teressant se<strong>in</strong> könnte. E<strong>in</strong> Empfänger<br />

für W<strong>in</strong>dow-Events muß das Interface W<strong>in</strong>dowListener implementieren.<br />

W<strong>in</strong>dowEvent stellt neben getID, getSource die Methode public W<strong>in</strong>dow<br />

getW<strong>in</strong>dow() zur Verfügung, mit der das Fenster ermittelt werden kann, das die<br />

Nachricht ausgelöst hat. Die Registrierung der Empfängerklasse erfolgt über die<br />

Methode public void addW<strong>in</strong>dowListener(W<strong>in</strong>dowListener l) , die <strong>in</strong> den<br />

Klassen Dialog und Frame zur Verfügung steht.<br />

150


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Ereignismethode Bedeutung<br />

w<strong>in</strong>dowActivated Das Fenster wurde aktiviert. Die Methode wird nach dem Erstellen des<br />

Fensters aufgerufen und wenn e<strong>in</strong> Fenster, das im H<strong>in</strong>tergrund stand,<br />

erneut <strong>in</strong> den Vordergrund gelangt.<br />

w<strong>in</strong>dowClosed Das Fenster wurde geschlossen<br />

w<strong>in</strong>dowClos<strong>in</strong>g Das Fenster soll geschlossen werden. Diese Methode wird aufgerufen,<br />

wenn der Anwender das Fenster über die TitelLeiste, das Systemmenü<br />

oder die Tastenkomb<strong>in</strong>ation ALT+F4 schließen will. Die Anwendung hat<br />

den Code bereit zu stellen, der das Fenster schließt. Standardmäßig<br />

reagiert das Programm nicht auf diese Benutzeraktionen<br />

w<strong>in</strong>dowDeactivated Das Fenster wurde deaktiviert, also <strong>in</strong> den H<strong>in</strong>tergrung gestellt<br />

w<strong>in</strong>dowDeiconified Das Fenster wurde wiederhergestellt, nachdem es zuvor auf<br />

Symbolgröße verkle<strong>in</strong>ert wurde<br />

w<strong>in</strong>dowIconified Das Fenster wurde auf Symbolgröße verkle<strong>in</strong>ert<br />

w<strong>in</strong>dowOpened Das Fenster wurde geöffnet.<br />

Abb.: Übersicht zu den Methoden von W<strong>in</strong>dowListener<br />

Mouse-Events<br />

E<strong>in</strong> Mouse-Event entsteht, wenn der Anwender (<strong>in</strong>nerhalb der Client-Area des<br />

Fensters) e<strong>in</strong>e der Maustasten drückt oder losläßt. Dabei reagiert das Programm<br />

sowohl auf Klicks der l<strong>in</strong>ken als auch der ( - falls vorhanden -) der rechten Maustaste<br />

und zeigt an, welche der Umschalttasten STRG, ALT, UMSCHALT oder META<br />

während des Mausklicks gedrückt waren. Es ist möglich zwischen e<strong>in</strong>fachen oder<br />

doppelten Mausklicks zu unterscheiden. E<strong>in</strong> Empfänger für Mouse-Events erweitert<br />

die Klasse InputEvent und stellt neben getID, getSource e<strong>in</strong>e Reihe<br />

zusätzlicher Methoden bereit. Die Registrierung der Empfängerklasse erfolgt mit<br />

public void addMouseListener(MouseListener l), die <strong>in</strong> allen Klassen<br />

zur Verfügung steht, die aus Component abgeleitet s<strong>in</strong>d.<br />

Ereignismethode Bedeutung<br />

mousePressed Die Maustaste wurde gedrückt<br />

mouseReleased Die gedrückte Maustaste wurde losgelassen<br />

mouseClicked E<strong>in</strong>e Maustaste wurde gedrückt und wieder losgelassen. Die Methode wird<br />

nach mouseReleased aufgerufen.<br />

mouseEntered Der Mauszeiger wurde <strong>in</strong> den Client-Bereich der auslösenden Komponente<br />

h<strong>in</strong>e<strong>in</strong>bewegt<br />

mouseExited Der Mauszeiger wurde aus dem Client-Bereich der auslösenden<br />

Komponente herausbewegt.<br />

Abb.: Übersicht zu den Methoden von MouseListener<br />

Die Ermittlung der Position des Mauszeigers kann über<br />

public <strong>in</strong>t getX(); // liefert die X-Koord<strong>in</strong>ate<br />

public <strong>in</strong>t getY(); // liefert die Y-Koord<strong>in</strong>ate<br />

public Po<strong>in</strong>t getPo<strong>in</strong>t(); /* liefert X- und Y-Koord<strong>in</strong>ate des Punkts, an dem<br />

sich der Mauszeiger beim Auftreten des Ereignisses bef<strong>in</strong>det */<br />

ermittelt werden. Koord<strong>in</strong>atenwerte werden relativ zum Ursprung der auslösenden<br />

Komponente angegeben.<br />

Weiterh<strong>in</strong> gibt es <strong>in</strong> MouseEvent die Methode isPopUpTrigger. Darüber kann<br />

abgefragt werden, ob das Klickereignis den Ausruf e<strong>in</strong>es Popup-Menüs anzeigen<br />

soll. Die Methode public <strong>in</strong>t getClickCount() liefert die Anzahl der<br />

Mausklicks.<br />

Für die Beabeitung von Mouse-Events stehen außerdem die aus InputEvent<br />

151


118 geerbten Methoden<br />

public boolean isShiftDown();<br />

public boolean isControlDown();<br />

public boolean isMetaDown();<br />

public boolean isAltDown();<br />

zur Verfügung.<br />

MouseMotionEvents<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Sie geben Auskunft über die Bewegung des Mauszeigers. E<strong>in</strong> Empfänger für<br />

"MouseMotionEvents" muß das Interface MouseMotionListener implementieren.<br />

Es wird mit public void addMouseMotionListener(MouseListener l)<br />

registriert. Die Methode steht allen Objekten der Klasse Component oder daraus<br />

abgeleiteteter Klassen zur Verfügung. Die Methoden von MouseMotionListener<br />

bekommen Events des Typs MouseEvent übergeben. Damit stehen diesselben<br />

Methoden wie bei MouseEvent zur Verfügung.<br />

Das Interface MouseMotionListener def<strong>in</strong>iert<br />

public abstract void mouseMoved(MouseEvent e);<br />

// Aufruf bei Bewegung e<strong>in</strong>er Maus ohne Drücken der Maustaste<br />

public abstract void mouseDragged(MouseEvent e);<br />

/* Aufruf bei Bewegung der Maus und gedrückter rechter oder l<strong>in</strong>ker<br />

Maustaste */<br />

Fokus-Events<br />

Der Fokus zeigt an, welches Fenster Tastature<strong>in</strong>gaben erhält. S<strong>in</strong>d mehrere Fenster<br />

gleichzeitig geöffnet, so kann immer nur e<strong>in</strong>es von ihnen den Fokus beanspruchen.<br />

S<strong>in</strong>d auf e<strong>in</strong>em aktiven Fenster mehrere Dialogelemente aktiv, so kann ebenfalls nur<br />

e<strong>in</strong>es davon den Fokus erhalten, denn jedes Dialogelement wird ebenfalls durch e<strong>in</strong><br />

(meist unsichtbares) Fenster dargestellt.<br />

E<strong>in</strong> Empfänger für Fokus-Events muß das Interface FocusListener<br />

implementieren und bekommt Events des Typs FocusEvent übergeben.<br />

FocusEvent erweitert ComponentEvent und stellt neben getID, getSource die<br />

Methode public boolean isTemporary() bereit. Sie zeigt an, ob der<br />

Fokuswechsel temporär oder permanent ist. Die Registrierung von Focus-Events<br />

erfolgt über public void addFocusListener(FocusListener l), die allen<br />

Objekten des Typs Component oder daraus abgeleiteten Objekten zur Verfügung<br />

steht, Das Interface FocusListener enthält zwei unterschiedliche Methoden:<br />

public abstract void focusGa<strong>in</strong>ed(FocusEvent e)<br />

// Aufruf, wenn die Komponente den Fokus erhält<br />

public abstract void focusLost(FocusEvent e)<br />

// Aufruf, wenn die Komonente den Fokus abgibt<br />

Über die Methode public void requestFocus() kann e<strong>in</strong>e Komponente den<br />

Fokus für sich selbst beanspruchen bzw. ihn e<strong>in</strong>er anderen Komponenten zuweisen.<br />

Key-Events<br />

118 InputEvent ist Basisklasse von MouseEvent und KeyEvent. Sie stellt Methoden bereit, die<br />

allgeme<strong>in</strong>e Informationen über den Zustand der Umschalttasten STRG, ALT, UMSCHALT oder META zum<br />

Zeitpunkt des Ereignisses liefern<br />

152


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> Empfänger für Key-Events muß das Interface KeyListener implementieren<br />

und bekommt Events des Typs KeyEvent übergeben. KeyEvent erweitert die<br />

Klasse InputEvent, die aus ComponentEvent abgeleitet ist, und stellt neben<br />

getID, getSource e<strong>in</strong>e Reihe von Methoden zur Erkennung und Berabeitung von<br />

Tastaturcodes zur Verfügung. Die Registrierung erfolgt mit der Methode public<br />

void addKeyListener (KeyListener l), die auf allen Objekten des Typs<br />

Component oder daraus abgeleiteter Klassen zur Verfügung steht. Das Interface<br />

KeyListener def<strong>in</strong>iert drei unterschiedliche Methoden:<br />

public abstract void keyTyped(KeyEvent e);<br />

public abstract void keyPressed(KeyEvent e);<br />

public abstract void keyReleased(KeyEvent e);<br />

Die Taste, die gedrückt wurde, erhält man über die folgenden Methoden der Klasse<br />

KeyEvemt bereitgestellt:<br />

public <strong>in</strong>t getKeyCode()<br />

liefert virtuelle Tastencodes, die <strong>in</strong> KeyEvent als symbolische Konstanten def<strong>in</strong>iert wurden.Hier wird<br />

beim Drücken der Taste A immer der Code VK_A geliefert, unabhängig davon, ob UMSCHALT<br />

gedrückt wurde oder nicht.<br />

Symbolischer Name Bedeutung<br />

VK_0..VK_9 0..9<br />

VK_A..VK_Z A..Z<br />

VK_ENTER Enter<br />

VK_SPACE Leertaste<br />

VK_TAB Tabulator<br />

VK_ESCAPE Escape<br />

VK_BACK_SPACE Rückschritt<br />

VK_F1..VK_F!" Die Funktionstasten F1 .. F12<br />

VK_HOME, VK_END Home, End<br />

VK_PAGE_UP, VK_PAGE_DOWN Bild hoch, Bild runter<br />

VK_DOWN, VK_UP Cursor hoch, Cursor runter<br />

VK_LEFT, VK_RIGHT Cursor l<strong>in</strong>ks, Cursor rechts<br />

VK_INSERT, VK_DELETE E<strong>in</strong>fg, Entf<br />

Abb.: Tabelle der virtuellen Key-Codes<br />

public char getKeyChar()<br />

liefert das Zeichen, das der gedrückten Zeichentste entspricht, z.B. "a", wenn Taste A gedrückt wurde,<br />

und "A", wenn die Tastenkomb<strong>in</strong>ation UMSCHALT + A gedrückt wurde. Funktionstasten werden nicht<br />

übertragen. Der Rückgabewert ist hier KeyEvent.CHAR_UNDEFINED.<br />

getKeyCode getKeyChar<br />

keyTyped119 Zeichentaste120 : VK_UNDEFINED<br />

Funktionstaste121 Zeichentaste: Taste als char<br />

: -<br />

Funktionstaste: -<br />

keyPressed122 Zeichentaste: VK_...<br />

Zeichentaste: Taste als char<br />

Funktionstaste: VK_...<br />

Funktionstaste: CHAR_UNDEFINED<br />

Rückgabecode bei Tastatur-Ereignissen<br />

119 zeigt das Verhalten beim Aufruf der Listener-Methode keyTyped<br />

120 Tasten, mit denen Buchstaben, Ziffern oder sonst. Unicode-Zeichen e<strong>in</strong>gegeben werden, wie z.B. a, A, 1, 2,<br />

% aber auch ESC, SPACE, TAB<br />

121 Dazu gehören bspw. F1, F2, Pos 1 aber auch die Umschalttasten: STRG, ALT, UMSCHALT<br />

122 zeigt das Verhalten beim Aufruf von keyPressed<br />

153


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Zusätzlich stehen fogende aus InputEvent geerbten Methoden zur Verfügung:<br />

public boolean isShiftDown();<br />

public boolean isControlDown();<br />

public boolean isMetaDown();<br />

public boolean isAltDown();<br />

Bsp.: Das folgende Programm 123 schreibt alle möglichen Ereignisse zu Low-Level-<br />

Events auf.<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14166 extends Frame<br />

{<br />

PR14166()<br />

{<br />

addComponentListener(new CL());<br />

addFocusListener(new FL());<br />

addKeyListener(new KL());<br />

addMouseListener(new ML());<br />

addMouseMotionListener(new MML());<br />

}<br />

class CL implements ComponentListener<br />

{<br />

public void componentMoved(ComponentEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void componentResized(ComponentEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void componentHidden(ComponentEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void componentShown(ComponentEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

class FL implements FocusListener<br />

{<br />

public void focusGa<strong>in</strong>ed(FocusEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void focusLost(FocusEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

class KL implements KeyListener<br />

{<br />

public void keyPressed(KeyEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void keyReleased(KeyEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

123 vgl. PR14160<br />

154


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public void keyTyped(KeyEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

class ML implements MouseListener<br />

{<br />

public void mouseClicked(MouseEvent e)<br />

{<br />

// requestFocus();<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void mousePressed(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void mouseReleased(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void mouseEntered(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void mouseExited(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

class MML implements MouseMotionListener<br />

{<br />

public void mouseDragged(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

public void mouseMoved(MouseEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

PR14166 f = new PR14166();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(200,200);<br />

f.setVisible(true);<br />

}<br />

}<br />

Die Lösung zu dieser Aufgabe kann auch über<br />

public void processEvent(AWTEvent e)<br />

erhalten werden. Jede Ereignisquelle besitzt e<strong>in</strong>e Reihe von Methoden, die für das<br />

Aufbereiten und Verteilen der Nachricht zuständig s<strong>in</strong>d. Beim Weiterreichen e<strong>in</strong>er<br />

nachricht wird <strong>in</strong>nerhalb der Nachrichtenquelle die Methode processEvent<br />

aufgerufen. Diese verteilt die Nachricht anhand ihres Typs an spezialisierte<br />

Methoden, deren Name sich nach dem Typ der zugehörigen Ereignisquelle richtet:<br />

155


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public void processComponentEvent(ComponentEvent e)<br />

public void processFocusEvent(FocusEvent e)<br />

public void processKeyEvent(KeyEvent e)<br />

public void processMouseEvent(MouseEvent e)<br />

public void processMouseMoveEvent(MouseEvent e)<br />

public void processActionEvent(ActionEvent e)<br />

Abb.: Spezialisierte Methoden für das Event-Handl<strong>in</strong>g<br />

"processEvent" bzw. die spezialisierten Methoden für das Event-Handl<strong>in</strong>g werden<br />

nur aufgerufen, wenn der entsprechende Ereignistyp für diese Ereignisquelle aktiviert<br />

wurde. Dies geschieht <strong>in</strong> folgenden Fällen:<br />

- E<strong>in</strong> passender Ereignisempfänger wurde über die zugehörige<br />

addEventListener-Methode registriert.<br />

- E<strong>in</strong> Ereignistyp wurde explizit durch Aufruf der Methode protected f<strong>in</strong>al void<br />

enableEvents(long eventsToEnable) aktiviert. Die Methode erwartet e<strong>in</strong>e<br />

Maske, die durch e<strong>in</strong>e bitweise Oder-Verknüpfung passender Konstanten aus der<br />

Klasse AWTEvent zusammengesetzt werden kann.<br />

Bsp.: Das folgende Programm schreibt alle möglichen Ereignisse zu Low-Level-<br />

Events auf.<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14168 extends Frame<br />

{<br />

PR14168()<br />

{<br />

// Bekanntmachen der im Programm zu bearbeitenden Ereignisse<br />

enableEvents(<br />

AWTEvent.COMPONENT_EVENT_MASK |<br />

AWTEvent.FOCUS_EVENT_MASK |<br />

AWTEvent.KEY_EVENT_MASK |<br />

AWTEvent.MOUSE_EVENT_MASK |<br />

AWTEvent.MOUSE_MOTION_EVENT_MASK |<br />

AWTEvent.CONTAINER_EVENT_MASK);<br />

}<br />

public void processEvent(AWTEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

super.processEvent(e);<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

PR14168 f = new PR14168();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(200,200);<br />

f.setVisible(true);<br />

}<br />

}<br />

156


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.2 Kommunikation Anwender – Programm über Dialoge bzw.<br />

Menüs mit vor- oder freidef<strong>in</strong>ierten Dialogelementen<br />

3.2.1 Dialoge<br />

Der Anwender verkehrt im Rahmen grafischer Benutzeroberflächen über vom<br />

Programm vorgegebene Dialoge. Diese bestehen aus e<strong>in</strong>em Fenster und e<strong>in</strong>er<br />

Reihe von Dialogelementen (z.B. Textfelder, Buttons, Listboxen) zur Darstellung und<br />

Erfassung programmspezifischer Daten. Das Design der Dialoge wird von<br />

Layoutmangern unterstützt, die sich um Größe und Anordnung der e<strong>in</strong>zelnen<br />

Dialogelemente kümmern.<br />

Erstellen e<strong>in</strong>es Dialogs<br />

Dafür s<strong>in</strong>d 4 Schritte nötig:<br />

- Anlegen e<strong>in</strong>es Fensters<br />

- Zuordnen e<strong>in</strong>e Layoutmanagers<br />

- E<strong>in</strong>fügen von Dialogelementen<br />

- Anzeigen des Fensters<br />

Anlegen e<strong>in</strong>es Fensters. E<strong>in</strong> Dialogfenster kann wahlweise aus der Klasse Frame<br />

oder Dialog abgeleitet werden. "Dialog" erlaubt "modale Dialoge 124 " und<br />

verh<strong>in</strong>dert das Verändern der Fenstergröße durch den Anwender. Im Gegensatz<br />

zum Frame kann e<strong>in</strong> "Dialog"-Fenster ke<strong>in</strong>e Menüleiste erzeugen und dem Fenster<br />

ke<strong>in</strong> Icon 125 zuordnen.<br />

Zuordnen e<strong>in</strong>es Layoutmanagers. Es wird über die Methode "public void<br />

setLayout(LayoutManager mgr)" der Klasse Conta<strong>in</strong>er realisiert. <strong>Java</strong> stellt<br />

fünf Layoutmanager 126 bereit: FlowLayout BorderLayout, GridLayout<br />

GridBagLayout und CardLayout.<br />

Neben den Fähigkeiten e<strong>in</strong>es Layoutmanagers bestimmt <strong>in</strong> der Regel die<br />

Reihenfolge der Aufrufe von der "add"-Methode des Fensters die tatsächliche<br />

Anordnung der Komponenten auf dem Bildschirm.<br />

Schachteln von Layoutmanagern. Dazu wird an die Stelle, die das Sublayout<br />

erhalten soll, e<strong>in</strong>fach e<strong>in</strong> Objekt der Klasse Panel e<strong>in</strong>gefügt, das e<strong>in</strong>en eigenen<br />

Layoutmanager erhält. Dieses Panel kann mit Dialogelementen bestückt werden, die<br />

entsprechend dem zugeordneten Sublayout formatiert werden, z.B.:<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14171 extends Frame<br />

{<br />

public PR14171()<br />

124 Modale Dialaloge verh<strong>in</strong>dern die Interaktion des Anwenders mit anderen Fenstern der Anwendung bis zum<br />

Schließen des Dialogfensters.<br />

125 Falls e<strong>in</strong> Fenster (unter W<strong>in</strong>dows) m<strong>in</strong>imiert wird, zeigt es e<strong>in</strong> Icon an. Mit Hilfe e<strong>in</strong>es Doppelklicks auf das<br />

Icon kann e<strong>in</strong>e ursprüngliche Größe des Fensters wiederhergestellt werden. Mit Hlife der Methode "public<br />

void setIconImage(Image bild)" kann e<strong>in</strong>em Fenster e<strong>in</strong> Icon zugeordnet werden, das beim<br />

m<strong>in</strong>imieren angezeigt wird.<br />

126 Vgl. 5.4.2<br />

157


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

setVisible(false);<br />

dispose();<br />

System.exit(0);<br />

}<br />

});<br />

// Layout festelegen und Komponenten h<strong>in</strong>zufuegen<br />

<strong>in</strong>t i = 0;<br />

Panel p1 = new Panel();<br />

p1.setLayout(new GridLayout(3,1));<br />

p1.add(new Button("Schaltflaeche " + ++i));<br />

p1.add(new Button("Schaltflaeche " + ++i));<br />

p1.add(new Button("Schaltflaeche " + ++i));<br />

Panel p2 = new Panel();<br />

p2.setLayout(new BorderLayout());<br />

p2.add("North",new Button("Schaltflaeche " + ++i));<br />

p2.add("South",new Button("Schaltflaeche " + ++i));<br />

p2.add("West",new Button("Schaltflaeche " + ++i));<br />

p2.add("East",new Button("Schaltflaeche " + ++i));<br />

p2.add("Center",new Button("Schaltflaeche " + ++i));<br />

// Hauptfenster<br />

setLayout(new GridLayout(1,2));<br />

add(p1);<br />

add(p2);<br />

pack();<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR14171 f = new PR14171();<br />

f.setVisible(true);<br />

}<br />

}<br />

Das vorliegende Programm zeigt nach dem Aufruf das folgende Fenster:<br />

E<strong>in</strong>fügen von Dialogelementen. Es erfolgt über<br />

public Component add(Component komponente)<br />

public Component add(Component komponente, <strong>in</strong>t pos)<br />

public Component add (Str<strong>in</strong>g name, Component komponente)<br />

// erwartet e<strong>in</strong>en Str<strong>in</strong>g-Parameter, der bei bestimmten Layout-Managern<br />

// (z.B. BorderLayout) Informationen zur Positionierung der Elemente ("bei<br />

// BorderLayout: "South", "East", "West", "North", "Center") angibt.<br />

der Klasse Conta<strong>in</strong>er. Mit "public void remove(Component komponente)"<br />

können bereits an das Fenster übergebene Komponenten gelöscht werden.<br />

Anzeigen e<strong>in</strong>es Dialogfensters. Es erfolgt durch e<strong>in</strong>en Aufruf von "setVisible".<br />

Zweckmäßig sollte zuvor "public void pack()" der Klasse W<strong>in</strong>dow zur<br />

Anpassung der Fenstergröße an den für die Darstellung der Dialogelemente<br />

erforderlichen Platz ausgeführt werden.<br />

158


Popup-Fenster der Klasse Dialog<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Klasse Dialog 127 stellt e<strong>in</strong> Popup-Fenster bereit und ermöglicht die Erzeugung<br />

"modaler" bzw. "nicht modaler" Dialoge. "Modal" bedeutet: Das Dialogfeld blockiert<br />

andere Fenster, während es angezeigt wird, z.B. 128 :<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class InfoDialog extends Dialog<br />

{<br />

protected Button schalter;<br />

protected Label label;<br />

public InfoDialog(Frame eltern, Str<strong>in</strong>g titel, Str<strong>in</strong>g nachricht)<br />

{<br />

super(eltern,titel,false);<br />

this.setLayout(new BorderLayout(15,15));<br />

label = new Label(nachricht,Label.CENTER);<br />

this.add("Center",label);<br />

schalter = new Button("Okay");<br />

schalter.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

dispose();<br />

setVisible(false);<br />

}<br />

});<br />

Panel p = new Panel();<br />

p.setLayout(new FlowLayout(FlowLayout.CENTER,15,15));<br />

p.add(schalter);<br />

this.add("South",p);<br />

this.pack();<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Frame f = new Frame("InfoDialog-Test");<br />

f.setSize(300,100);<br />

f.setVisible(true);<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

// dispose();<br />

// setVisible(false);<br />

System.exit(0);<br />

}<br />

});<br />

InfoDialog dlg = new InfoDialog(f,"Dialog-Demo",<br />

"Diese Demo wurde nach e<strong>in</strong>er Vorlage von"<br />

+ "David Flanagan geschrieben");<br />

dlg.setVisible(true);<br />

}<br />

}<br />

Dialogfenster s<strong>in</strong>d Übergangsfenster. Sie dienen dazu, den Benutzer über<br />

Ereignisse zu <strong>in</strong>formieren oder E<strong>in</strong>gabe vom Benutzer anzufordern. Im Gegensatz zu<br />

127 vgl. 5.3.4<br />

128 vgl. PR14170<br />

159


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Frames haben Dialogfelder im allg. ke<strong>in</strong>e Titelleiste oder Schaltfläche zum Schließen<br />

des Fensters.<br />

E<strong>in</strong> Dialogfenster ist, wie e<strong>in</strong> Frame, e<strong>in</strong> Panel, <strong>in</strong> dem Komponenten der<br />

Benutzeroberfläche angeordnet, gezeichnet sowie Grafikoperationen ausgeführt<br />

werden können.<br />

Mit der Klasse FileDialog kann e<strong>in</strong> plattformspezifischer Dateidialog erzeugt<br />

werden.<br />

Bsp.: Laden und Speichern von Dateien mit Unterstützung durch e<strong>in</strong> Dateidialogfeld.<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class DateiDialog extends Frame<br />

{<br />

TextField dateiName = new TextField();<br />

TextField verzeichnis = new TextField();<br />

Button oeffnen = new Button("Oeffnen");<br />

Button sichern = new Button("Sichern");<br />

public DateiDialog()<br />

{<br />

setTitle("Dateidialog-Test");<br />

Panel p = new Panel();<br />

p.setLayout(new FlowLayout());<br />

oeffnen.addActionListener(new OeffnenL());<br />

p.add(oeffnen);<br />

sichern.addActionListener(new SichernL());<br />

p.add(sichern);<br />

add(p,BorderLayout.SOUTH);<br />

verzeichnis.setEditable(false);<br />

dateiName.setEditable(false);<br />

p = new Panel();<br />

p.setLayout(new GridLayout(2,1));<br />

p.add(dateiName);<br />

p.add(verzeichnis);<br />

add(p,BorderLayout.NORTH);<br />

}<br />

class OeffnenL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

FileDialog d = new FileDialog(DateiDialog.this,<br />

"Welche Datei soll geoeffnet werden?");<br />

d.setFile("*.java");<br />

d.setDirectory("."); // Aktuelles Verzeichnis<br />

d.show();<br />

Str<strong>in</strong>g datei = "*.*";<br />

if ((datei = d.getFile()) != null)<br />

{<br />

dateiName.setText(datei);<br />

verzeichnis.setText(d.getDirectory());<br />

}<br />

else {<br />

dateiName.setText("Cancel wurde gedrueckt!");<br />

verzeichnis.setText("");<br />

}<br />

}<br />

}<br />

class SichernL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

FileDialog d = new FileDialog(DateiDialog.this,<br />

"Welche Datei soll gesichert werden?",<br />

FileDialog.SAVE);<br />

d.setFile("*.java");<br />

d.setDirectory("."); // Aktuelles Verzeichnis<br />

160


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

d.show();<br />

Str<strong>in</strong>g datei = "*.*";<br />

if ((datei = d.getFile()) != null)<br />

{<br />

dateiName.setText(datei);<br />

verzeichnis.setText(d.getDirectory());<br />

}<br />

else {<br />

dateiName.setText("Cancel wurde gedrueckt!");<br />

verzeichnis.setText("");<br />

}<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Frame f = new DateiDialog();<br />

f.addW<strong>in</strong>dowListener(<br />

new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(250,110);<br />

f.setVisible(true);<br />

}<br />

}<br />

Bei Applets ist es vom Browser abhängig, ob Instanzen von FileDialog e<strong>in</strong>gesetzt<br />

werden können. Die meisten Browser erzeugen lediglich e<strong>in</strong>en Fehler.<br />

Vordef<strong>in</strong>ierte Dialogelemente<br />

Jedes Dialogelement wird <strong>in</strong> <strong>Java</strong> durch e<strong>in</strong>e eigene Klasse repräsentiert. Zur<br />

Aufnahme e<strong>in</strong>es Dialogelements <strong>in</strong> e<strong>in</strong>en Dialog wird e<strong>in</strong>e neue Instanz der<br />

gewünschten Klasse angelegt und das resultierende Element mit "add" <strong>in</strong> den Dialog<br />

e<strong>in</strong>gefügt. Alle Dialogelemente s<strong>in</strong>d aus der Klasse Component abgeleitet. Sie<br />

verfügen über die grundlegenden Eigenschaften e<strong>in</strong>es Fensters, besitzen Größe und<br />

Position und s<strong>in</strong>d <strong>in</strong> der Lage, Nachrichten zu empfangen und zu bearbeiten.<br />

161


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Component<br />

Button TextComponent Conta<strong>in</strong>er MenuComponent Checkbox<br />

TextField TextArea Menu MenuBar MenuItem<br />

Abb.: Komponenten des AWT<br />

Panel W<strong>in</strong>dow<br />

Applet Frame Dialog<br />

Vordef<strong>in</strong>ierte Dialogelemente unter den Komponenten des AWT s<strong>in</strong>d:<br />

Labels 129 , Schaltflächen(Buttons) 130 , Kontrollkästchen und Optionsfelder 131 ,<br />

Auswahlmenüs 132 , Listenfelder 133 , Textbereiche und Textfelder 134 , Schieberegler 135 .<br />

Das freidef<strong>in</strong>ierte Dialogelement „Canvas“<br />

Die meisten AWT-Komponenten bieten Möglichkeiten für die Ausführung von<br />

Zeichenoperationen. Zeichenbereiche s<strong>in</strong>d Komponenten, die nur speziell zum<br />

Zeichnen ausgerichtet s<strong>in</strong>d. Zeichenbereiche können ke<strong>in</strong>e anderen Komponenten<br />

enthalten, akzeptieren aber Ereignisse. Außerdem können sie Animationen und<br />

Bilder anzeigen. Zum Erstellen e<strong>in</strong>es Zeichenbereichs wird die Klasse Canvas<br />

benutzt. Das eigentliche Zeichnen erfolgt <strong>in</strong> der Methode pa<strong>in</strong>t(Graphics g).<br />

Diese Methode wird immer dann aufgerufen, wenn die Zeichenfäche neu gezeichnet<br />

werden muß. Typische Situationen, <strong>in</strong> denen pa<strong>in</strong>t(Graphics g) aufgerufen<br />

wird, s<strong>in</strong>d:<br />

- Der die Zeichenfläche umfassende Rahmen (Frame) wird ertmals erstellt<br />

- Die Methode repa<strong>in</strong>t() wird explizit aufgerufen<br />

- Die Zeichenfläche wurde teilweise oder ganz von anderen Fenstern überdeckt<br />

- Die Größe der Zeichenfläche hat sich verändert<br />

Durch Überlagerung von public void pa<strong>in</strong>t(Graphics g) sorgt e<strong>in</strong>e Canvas-<br />

Komponente für die Darstellung auf dem Bildschirm. Der Punkt (0,0) des<br />

129 vgl. 5.2.2<br />

130 vgl. 5.2.1<br />

131 vgl. 5.2.3<br />

132 vgl. 5.2.4<br />

133 vgl. 5.2.5<br />

134 vgl. 5.2.6<br />

135 vgl. 5.2.7<br />

162


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

übergebenen Graphics-Objekts entspricht dabei der l<strong>in</strong>ken oberen Ecke des<br />

Ausgabebereichs.<br />

Bsp. 136 : import java.awt.*;<br />

public class KreuzHaar extends java.applet.Applet<br />

{<br />

GridLayout g = new GridLayout(1,1);<br />

Me<strong>in</strong>Canvas can = new Me<strong>in</strong>Canvas();<br />

public void <strong>in</strong>it()<br />

{<br />

setLayout(g);<br />

add(can);<br />

}<br />

}<br />

class Me<strong>in</strong>Canvas extends java.awt.Canvas<br />

{<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

<strong>in</strong>t x = getSize().width / 2;<br />

<strong>in</strong>t y = getSize().height / 2;<br />

g.setColor(Color.black);<br />

g.drawL<strong>in</strong>e(x-10,y,x-2,y);<br />

g.drawL<strong>in</strong>e(x+10,y,x+2,y);<br />

g.drawL<strong>in</strong>e(x,y-10,x,y-2);<br />

g.drawL<strong>in</strong>e(x,y+10,x,y+2);<br />

}<br />

}<br />

Da die Klasse Canvas aus Component abgeleitet ist, bekommt e<strong>in</strong> Canvas-Objekt<br />

alle Ereignisse zugestellt, die auch an e<strong>in</strong>e Komponente gehen. Hierzu zählen:<br />

Tastatur-, Maus-, Mausbewegungs-, Fokus- und Komponentenereignisse.<br />

3.2..2 Menüs<br />

Jedes Fenster / Frame kann e<strong>in</strong>e eigene Menüleiste besitzen. Jede Menüleiste kann<br />

mehrere Menüs enthalten und jedes Menü beliebige E<strong>in</strong>träge 137 .<br />

136 PR52900<br />

137 vgl. 5.3.3<br />

163


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.3 Grundlagen der Applet-Erstellung<br />

3.3.1 HTML-Grundlagen<br />

Die E<strong>in</strong>b<strong>in</strong>dung von <strong>Java</strong>-Applets <strong>in</strong> HTML-Seiten<br />

<strong>Java</strong>-Applets werden <strong>in</strong>nerhalb von HTML-Seiten über Referenzen e<strong>in</strong>gebunden.<br />

Referenzen können Überschriften, Texte, Kapitel, Unterkapitel, Absätze, Grafiken<br />

bzw. L<strong>in</strong>ks zu anderen Seiten se<strong>in</strong>. HTML ist e<strong>in</strong>e Dokumentationsbeschreibungssprache<br />

mit der logische Strukturen e<strong>in</strong>es Dokuments beschrieben werden. Über<br />

Klartext (ASCII-Text) gibt e<strong>in</strong> Dokumentenformat Empfehlungen an e<strong>in</strong>e<br />

Darstellungssoftware (Browser) zur Darstellung der Dokumentstruktur.<br />

Außerdem wird beschrieben, welche Funktionalität wie auszuführen ist, damit sie<br />

dem geplanten Layout und der vorgegebenen Funktionalität entspricht. Es gibt ke<strong>in</strong>e<br />

verb<strong>in</strong>dliche Darstellungsvorschrift, deshalb kann die Ausführung von HTML-Seiten<br />

<strong>in</strong> verschiedenen Browsern oft unterschiedlich anfallen.<br />

Die Basis von HTML<br />

Die Sprache HTML baut auf der Sprache SGML auf. HTML ist die Abkürzung für<br />

Hypertext Markup Language und wurde aus der <strong>in</strong> der ISO-Norm 87779:1986<br />

festgeschriebenen Spache SGML (Structured Generalized Markup Language)<br />

entwickelt. E<strong>in</strong> <strong>in</strong> HTML geschiebenes Dokument kann außer Text, Grafiken und<br />

multimediale Elemente (Sound, Video, usw.) enthalten (Referenz auf Grafik- oder<br />

Multimedia-Dateien). Weiterh<strong>in</strong> können mit gewissen E<strong>in</strong>schränkungen über HTML<br />

Datenbankabfragen formuliert, Resultate optisch aufbereitet und Menüstrukturen<br />

aufgebaut werden.<br />

Die Normung der HTML realisiert und kontrolliert das World Wide Web Consortium<br />

(W3C) mit Sitz <strong>in</strong> Genf. Ende 1997 kam es zu zur offiziellen Verabschiedung des<br />

Standards.<br />

HTML-Steueranweisungen<br />

Tags. Alle HTML-Steueranweisungen werden <strong>in</strong> sog. Tags geschrieben, die von<br />

spitzen Klammern (< >) begrenzt s<strong>in</strong>d. Man unterscheidet zwischen E<strong>in</strong>leitungs- und<br />

Abschluß-Tags. Die Abschluß-Tags s<strong>in</strong>d be<strong>in</strong>ahe identisch mit dem E<strong>in</strong>leitungs-Tag.<br />

Sie besitzen lediglich zusätzlich e<strong>in</strong>en Slash (/) nach dem „


Das Grundgerüst e<strong>in</strong>er HTML-Seite<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e HTML-Seite wird immer <strong>in</strong> die Anweisung am Anfang und am<br />

Ende e<strong>in</strong>geschlossen.<br />

Konkrete Referenzierung e<strong>in</strong>es <strong>Java</strong> Applet<br />

Die konkrete Referenzierung e<strong>in</strong>es <strong>Java</strong>-Applet wird mit dem Applet-Tag e<strong>in</strong>geleitet. Zwischen dem e<strong>in</strong>leitenden Tag und dem abschließenden Applet-<br />

Tag () können benötigte Parameter oder beliebiger Text e<strong>in</strong>gegeben<br />

werden. Die e<strong>in</strong>fachste Form der Applet-Referenz. Ohne irgendwelche Parameter<br />

wird e<strong>in</strong> <strong>Java</strong>-Applet e<strong>in</strong>gebunden mit<br />

<br />

<br />

klassenelement: Applet-Klasse<br />

WIDTH = Wert: Breite des Applet <strong>in</strong> Pixel<br />

HEIGHT = Wert: Höhe des Applet <strong>in</strong> Pixel<br />

Das -Tag erzeugt ke<strong>in</strong>en Absatz, deshalb sollte es <strong>in</strong> e<strong>in</strong>em allgeme<strong>in</strong>en<br />

Text-Tag stehen, z.B. oder <strong>in</strong> e<strong>in</strong>em Überschriften-Tag (, usw.).<br />

Optionale Parameter des -Tag<br />

Parameter Bedeutung<br />

CODEBASE Hier kann e<strong>in</strong> alternatives Verzeichnis 138 für das Laden von Klassendateien<br />

angegeben werden. Fehlt diese Angabe, wird das Dokumentenverzeichnis<br />

genommen.<br />

ARCHIVE Angabe des JAR-Archivs, aus dem die Klassendateien und sonstige Resourcen<br />

des Applet genommen werden<br />

OBJECT Name der Datei, die den serialisierten Inhalt des Applet enthält.<br />

ALT Alternativer Text für Browser, die das Applet verstehen, aber <strong>Java</strong> nicht<br />

unterstützen<br />

NAME E<strong>in</strong>deutiger Name für das Applet. Er kann zur Unterscheidung mehrerer<br />

kommunizierender Applets auf e<strong>in</strong>er Web-Seite verwendet werden.<br />

ALIGN Vertikale Anordnung des Applets <strong>in</strong> e<strong>in</strong>er Textzeile. Hier kann e<strong>in</strong>er der Werte left,<br />

right, top, texttop, middle, absmiddle, basel<strong>in</strong>e, bottom, absbottom angegeben<br />

werden.<br />

VSPACE Rand über und unter dem Applet<br />

HSPACE Rand l<strong>in</strong>ks oder rechts vom Applet<br />

Neben den Parametern des „Applet-Tag“ können auch Parameter an das Applet<br />

selbst übergeben werden. Jeder Parameter kann durch e<strong>in</strong> -Tag über zwei<br />

Attribute für Name (name) und Wert (value) festgelegt werden. Das -Tag<br />

steht zwischen e<strong>in</strong>em öffnenden und schließenden -Tag.<br />

Die Parameter werden beim Laden an das Applet weitergereicht. Innerhalb des<br />

Applets können sie mit der Methode public Str<strong>in</strong>g getParameter(Str<strong>in</strong>g<br />

name) abgefragt werden.<br />

138 Pfadname, <strong>in</strong> dem sich die Klassen bef<strong>in</strong>den<br />

165


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.3.2 Die <strong>in</strong>terne Arbeitsweise e<strong>in</strong>es Applets<br />

E<strong>in</strong> <strong>Java</strong>-Applet besitzt im Gegensatz zu e<strong>in</strong>er <strong>Java</strong>-Anwendung ke<strong>in</strong>e ma<strong>in</strong>()-<br />

Methode, die beim Laden gestartet wird und das Programm solange am Leben hält,<br />

bis es der Benutzer beendet. In e<strong>in</strong>em Applet sorgen vier Methoden dafür, daß sich<br />

das Applet <strong>in</strong> se<strong>in</strong>er Umgebung korrekt verhält.<br />

1. Das Erstellen e<strong>in</strong>es Applets<br />

Zum Erstellen e<strong>in</strong>es Applet muß immer e<strong>in</strong>e „Subklasse“ der Klasse Applet 139<br />

erzeugt werden. <strong>Java</strong> setzt voraus, daß e<strong>in</strong>e Applet-Subklasse public deklariert<br />

wurde. Erkennt <strong>Java</strong> e<strong>in</strong> Applet auf e<strong>in</strong>er Web-Seite, dann wird die Applet-<br />

Ausgangsklasse und die Hilfsklasse, die diese erste Klasse evtl. benutzt, über das<br />

Netz geladen. <strong>Java</strong> erstellt e<strong>in</strong>e Instanz dieser Klasse, alle systembezogenenen<br />

Methoden werden an diese Instanz geschickt. Mehrere Applets auf der gleichen oder<br />

auf unterschiedlichen Seiten verwenden andere Instanzen, so daß sich jedes Applet<br />

auf dem gleichen System evtl. anders verhält.<br />

2. Applet-Methoden<br />

Applets können zahlreiche, unterschiedliche Aktivitäten umfassen, die<br />

verschiedenen wichtigen Ereignissen im Lebenszyklus e<strong>in</strong>es Applet entsprechen,<br />

z.B. Initialisieren, Zeichnen, Mausereignisse. Jeder Aktivität ist e<strong>in</strong>e entsprechende<br />

Methode zugeordnet, d.h.: Falls e<strong>in</strong>e Ereignis stattf<strong>in</strong>det, ruft der Browser (oder e<strong>in</strong><br />

javaähnliches Werkzeug) diese spezifische Methode auf.<br />

Zum Reagieren auf solche Ereignisse s<strong>in</strong>d bestimmte Verhaltensweisen vorzusehen.<br />

Das geschieht durch Überschreiben der jeweiligen Methode <strong>in</strong> der Applet-Subklasse.<br />

Unterschiedliche Applet-Verhalten bedeutet: Jeweils andere Methoden müssen<br />

überschieben werden. Die folgenden Methoden bestimmen den Lebenszyklus e<strong>in</strong>es<br />

Applet:<br />

Rückkehr zur HTML-Seite<br />

<strong>in</strong>it() start() stop() destroy()<br />

Abb.: Lebenszklus e<strong>in</strong>es Applet<br />

166<br />

Verlassen der HTML-Seite<br />

Die Methode <strong>in</strong>it() wird nach dem Laden des Applet ausgeführt. Sie dient zur<br />

Initialisierung.<br />

139 Alle Applets müssen java.applet.Applet <strong>in</strong> die Datei mit der Def<strong>in</strong>ition der Applet-Klasse importieren.<br />

„java.applet.*“ vollzieht das E<strong>in</strong>bunden von „java.applet.Applet“ automatisch. Fast alle Applets (die mit<br />

grafischen schnittstellen) benötigen auch java.awt.*


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Methode start() wird automatisch nach Aufruf der Methode <strong>in</strong>it()<br />

aufgerufen bzw. dann, wenn das Applet <strong>in</strong> den Zustand „aktiv“ versetzt wird. Applets<br />

können <strong>in</strong> zwei Zuständen se<strong>in</strong>: aktiv und <strong>in</strong>aktiv. Nach dem Laden e<strong>in</strong>es Applets ist<br />

dieses zunächst <strong>in</strong>aktiv. Das Applet wechselt <strong>in</strong> den Zustand aktiv, wenn es<br />

erstmalig auf dem Bildschirm ersche<strong>in</strong>t. Von dort aus wechselt es se<strong>in</strong>en Zustand<br />

zwischen aktiv und <strong>in</strong>aktiv. Wodurch dieser Zustandswechsel genau ausgelöst wird,<br />

ist abhängig vom Kontext des Applel, d.h. <strong>in</strong> der Regel vom verwendetet Web-<br />

Browser.<br />

Die Methode stop() wird aufgerufen, wenn die HTML-Seite, <strong>in</strong> der das Applet<br />

e<strong>in</strong>gebunden ist, verlassen wird bzw. das Applet <strong>in</strong> den Zustand <strong>in</strong>aktiv versetzt wird.<br />

Die Methode destroy() zerstört das Applet, nachdem es gestoppt wurde und der<br />

Kontext des Applet sich für e<strong>in</strong>e Zerstörung entscheidet. Die Methode destroy()<br />

sorgt dafür, daß alle vom Applet belegte Ressourcen wieder freigegeben werden.<br />

Vorhandene, vom Applet erzeugte Threads werden ebenfalls zerstört.<br />

Die pa<strong>in</strong>t()-Methode wird <strong>in</strong> <strong>Java</strong> immer aufgerufen, wenn e<strong>in</strong> Applet gezeichnet<br />

werden muß, z.B. be<strong>in</strong> erstmaligen Zeichnen des Applet, beim Verschieben des<br />

Applet-Fenster, beim Überlagern des Applet-Fenster durch e<strong>in</strong> anderes Fenster. Die<br />

pa<strong>in</strong>t()-Methode hat folgende Gestalt:<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

....<br />

}<br />

pa<strong>in</strong>t() besitzt e<strong>in</strong> Argument: e<strong>in</strong>e Instanz der Klasse Graphics. Dieses Objekt<br />

wird vom Browser erstellt und an pa<strong>in</strong>t() abgegeben. Es muß sichergestellt se<strong>in</strong>,<br />

daß die Graphics-Klasse 140 <strong>in</strong> den Code der Applet-Subklasse importiert 141<br />

wird.<br />

Bsp.: „Aller Anfang ist schwer!. Dieser Spruch soll mit Hilfe e<strong>in</strong>es Applet gezeigt<br />

werden.. Die zugehörige Quellcodedatei „AllerAnfangApplet.java“ umfaßt 142 :<br />

import java.applet.*;<br />

import java.awt.*;<br />

public class AllerAnfangApplet extends Applet<br />

{<br />

Font f;<br />

Str<strong>in</strong>g spruch;<br />

//<br />

public void <strong>in</strong>it()<br />

{<br />

f = new Font(„Helvetica“,Font.BOLD,24);<br />

this.spruch = „Aller Anfang ist schwer!“;<br />

}<br />

//<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Oval mit Farbe yellow<br />

g.setColor(Color.yellow);<br />

g.fillOval(10,10,330,100);<br />

// Roter Rahmen; da <strong>Java</strong> ke<strong>in</strong>e L<strong>in</strong>ienbreite kennt,<br />

// wird die L<strong>in</strong>ienbreite durrch 4 Ovale, (die sich<br />

// um Pixelbreite unterscheiden,) simuliert<br />

g.setColor(Color.red);<br />

140 Teil des Pakets java.awt<br />

141 Normalerweise geschieht dies über: import java.awt.Graphics<br />

142 vgl. PR32101<br />

167


g.drawOval(10,10,330,100);<br />

g.drawOval( 9, 9,332,102);<br />

g.drawOval( 8, 8,334,104);<br />

g.drawOval( 7, 7,336,106);<br />

g.setColor(Color.black);<br />

g.setFont(f);<br />

g.drawStr<strong>in</strong>g(this.spruch,40,70);<br />

}<br />

}<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die zugehörige HTML-Datei AllerAnfangApplet.html umfaßt:<br />

<br />

<br />

Hallo!<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

In e<strong>in</strong>em Browser führt das zu der folgenden Darstellung:<br />

<strong>Java</strong>-Applets zeichnen sich durch Überschreiben der „pa<strong>in</strong>t“-Methode selbst. Wie<br />

wird die „pa<strong>in</strong>t“-Methode aufgerufen?<br />

Es gibt drei verschiedene Methoden zum Neuzeichnen e<strong>in</strong>es Applet:<br />

public void pa<strong>in</strong>t(Graphics g)<br />

Sie zeichnet tatsächlich die Grafik des Applets <strong>in</strong> den Zeichenbereich. Sie wird immer aufgerufen,<br />

wenn e<strong>in</strong> Applet neu gezeichnet 143 werden muß. Das <strong>in</strong> der „pa<strong>in</strong>t“-Methode abgebene Graphics-<br />

Objekt enthält den Grafikstatus, d.h. die aktuellen Merkmale der Zeichnungsoberfläche.<br />

public void repa<strong>in</strong>t()<br />

Sie kann jederzeit aufgerufen werden, wann auch immer das Applet neu gezeichnet werden muß. Sie<br />

ist der Auslöser, die „pa<strong>in</strong>t“-Methode sobald wie möglich aufzurufen und das Applet neu zu zeichnen.<br />

Sollten die repa<strong>in</strong>t()-Anweisungen schneller ablaufen, als <strong>Java</strong> diese verarbeiten kann, werden evtl.<br />

143 Dies ist immer beim ersten Aufruf des Applets der Fall, aber auch jedesmal dann, wenn das Applet-Fenster<br />

verschoben oder zwischenzeitlich von e<strong>in</strong>em anderen Fenster überlagert wurde.<br />

168


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

e<strong>in</strong>ige übersprungen. In vielen Fällen ist die Verzögerung zwischen dem Aufruf von repa<strong>in</strong>t() und der<br />

eigentlichen Aktualisierung des Fensters vernachlässigbar.<br />

public void update(Graphics g)<br />

Sie wird von repa<strong>in</strong>t() aufgerufen. Die „update“-Methode löscht den vollständigen<br />

Zeichenbereich 144 und ruft anschließend die „pa<strong>in</strong>t“-Methode auf, die dann das Applet vollständig<br />

neu zeichnet. Der Aufruf der „pa<strong>in</strong>t“-Methode erfolgt also nicht direkt über die „repa<strong>in</strong>t“-Methode,<br />

sondern <strong>in</strong>direkt über die „update“-Methode.<br />

Applets werden aus Sicherheitsgründen gewissen E<strong>in</strong>schränkungen unterworfen:<br />

- Applets können das Dateisystem des Bernutzers nicht lesen und nicht beschreiben, abgesehen von<br />

bestimmten Verzeichnissen (, die vom Benutzer durch e<strong>in</strong>e Zugriffskontrolliste, die standardäßig leer<br />

ist, bestimmt werden). E<strong>in</strong>ige Browser lassen ke<strong>in</strong>erlei Schreib- und Leseaktion des Applets auf dem<br />

Client zu.<br />

- Applets können auf dem Client ke<strong>in</strong>erlei Programme ausführen.<br />

- Applets können normalerweise nur mit dem System kommunizieren, auf denen sie gespeichert s<strong>in</strong>d.<br />

- Applets können ke<strong>in</strong>e ke<strong>in</strong>e nativen Programme der lokalten Plattform laden, auch ke<strong>in</strong>e<br />

geme<strong>in</strong>same Bibliotheken (wie DLL’s).<br />

3. Methoden zur Ereignisbehandlung <strong>in</strong> Applets<br />

E<strong>in</strong> Applet kann auch auf Ereignisse wie Mausbewegungen reagieren. Für soche<br />

Ereignisse (z.B. Drücken der Maustaste) stellt <strong>Java</strong> Ereignisbehandlungs-Methoden<br />

des JDK 1.0 bzw. JDK 1.1 zur Verfügung.<br />

Bsp. 145 : E<strong>in</strong> Applet zum Zeichnen von Punkten an den Stellen, an denen e<strong>in</strong>e<br />

Maustaste gedrückt wurde.<br />

// Import der Pakete<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

// Top-Level Klassen-Deklaration des Applets<br />

public class MausDownPunktApplet extends java.applet.Applet<br />

{<br />

// Variablen-Deklarationen<br />

private <strong>in</strong>t mausX, mausY;<br />

// private boolean mausKlick = false;<br />

// Methoden, die ueberschrieben werden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.yellow);<br />

addMouseListener(new MouseAdapter()<br />

{<br />

public void mouseClicked(MouseEvent e)<br />

{<br />

mausX = e.getX(); mausY = e.getY();<br />

repa<strong>in</strong>t();<br />

}<br />

});<br />

}<br />

/*<br />

public boolean mouseDown(Event e, <strong>in</strong>t x, <strong>in</strong>t y)<br />

{<br />

mausX = x; mausY = y;<br />

mausKlick = true;<br />

repa<strong>in</strong>t();<br />

return true;<br />

}<br />

*/<br />

144 Das ruft oft den unangenehmen Flimmereffekt bei schnellen Bildsequenzen hervor.<br />

145 PR32305<br />

169


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

// Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setColor(Color.blue);<br />

// if (mausKlick)<br />

// {<br />

g.fillOval(mausX,mausY,20,20);<br />

// mausKlick = false;<br />

// }<br />

}<br />

}<br />

Nach jedem Mausklick wird e<strong>in</strong> blauer Punkt <strong>in</strong> die Zeichenfläche gebracht.<br />

Das Bild wird neu gezeichnet. Die repa<strong>in</strong>t()-Methode ruft vor der<br />

Ausführung der pa<strong>in</strong>t()-Methode die update()-Methode auf, die<br />

anschließend pa<strong>in</strong>t() aufruft. „update()“ leert <strong>in</strong> Orig<strong>in</strong>alform den<br />

Anzeigebereich des Applets. Wird update() überschrieben, z.B. durch<br />

public void update(Graphics g)<br />

{<br />

pa<strong>in</strong>t(g);<br />

}<br />

entfällt das Leeren des Anzeigebereichs.<br />

// Import der Pakete<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

// Top-Level Klassen-Deklaration des Applets<br />

public class MausDownPunkteApplet extends java.applet.Applet<br />

{<br />

// Variablen-Deklarationen<br />

private <strong>in</strong>t mausX, mausY;<br />

// private boolean mausKlick = false;<br />

// Methoden, die ueberschrieben werden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.yellow);<br />

addMouseListener(new MouseAdapter()<br />

{<br />

public void mouseClicked(MouseEvent e)<br />

{<br />

mausX = e.getX(); mausY = e.getY();<br />

repa<strong>in</strong>t();<br />

}<br />

});<br />

}<br />

/*<br />

public boolean mouseDown(Event e, <strong>in</strong>t x, <strong>in</strong>t y)<br />

{<br />

mausX = x; mausY = y;<br />

mausKlick = true;<br />

repa<strong>in</strong>t();<br />

return true;<br />

}<br />

*/<br />

// Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setColor(Color.blue);<br />

// if (mausKlick)<br />

// {<br />

g.fillOval(mausX,mausY,20,20);<br />

// mausKlick = false;<br />

// }<br />

}<br />

170


public void update(Graphics g)<br />

{<br />

pa<strong>in</strong>t(g);<br />

}<br />

}<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e überschriebene update()-Methode kann den Flimmereffekt erheblich senken.<br />

3.3.3 „Multithread<strong>in</strong>g“-fähige Applets<br />

Mit Threads können <strong>in</strong> <strong>Java</strong> Applets so erstellt werden, daß alle oder auch e<strong>in</strong>zelnen<br />

Codeteile <strong>in</strong> ihrem eigenen Thread laufen, ohne andere Teile des Systems zu<br />

bee<strong>in</strong>flussen. E<strong>in</strong> Applet kann im wesentlichen über vier Schritte<br />

Multithread<strong>in</strong>g-fähig gemacht werden:<br />

1. Erweitern der Unterschrift des Applets um implements Runnable<br />

2. H<strong>in</strong>zufügen e<strong>in</strong>er Instanzvariablen, die den Thread des Applet enthält<br />

3. Reduktion der start()-Methode, so daß sie außer dem Start des Threads ke<strong>in</strong>e weiteren Threads<br />

enthält<br />

4. H<strong>in</strong>zufügen der run()-Methode, die den eigentlichen Code enthält, den das Applet ausführen soll.<br />

Bsp.: E<strong>in</strong> Applet zur Anzeige von Datum und Uhrzeit, jede Sekunde wird<br />

aktualisiert 146 . Nach den bisher vorliegenden Erkenntnissen müßte das<br />

zugehörige Applet folgende Gestalt haben:<br />

import java.awt.Graphics;<br />

import java.awt.Font;<br />

import java.util.Date;<br />

//<br />

// Top Level Deklaration des Applets<br />

//<br />

public class DigitalUhr extends java.applet.Applet<br />

{<br />

// Variablen-Deklaration<br />

Font e<strong>in</strong>Font = new Font(“TimesRoman“,Font.BOLD,24);<br />

Date datum;<br />

// Eigene Methoden<br />

// Methoden, die ueberschrieben werden<br />

public void start()<br />

{<br />

// Ausfuehrung des Applet<br />

while (true)<br />

{<br />

datum = new Date();<br />

repa<strong>in</strong>t(); // Aufruf der repa<strong>in</strong>t()-Methode<br />

try {Thread.sleep(1000); } // Pause von 1000 Millisekunden<br />

catch(InterruptedException e) {}<br />

}<br />

}<br />

// Optional, aber sehr wahrsche<strong>in</strong>lich – die Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setFont(e<strong>in</strong>Font); // Setzen des aktuellen Font<br />

g.drawStr<strong>in</strong>g(datum.toStr<strong>in</strong>g(),10,50); // Ausgabe Datum<br />

// Da pa<strong>in</strong>t() wiederholt mit jeweils dem aktuellen Wert von<br />

// „datum“ aufgerufen wird, wird die Zeichenkette jede Sekunde<br />

//zur Ausgabe des neuen Datums aufgerufen<br />

}<br />

}<br />

146 vgl. PR42001<br />

171


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

In der start()-Methode nimmt die while-Schleife alle Systemressourcen für<br />

sich <strong>in</strong> Anspruch (e<strong>in</strong>schl. der Anzeige am Bildschirm). Deshalb funktioniert die<br />

digitale Uhr nicht. Außerdem kann das Applet nicht gestoppt werden, da die<br />

stop()-Methode nicht aufgerufen werden kann. Die Lösung des Problems<br />

liegt im erneuten Schreiben des Applets mit Threads. Das Applet muß dazu mit<br />

den vorgegebenen vier Arbeitsschritten erweitert werden.<br />

import java.awt.Graphics;<br />

import java.awt.Font;<br />

import java.util.Date;<br />

//<br />

// Top Level Deklaration des Applets<br />

//<br />

public class DigitalThreadUhr extends java.applet.Applet<br />

implements Runnable<br />

{<br />

// Variablen-Deklaration<br />

Font e<strong>in</strong>Font = new Font(“TimesRoman“,Font.BOLD,24);<br />

Date datum;<br />

Thread faden;<br />

// Eigene Methoden<br />

// Methoden, die ueberschrieben werden<br />

public void start()<br />

{<br />

if (faden == null)<br />

{<br />

faden = new Thread(this);<br />

faden.start();<br />

}<br />

}<br />

public void stop()<br />

{<br />

if (faden != null)<br />

{<br />

faden.stop();<br />

faden = null;<br />

}<br />

}<br />

public void run()<br />

{<br />

// Ausfuehrung des Applet, hier f<strong>in</strong>det die Animation statt<br />

while (true)<br />

{<br />

datum = new Date();<br />

repa<strong>in</strong>t(); // Aufruf der repa<strong>in</strong>t()-Methode<br />

try {Thread.sleep(1000); } // Pause von 1000 Millisekunden<br />

catch(InterruptedException e) {}<br />

}<br />

}<br />

// Optional, aber sehr wahrsche<strong>in</strong>lich – die Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setFont(e<strong>in</strong>Font); // Setzen des aktuellen Font<br />

g.drawStr<strong>in</strong>g(datum.toStr<strong>in</strong>g(),10,50); // Ausgabe Datum<br />

// Da pa<strong>in</strong>t() wiederholt mit jeweils dem aktuellen Wert von<br />

// „datum“ aufgerufen wird, wird die Zeichenkette jede Sekunde<br />

// zur Ausgabe des neuen Datums aufgerufen<br />

}<br />

}<br />

172


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das folgende Gerüst umfaßt e<strong>in</strong> Muster für „multithread<strong>in</strong>g“-fähige Applets:<br />

// Name der Klasse:<br />

// Beschreibung:<br />

// Import der Pakete<br />

// import java.lang.*;<br />

// import java.applet.*;<br />

// import java.awt.*;<br />

// Top-Level-Klassen-Deklaration bzw. Def<strong>in</strong>ition des Applets<br />

public Klassenname extends java.applet.Applet<br />

{<br />

// Variablen-Deklarationen bzw. Def<strong>in</strong>itionen<br />

// ...<br />

// Eigene Methoden<br />

// ...<br />

// Methoden, die ueberschrieben werden<br />

//<br />

public void <strong>in</strong>it()<br />

{<br />

// ...<br />

}<br />

public void start()<br />

{<br />

// ...<br />

}<br />

public void stop()<br />

{<br />

// ...<br />

}<br />

public void destroy()<br />

{<br />

// ...<br />

}<br />

// Optional: die Ausgabemethode<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// ..<br />

}<br />

// Bei Multithread<strong>in</strong>g: Verwendung der run-Methode<br />

public void run()<br />

{<br />

// ...<br />

}<br />

}<br />

173


3.3.4 Animation <strong>in</strong> Applets<br />

Animationsschritte<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong>e Animation umfaßt <strong>in</strong> <strong>Java</strong> zwei Schritte:<br />

1.Aufbau und Ausgabe e<strong>in</strong>es Animationsrahmens (-fenster).<br />

2. Entsprechende häufige Wiederholung der Zeichnung, um den E<strong>in</strong>druck von Bewegung zu vermitteln<br />

(Abspielen e<strong>in</strong>er Animation).<br />

Aufbau e<strong>in</strong>es Animationsrahmens<br />

Dazu gehört alles das, was die Animation vorbereitet, z.B.:<br />

- Ermitteln der Größe des Ausgabebereichs<br />

- Positionieren der Animation<br />

- Erstellen oder Laden der e<strong>in</strong>zelnen Animationsbilder<br />

- Aufbau von e<strong>in</strong>zelnen Animationssequenzen<br />

Abspielen e<strong>in</strong>er Animation<br />

Die pa<strong>in</strong>t()-Methode wird von <strong>Java</strong> aufgerufen, wenn e<strong>in</strong> Applet gezeichnet<br />

werden muß. <strong>Java</strong> kann aber auch aufgefordert werden, e<strong>in</strong> Bild zu e<strong>in</strong>em<br />

bestimmten Zeitpunkt nachzuzeichnen. Tut man das wiederholt und schnell genug<br />

mit der repa<strong>in</strong>t()-Methode, dann entsteht e<strong>in</strong>e Animation. Repa<strong>in</strong>t() ist e<strong>in</strong>e<br />

Anfrage an <strong>Java</strong>, das Applet so schnell wie möglich zu zeichnen.<br />

import java.awt.*;<br />

import java.util.*;<br />

public class PendelAppl1 extends java.applet.Applet implements Runnable<br />

{<br />

// Instanzvariable<br />

// Position vom Zentrum des schw<strong>in</strong>genden Pendels<br />

<strong>in</strong>t x, y;<br />

//<br />

double thetaMax = (double) 0.35;<br />

double thetaM<strong>in</strong> = (double) –0.35;<br />

// Die <strong>in</strong>itiale Position vom Pendel<br />

double theta = (double) 0.;<br />

//<br />

double wechsel = (double) 0.01;<br />

//<br />

<strong>in</strong>t xStart = 150, yStart = 20;<br />

// Radius des Pendels<br />

double r = (double) 200;<br />

// Durchmesser des Balls<br />

<strong>in</strong>t d = 20;<br />

Thread faden;<br />

// Methoden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.yellow);<br />

}<br />

public void start()<br />

{<br />

if (faden == null)<br />

174


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

faden = new Thread(this);<br />

faden.start();<br />

}<br />

}<br />

public void stop()<br />

{<br />

if (faden != null)<br />

{<br />

faden.stop();<br />

faden = null;<br />

}<br />

}<br />

public void run()<br />

{<br />

while (true)<br />

{<br />

x = xStart + (<strong>in</strong>t)(r * Math.s<strong>in</strong>(theta));<br />

y = yStart + (<strong>in</strong>t)(r * Math.cos(theta));<br />

if ((theta >= thetaMax) | (theta


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

import java.awt.*;<br />

public class PendelAppl2 extends java.applet.Applet implements Runnable<br />

{<br />

// Instanzvariable<br />

// Position vom Zentrum des schw<strong>in</strong>genden Pendels<br />

<strong>in</strong>t x, y;<br />

//<br />

double thetaMax = (double) 0.35;<br />

double thetaM<strong>in</strong> = (double) –0.35;<br />

// Die <strong>in</strong>itiale Position vom Pendel<br />

double theta = (double) 0.;<br />

//<br />

double wechsel = (double) 0.01;<br />

//<br />

<strong>in</strong>t xStart = 150, yStart = 20;<br />

// Radius des Pendels<br />

double r = (double) 200;<br />

// Durchmesser des Balls<br />

<strong>in</strong>t d = 20;<br />

Thread faden;<br />

<strong>in</strong>t xAlt, yAlt;<br />

// Methoden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.white);<br />

}<br />

public void start()<br />

{<br />

if (faden == null)<br />

{<br />

faden = new Thread(this);<br />

faden.start();<br />

}<br />

}<br />

public void stop()<br />

{<br />

if (faden != null)<br />

{<br />

faden.stop();<br />

faden = null;<br />

}<br />

}<br />

public void run()<br />

{<br />

while (true)<br />

{<br />

x = xStart + (<strong>in</strong>t)(r * Math.s<strong>in</strong>(theta));<br />

y = yStart + (<strong>in</strong>t)(r * Math.cos(theta));<br />

if ((theta >= thetaMax) | (theta


pa<strong>in</strong>t(g);<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

xAlt = x;<br />

yAlt = y;<br />

}<br />

}<br />

2. Double Buffer<strong>in</strong>g<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Mit „double buffer<strong>in</strong>g“ 148 wird e<strong>in</strong>e zweite Oberfläche geschaffen, <strong>in</strong> der alles<br />

vorgezeichnet und dann auf e<strong>in</strong>mal <strong>in</strong> die Zeichnungsoberfläche des Applet<br />

ausgegeben wird.<br />

import java.awt.*;<br />

public class Pendel extends java.applet.Applet implements Runnable<br />

{<br />

// Instanzvariable<br />

// Position vom Zentrum des schw<strong>in</strong>genden Pendels<br />

<strong>in</strong>t x, y;<br />

//<br />

double thetaMax = (double) 0.35;<br />

double thetaM<strong>in</strong> = (double) –0.35;<br />

// Die <strong>in</strong>itiale Position vom Pendel<br />

double theta = (double) 0.;<br />

//<br />

double wechsel = (double) 0.01;<br />

//<br />

<strong>in</strong>t xStart = 150, yStart = 20;<br />

// Radius des Pendels<br />

double r = (double) 200;<br />

// Durchmesser des Balls<br />

<strong>in</strong>t d = 20;<br />

Thread faden;<br />

<strong>in</strong>t xAlt, yAlt;<br />

Image backgroundImage;<br />

Graphics backgroundGraphics;<br />

// Methoden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.white);<br />

backgroundImage = createImage(this.size().width,<br />

this.size().height);<br />

backgroundGraphics = backgroundImage.getGraphics();<br />

}<br />

public void start()<br />

{<br />

if (faden == null)<br />

{<br />

faden = new Thread(this);<br />

faden.start();<br />

}<br />

}<br />

public void stop()<br />

{<br />

if (faden != null)<br />

{<br />

faden.stop();<br />

faden = null;<br />

}<br />

}<br />

148<br />

177


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public void run()<br />

{<br />

while (true)<br />

{<br />

x = xStart + (<strong>in</strong>t)(r * Math.s<strong>in</strong>(theta));<br />

y = yStart + (<strong>in</strong>t)(r * Math.cos(theta));<br />

if ((theta >= thetaMax) | (theta


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

- das Image-Objekt, das angezeigt werden soll<br />

- die x- und y-Koord<strong>in</strong>ate<br />

- das Schlüsselwort this<br />

Mit pa<strong>in</strong>t() kann das Bild zur Anzeige gebracht werden:<br />

public pa<strong>in</strong>t(Graphigs g)<br />

{<br />

g.drawImage(imageObjekt, xKoord, yKoord, this);<br />

}<br />

Bsp. 150 :<br />

import java.awt.*;<br />

import java.applet.*;<br />

public class ZeichneBild extends Applet<br />

{<br />

private Image bild;<br />

public void <strong>in</strong>it()<br />

{<br />

bild = getImage(getDocumentBase(),"B04240900.jpg");<br />

resize(250, 200);<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

<strong>in</strong>t xPos = 10;<br />

g.drawImage(bild,xPos,10,this);<br />

}<br />

}<br />

3.3.6 Die Ausgabe von Sound<br />

Sound-Ausgabe <strong>in</strong> Applets<br />

Das JDK bietet Möglichkeiten zur Ausgabe von Sound 151 an. Die Ausgabe von<br />

Sound kann über zwei Methoden der Klasse Applet erfolgen:<br />

public void play(URL url)<br />

public void play(URL url, Str<strong>in</strong>g name)<br />

hier kann entweder die URL e<strong>in</strong>er Sound-Datei oder die Komb<strong>in</strong>ation von<br />

Verzeichnis-URL und Date<strong>in</strong>amen angegeben werden. Die Übergabe der URLs<br />

geschieht über die Applet-Methoden:<br />

public URL getCodeBase()<br />

public URL getDocumentbase()<br />

Die Methoden liefern e<strong>in</strong>e URL des Verzeichnisses, aus dem das Applet gestartet wurde bzw. <strong>in</strong> dem<br />

die aktuelle HTML-Seite liegt. Der nachteil dieser Vorgehensweise ist, daß die Sound-datei bei jedem<br />

Aufruf neu geladen werden muß.<br />

150 vgl. PR33501<br />

151 Das JDK 1.2 ermöglicht die Soundausgabe <strong>in</strong> Applets und Applikationen. Frühere Versionen gestatten<br />

Soundausgabe nur für Applets. Die Ausgabe war auf Sound beschränkt, die im AU-Format (stammt aus der Sun-<br />

Welt und legt e<strong>in</strong> Sample im Format 8 Bit Mono, Sampl<strong>in</strong>g-Rate 8 kHz, μ -lawKompression ab) vorliegen<br />

mußte. Seit dem JDK 1.2 werden auch die Sample-Formate WAV und AIFF sowie die Midi-Formate Typ 0 und<br />

Typ 1 und RMF unterstützt. Zudem gibt es e<strong>in</strong>ige Shareware- oder Freeware-Tools, die zwischen verschieden<br />

Formaten konvertieren können (z.B. CoolEdit oder Gold-Wave).<br />

179


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public getAudioClip(URL url, Str<strong>in</strong>g name)<br />

Hier wird e<strong>in</strong> Objekt der Klasse AudioClip beschafft, das dann abgespielt werden<br />

kann. AudioClip stellt drei Methoden zur Verfügung:<br />

public void play()<br />

startet die zuvor geladene Sound-Datei und spielt sie genau e<strong>in</strong>mal ab.<br />

public void loop()<br />

startet die zuvor geladene Sound-Datei und spielt den Sound <strong>in</strong> e<strong>in</strong>er Endlosschleife<br />

immer wieder ab.<br />

public void stop()<br />

Darüber kann die zuvor mit loop() <strong>in</strong>iziierte Schleife beendet werden.<br />

Bsp. 152 :<br />

import java.net.*;<br />

import java.applet.*;<br />

public class PR33602<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

if (args.length >= 1)<br />

{<br />

try {<br />

URL url = new URL(args[0]);<br />

AudioClip clip = Applet.newAudioClip(url);<br />

clip.play();<br />

try {<br />

Thread.sleep(10000);<br />

}<br />

catch (InterruptedException e)<br />

{}<br />

}<br />

catch (MalformedURLException e)<br />

{<br />

System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />

}<br />

}<br />

}<br />

}<br />

Sound-Ausgabe <strong>in</strong> Applikationen<br />

152 Vgl. PR33602<br />

180


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

3.4 Grafische Benutzeroberfläche mit Observable-Observer<br />

Das Zusammenwirken und die Kommunikation zwischen Awendung und grafischer<br />

Benutzeroberfläche sollte folgendermaßen gestaltet se<strong>in</strong>:<br />

- Anwendung und grafische Benutzeroberfläche sollen möglichst unabhängig vone<strong>in</strong>ander se<strong>in</strong>, <strong>in</strong><br />

jedem Fall aber sauber vone<strong>in</strong>ander getrennt se<strong>in</strong> (Anwendungsklasse, GUI-Klasse).<br />

- Jedes GUI-Objekt muß se<strong>in</strong>en Anwendungsfall kennen, um desssen Methoden aufrufen zu können<br />

- Eigentlich müßte umgekehrt jedes Anwendungsobjekt „se<strong>in</strong> GUI-Objekt“ kennen, z.B. zur Anzeige<br />

der Anfangswerte<br />

- Das Hauptprogramm „degeneriert“ zur Erzeugung e<strong>in</strong>es Anwendungs- und GUI-Objekts.<br />

Die Klasse Observable<br />

In <strong>Java</strong> muß das Interesse an e<strong>in</strong>em Objekt durch e<strong>in</strong>e eigene Klasse ausgedrückt<br />

werden. Die eigene Klasse muß von der Klasse Observable abgeleitet se<strong>in</strong>. Die<br />

Observable-Klasse erlaubt es e<strong>in</strong>em Objekt, andere Objekte zu <strong>in</strong>formieren, wenn es<br />

e<strong>in</strong>e Änderung erfährt.<br />

Methoden: Die wichtigsten Methoden beim Erzeugen e<strong>in</strong>er Subklasse von<br />

Observable s<strong>in</strong>d „setChanged“ und „notifyObservers“. Die „setChanged“-<br />

Methode markiert, daß Observable verändert wurde. Beim aufruf von<br />

„notifyObservers“ werden die Observer benachrichtigt.<br />

public synchronized void setChanged()<br />

setzt e<strong>in</strong> <strong>in</strong>ternes Flag für die Modifikation (wird von „notifyObservers“ verwendet). Es wird<br />

automatisch gelöscht, wenn „notifyObservers“ aufgerufen wird, kann aber auch manuell mit der<br />

„clearChanged“-Methode gelöscht werden.<br />

protected synchronized void clearChanged()<br />

public void notifyObservers()<br />

public void notifyObservers(Object arg)<br />

Das Argument kann zur Übergabe zusätzlicher Information über die Modifikation dienen. Ohne<br />

Parameter entspricht der Aufruf e<strong>in</strong>em Aufruf mit dem Argument Null.<br />

public synchronized boolean hasChanged()<br />

public synchronized void deleteObserver (Observer ob)<br />

public synchronized void deleteObservers()<br />

public synchronized <strong>in</strong>t countObservers()<br />

liefert die Anzahl der für <strong>in</strong> Observable registrierten Observer<br />

181


Die Schnittstelle Observable<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Jede Klasse, die Mitteilungen über Modifikationen e<strong>in</strong>es Observable bekommen<br />

möchte, muß das Observer-Interface implementieren. Dieses <strong>in</strong>terfave besteht aus<br />

e<strong>in</strong>er e<strong>in</strong>zigen Methode:<br />

public abstract void update(Observable obs, Object arg)<br />

Sie wird bei e<strong>in</strong>er Objektmodifikation aufgerufen. „obs“ ist das Observable, das<br />

soeben geändert wurde. Wurde „notifyObservers“ ohne Argument aufgerufen,<br />

dann ist arg Null.<br />

Observable-Observer: Kopplung von Anwendung und GUI<br />

182


3.5 Sw<strong>in</strong>g<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Sw<strong>in</strong>g 153 ist e<strong>in</strong>e Erweiterung des Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit, vollständig <strong>in</strong><br />

<strong>Java</strong> 2 <strong>in</strong>tegriert und bietet e<strong>in</strong>e wesentlich verbesserte Funktionalität. Alle Elemente<br />

von Sw<strong>in</strong>g s<strong>in</strong>d Bestandteile des Pakets javax.sw<strong>in</strong>g, die über import<br />

javax.sw<strong>in</strong>g.* <strong>in</strong> Anwendungen e<strong>in</strong>bezogen werden kann.<br />

Sw<strong>in</strong>g-Komponenten werden auf gleiche Weise verwendet wie die Komponenten<br />

des AWT: Erzeugen e<strong>in</strong>er Komponete über den Konstruktor, Aufruf der Methoden<br />

der Komponente.<br />

3.6 <strong>Java</strong> Beans<br />

<strong>Java</strong>Beans ist das Komponentenmodell von <strong>Java</strong>. Diese Komponenten haben e<strong>in</strong>e<br />

genauere und für Programmierwerkzeuge verständlichere Schnittstellendef<strong>in</strong>tion als<br />

<strong>Java</strong>-Klassen. Die zur Beschreibung und Analyse benötigten Interfaces und Klassen<br />

stehen im Package java.beans. Sie arbeiten sehr eng mit den Klassen zur<br />

Laufzeitanalyse von <strong>Java</strong>-Klassen im Paket java.lang.reflect zusammen. Die<br />

Schnittstellen von <strong>Java</strong>Beans bezeichnet man als Features. Sie besteht aus drei<br />

Teilen:<br />

<strong>Java</strong>Beans<br />

Properties Methoden Ereignisse<br />

Abb.: Die <strong>Java</strong>Bean-Features<br />

1. Properties s<strong>in</strong>d die öffentlichen Attribute oder Eigenschaften. Über diese Properties s<strong>in</strong>d Beans an<br />

die Vorstellungen des Programmierers anpassbar, ohne daß er er den Quellcode ändern und<br />

darauf irgende<strong>in</strong> Zugriff haben muß.<br />

2. Die öffentlichen Methoden, die e<strong>in</strong>e Bean ausführen kann<br />

3. E<strong>in</strong> JBean erzeugr Ereignisse, z.B. dann, wenn sich ihre Properties ändern.<br />

Diese drei Arten von Features s<strong>in</strong>d im Interface BeanInfo dokumentiert.<br />

153 vgl. 5.6<br />

183


4. Grafik und Animation<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Mit e<strong>in</strong>er Instanz von Graphics kann gezeichnet werden, z.B.:<br />

Graphics me<strong>in</strong>eGrafik;<br />

me<strong>in</strong>eGrafik = getGraphics();<br />

me<strong>in</strong>eGrafik.drawStr<strong>in</strong>g(“mache irgendwas“,20,40);<br />

Die <strong>in</strong> der Klasse Component als public Graphics getGraphics() def<strong>in</strong>ierte<br />

Methode gibt den „Graphics“-Kontext von der Komponente zurück bzw. Null, wenn<br />

die Komponente ke<strong>in</strong>en aktuellen Grafikbezug hat.<br />

Die meisten Zeichenvorgänge werden jedoch <strong>in</strong> der pa<strong>in</strong>t()-Methode<br />

durchgeführt. <strong>Java</strong>-Applets zeichnen sich selbst neu nach Überschreiben der<br />

pa<strong>in</strong>t()-Methode. Es gibt drei verschieden Methoden 154 zum Neuzeichnen des<br />

Applet:<br />

public void pa<strong>in</strong>t(Graphics g)<br />

public void repa<strong>in</strong>t()<br />

public void update(Graphics g)<br />

4.1 Allgeme<strong>in</strong>e Zeichenvorgänge<br />

4.1.1 Punkte, L<strong>in</strong>ien, Kreise, Bögen<br />

Das Koord<strong>in</strong>atensystem. Der Ausgangspunkt (0,0) des <strong>Java</strong>-Koord<strong>in</strong>atensystems<br />

ist die obere l<strong>in</strong>ke Ecke. Von dieser Stelle führen positive x-Werte nach rechts und<br />

positive y-Werte nach unten. Die Angaben der Koord<strong>in</strong>aten erfolgen <strong>in</strong> Pixel. Alle<br />

Pixelwerte s<strong>in</strong>d Ganzzahlen.<br />

Zeichnen e<strong>in</strong>er L<strong>in</strong>ie. Es geschieht mit der Methode: public abstract void<br />

drawL<strong>in</strong>e(<strong>in</strong>t x1, <strong>in</strong>t y1, <strong>in</strong>t x2, <strong>in</strong>t y2). (x1,y1) bestimmt den<br />

Anfangspunkt, (x2,y2) bestimmt den Endpunkt der L<strong>in</strong>ie.<br />

Bsp.: E<strong>in</strong> Applet mit zufällig verteilten L<strong>in</strong>ien 155<br />

import java.awt.*;<br />

// Top Level Deklaration des Applets<br />

public class L<strong>in</strong>ienApplet extends java.applet.Applet<br />

implements Runnable<br />

{<br />

// Variablen-Deklaration<br />

<strong>in</strong>t x1 = 0;<br />

<strong>in</strong>t x2 = 0;<br />

<strong>in</strong>t y1 = 0;<br />

<strong>in</strong>t y2 = 0;<br />

float rot, gruen, blau;<br />

Color l<strong>in</strong>ienFarbe;<br />

// Eigene Methoden<br />

// Methoden, die ueberschrieben werden<br />

154 vgl. 3.2.2<br />

155 vgl. PR42005<br />

184


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.lightGray);<br />

}<br />

public void start()<br />

{<br />

if (faden == null)<br />

{<br />

faden = new Thread(this);<br />

faden.start();<br />

}<br />

}<br />

public void stop()<br />

{<br />

if (faden != null)<br />

{<br />

faden.stop();<br />

faden = null;<br />

}<br />

}<br />

public void run()<br />

{<br />

// Ausfuehrung des Applet<br />

while (true)<br />

{<br />

x1 = (<strong>in</strong>t) (Math.random() * this.size().width);<br />

x2 = (<strong>in</strong>t) (Math.random() * this.size().width);<br />

y1 = (<strong>in</strong>t) (Math.random() * this.size().height);<br />

y2 = (<strong>in</strong>t) (Math.random() * this.size().height);<br />

rot = (float) Math.random();<br />

gruen = (float) Math.random();<br />

blau = (float) Math.random();<br />

l<strong>in</strong>ienFarbe = new Color(rot,gruen,blau);<br />

repa<strong>in</strong>t(); // Aufruf der repa<strong>in</strong>t()-Methode<br />

try {faden.sleep(1000); } // Pause von 1000 Millisekunden<br />

catch(InterruptedException e) {}<br />

}<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setColor(l<strong>in</strong>ienFarbe);<br />

g.drawL<strong>in</strong>e(x1,y1,x2,y2);<br />

}<br />

}<br />

Die Methode drawL<strong>in</strong>e zeichnet L<strong>in</strong>ien mit e<strong>in</strong>er Dicke von e<strong>in</strong>em Pixel.<br />

Zeichnen e<strong>in</strong>es Rechtecks. Dafür gibt es die Methode: public abstract void<br />

drawRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height). (x1,y1) bestimmt die<br />

obere l<strong>in</strong>ke Ecke e<strong>in</strong>es Rechtecks, (width, height) legen Breite und Höhe des<br />

Rechtecks fest.<br />

Zeichnen e<strong>in</strong>es gefüllten Rechtecks. Es wird ermöglicht durch die Methode: public<br />

abstract void fillRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height). Die<br />

Farbe, mit der das Rechteck gefüllt werden soll, kann mit der folgenden Methode<br />

gesetzt werden: public void setColor(Color c).<br />

Bsp.: E<strong>in</strong> Applet mit zufällig verteilten Rechtecken 156<br />

// zeichne Rechtecke<br />

import java.applet.*;<br />

import java.awt.*;<br />

public class RechteckeAppl3 extends Applet<br />

156 vgl. PR41103<br />

185


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

// Instanzvariable<br />

<strong>in</strong>t appletHoehe;<br />

<strong>in</strong>t appletBreite;<br />

<strong>in</strong>t rechteckHoehe;<br />

<strong>in</strong>t rechteckBreite;<br />

<strong>in</strong>t rechteckTop;<br />

<strong>in</strong>t rechteckL<strong>in</strong>ks;<br />

Color rechteckFarbe;<br />

<strong>in</strong>t anzRechtecke = 100;<br />

// Methoden<br />

public void <strong>in</strong>it()<br />

{<br />

Dimension d = size();<br />

appletHoehe = d.height;<br />

appletBreite = d.width;<br />

repa<strong>in</strong>t();<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

setBackground(Color.white);<br />

g.setColor(Color.black);<br />

g.drawRect(0,0,appletBreite – 1,appletHoehe – 1);<br />

for (<strong>in</strong>t i = 0; i < anzRechtecke; i++)<br />

{<br />

rechteckTop = bestimmeZufallszahl(appletHoehe);<br />

rechteckL<strong>in</strong>ks = bestimmeZufallszahl(appletBreite);<br />

rechteckHoehe = bestimmeZufallszahl(<br />

appletHoehe - rechteckTop);<br />

rechteckBreite = bestimmeZufallszahl(<br />

appletBreite – rechteckL<strong>in</strong>ks);<br />

rechteckFarbe = new Color(bestimmeZufallszahl(255),<br />

bestimmeZufallszahl(255),<br />

bestimmeZufallszahl(255));<br />

g.setColor(rechteckFarbe);<br />

g.fillRect(rechteckL<strong>in</strong>ks,rechteckTop,rechteckBreite-1,<br />

rechteckHoehe – 1);<br />

}<br />

}<br />

private <strong>in</strong>t bestimmeZufallszahl(<strong>in</strong>t bereich)<br />

{<br />

double ausgangsgroesse;<br />

ausgangsgroesse = Math.random();<br />

return (<strong>in</strong>t) (ausgangsgroesse * bereich);<br />

}<br />

}<br />

Löschen e<strong>in</strong>es Rechtecks. Das übernimmt die Methode public abstract void<br />

clearRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height).<br />

Kopieren e<strong>in</strong>es Rechtecks. Dafür gibt es die Methode public abstract void<br />

copyArea(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height, <strong>in</strong>t dx, <strong>in</strong>t dy).<br />

Zeichnen e<strong>in</strong>es 3D-Rechtecks. Es erfolgt mit Hilfe der Methode public void<br />

draw3Drect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height, boolean<br />

raised).<br />

Zeichnen e<strong>in</strong>es gefüllten 3D-Rechtecks.<br />

Zeichnen abgerundeter Rechtecke. Sie können gezeichnet werden mit public<br />

abstract void drawRoundRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t<br />

height, <strong>in</strong>t arcWidth, <strong>in</strong>t arcHeight). „arcwidth“ bestimmt den W<strong>in</strong>kel<br />

der Abrundung auf der horizontalen, „arcHeight“ den W<strong>in</strong>kel auf der vertikalen<br />

Ebene. Je größer die W<strong>in</strong>kel s<strong>in</strong>d, desto stärker gerundet ersche<strong>in</strong>t das Rechteck.<br />

186


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Zeichnen abgerundeter, gefüllter Rechtecke. Dafür existiert die Methode public<br />

abstract void fillRoundRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t<br />

height, <strong>in</strong>t arcWidth, <strong>in</strong>t arcHeight).<br />

Zeichnen von Polygonen. Hierfür kann die Methode public abstract void<br />

drawPolygon(<strong>in</strong>t[] xPunkte, <strong>in</strong>t[] yPunkte, <strong>in</strong>t nPunkte)<br />

herangezogen werden. Es gibt zwei Möglichkeiten beim Zeichnen von Polygonen:<br />

- Weitergabe der beiden Datenbereiche (Arrays) mit den x- und y-Koord<strong>in</strong>aten der Punkte, z.B. 157 :<br />

import java.awt.*;<br />

public class ZeichnePolyAppl1 extends java.applet.Applet<br />

{<br />

// Instanzvariable<br />

// Def<strong>in</strong>ition des Felds mit den x-Koord<strong>in</strong>aten<br />

<strong>in</strong>t xKoord[] = {20,50,70,40,20,20};<br />

// Def<strong>in</strong>ition des Felds mit den y-Koord<strong>in</strong>aten<br />

<strong>in</strong>t yKoord[] = {30,10,20,70,50,30};<br />

// Methoden<br />

public void <strong>in</strong>it() { setBackground(Color.yellow); }<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Zeichne e<strong>in</strong> 5-Eck<br />

g.setColor(Color.red);<br />

g.drawPolygon(xKoord,yKoord,6);<br />

}<br />

}<br />

- Weitergabe e<strong>in</strong>er Instanz der Polygon-Klasse, z.B. 158 :<br />

import java.awt.*;<br />

public class ZeichnePolyAppl2 extends java.applet.Applet<br />

{<br />

// Instanzvariable<br />

// Def<strong>in</strong>ition des Felds mit den x-Koord<strong>in</strong>aten<br />

<strong>in</strong>t xKoord[] = {20,50,70,40,20,20};<br />

// Def<strong>in</strong>ition des Felds mit den y-Koord<strong>in</strong>aten<br />

<strong>in</strong>t yKoord[] = {30,10,20,70,50,30};<br />

// Anzahl Ecken<br />

<strong>in</strong>t anzEcken = xKoord.length;<br />

// Methoden<br />

public void <strong>in</strong>it() { setBackground(Color.yellow); }<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Zeichne e<strong>in</strong> 5-Eck<br />

g.setColor(Color.red);<br />

Polygon poly = new Polygon(xKoord,yKoord, anzEcken);<br />

g.drawPolygon(poly);<br />

}<br />

}<br />

Das Zeichnen von gefüllten Polygonen. Dazu dient die Methode public abstract<br />

void fillPolygon(<strong>in</strong>t[] xPunkte, <strong>in</strong>t[] yPunkte, <strong>in</strong>t nPunkte),<br />

z.B. 159 :<br />

157 PR41105<br />

158 PR41105<br />

159 PR41105<br />

import java.awt.*;<br />

public class ZeichnePolyAppl3 extends java.applet.Applet<br />

{<br />

187


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

// Instanzvariable<br />

// Def<strong>in</strong>ition des Felds mit den x-Koord<strong>in</strong>aten<br />

<strong>in</strong>t xKoord[] = {20,50,70,40,20};<br />

// Def<strong>in</strong>ition des Felds mit den y-Koord<strong>in</strong>aten<br />

<strong>in</strong>t yKoord[] = {30,10,20,70,50};<br />

// Methoden<br />

public void <strong>in</strong>it() { setBackground(Color.yellow); }<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Zeichne e<strong>in</strong> 5-Eck<br />

g.setColor(Color.red);<br />

g.fillPolygon(xKoord,yKoord,5);<br />

}<br />

}<br />

Das Zeichnen von Kreisen und Ellipsen. Es erfolgt über die Methode public<br />

abstract void drawOval(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height).<br />

(x,y) gibt die Koord<strong>in</strong>aten der oberen l<strong>in</strong>ken Ecke des umschreibenden Rechtecks<br />

an.<br />

Das Zeichnen von gefüllten Kreisen und Ellipsen. Es erfolgt über die Methode<br />

public abstract void fillOval(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t<br />

height)<br />

Das Zeichnen von Bögen. <strong>Java</strong> stellt die folgende Methode dafür zur Verfügung:<br />

public abstract void drawArc(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t breite, <strong>in</strong>t<br />

hoehe, <strong>in</strong>t startW<strong>in</strong>kel, <strong>in</strong>t bogenW<strong>in</strong>kel). „startW<strong>in</strong>kel“ bestimmt<br />

den Anfangsw<strong>in</strong>kel von e<strong>in</strong>er (gedachten) horizontalen Mittell<strong>in</strong>ie aus gesehen, ab<br />

dem der Bogen gezeichnet werden soll. „bogenW<strong>in</strong>kel“ legt fest, wie weit der<br />

Bogen ab dem Startpunkt gezeichnet wird und <strong>in</strong> welche Richtung er geht. Die<br />

positive Richtung <strong>in</strong> <strong>Java</strong> ist entgegen dem Uhrzeigers<strong>in</strong>n.<br />

Das Zeichnen von gefüllten Bögen. Es erfolgt über die Methode public abstract<br />

void fillArc(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t breite, <strong>in</strong>t hoehe, <strong>in</strong>t<br />

startW<strong>in</strong>kel, <strong>in</strong>t bogenW<strong>in</strong>kel)<br />

4.1.2 Farbangaben<br />

<strong>Java</strong> setzt Farben aus sog. Primärfarben (Rot, Grün, Blau) des Lichts zusammen<br />

(RGB-Modell). E<strong>in</strong>e Farbe im RGB-Modell wird durch die Angabe, wieviel rotes,<br />

grünes und blaues Licht <strong>in</strong> der Farbe enthalten s<strong>in</strong>d, bestimmt. Dies kann entweder<br />

mit e<strong>in</strong>er Ganzzahl zwischen 0 und 255 oder e<strong>in</strong>er Gleitpunktzahl zwischen 0.0 und<br />

1.0 geschehen.<br />

Farbe Rot-Anteil Grün-Anteil Blau-Anteil<br />

Weiß 255 255 255<br />

Schwarz 0 0 0<br />

Grau 127 127 127<br />

Rot 255 0 0<br />

Grün 0 255 0<br />

Blau 0 0 255<br />

Yellow 255 255 0<br />

Magenta 255 0 255<br />

Cyan 0 255 255<br />

Abb.: Gebräuchliche Farbwerte RGB-Werte)<br />

188


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Neben dem RGB-Farbmodell unterstützt <strong>Java</strong> auch das HSB-Farbmodell. Dieses<br />

stellt e<strong>in</strong>e Farbe durch die drei Parameter Farbton, Intensität und Helligkeit dar.<br />

Die Color-Klasse. Auf drei Arten kann e<strong>in</strong>e Farbe erzeugt werden:<br />

public Color(<strong>in</strong>t red, <strong>in</strong>t green, <strong>in</strong>t blue)<br />

Damit wird e<strong>in</strong>e Farbe mit Rot-, Grün- und Blau-Werten zwischen 0 und 255 erzeugt.<br />

Public Color(<strong>in</strong>t rgb)<br />

public Color(float red, float green, float blue)<br />

E<strong>in</strong>e gängige Farbe kann schneller über die Standardfarbobjekte der <strong>in</strong> der Color-Klasse def<strong>in</strong>ierten<br />

verschiedenen Klassenvariablen gewonnen werden, z.B.:<br />

public static Color white;<br />

public static Color lightGray;<br />

public static Color gray;<br />

public static Color darkGray;<br />

public static Color black;<br />

public static Color red;<br />

public static Color blue;<br />

public static Color green;<br />

public static Color yellow;<br />

public static Color magenta;<br />

public static Color cyan;<br />

public static Color orange;<br />

public static Color p<strong>in</strong>k;<br />

Ermitteln der RGB-Werte von e<strong>in</strong>em bestimmten Farbobjekt. Es erfolgt über<br />

public <strong>in</strong>t getRed();<br />

public <strong>in</strong>t getGreen();<br />

public <strong>in</strong>t getBlue();<br />

Setzen von Farben. Es wird möglich durch die Methode: public abstract<br />

void setColor(Color c). Der Parameter bestimmt das gewünschte Farbobjekt.<br />

Setzen von H<strong>in</strong>tergrundfarben. Normalerweise ist die H<strong>in</strong>tergrundfarbe e<strong>in</strong>es Applets<br />

weiß oder dunkelgrau (je nach Conta<strong>in</strong>er). Individuell kann die H<strong>in</strong>tergrundfarbe<br />

e<strong>in</strong>es Applets gesetzt werden durch: public setBackground(Color c).<br />

Parameter ist das gewünschte Farbobjekt.<br />

Setzen von Vordergrundfarben. Falls die Farbe für alle Zeichenobjekte <strong>in</strong>nerhalb<br />

e<strong>in</strong>es Applets pauschal festgesetzt werden soll, dann kann die Methode public<br />

void setForeground(Color c) verwendet werden.<br />

4.1.3 Textausgabe über den Zeichen-Modus<br />

Die Graphics-Klasse enthält auch Methoden zum Zeichnen von Textzeichen und<br />

Zeichenketten (z.B. die drawStr<strong>in</strong>g() Methode). Zusätzlich spielen die Font-<br />

Klasse160 und die Fontmetrics-Klasse161 beim Textzeichnen e<strong>in</strong>e Rolle.<br />

Die Klasse Font<br />

160 Die Font-Klasse stellt bestimmte Fonts dar (Name, Stil, Fontgröße)<br />

161 Die Fontmetrics-Klasse enthält Informationen über den Font wie tatsächliche Höhe und Breite e<strong>in</strong>es<br />

bestimmten Zeichens.<br />

189


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Texte werden <strong>in</strong> e<strong>in</strong>em standarmäßig bereitgestellten Font ausgegeben. Soll e<strong>in</strong><br />

anderer Font zur Textausgabe verwendet werden, so muß e<strong>in</strong> Objekt der Klasse<br />

Font erzeugt und dem verwendeten Graphics-Objekt zugewiesen werden.<br />

Das Erzeugen neuer Font-Objekte wird über die Parameter name, style <strong>in</strong>d size<br />

des Konstruktors der Klasse Font gesteuert:<br />

public Font(Str<strong>in</strong>g name, <strong>in</strong>t style, <strong>in</strong>t size)<br />

name: Name des gewünschten Font. In allen <strong>Java</strong>-Systemen sollen „SansSerif“, „Serif“, und<br />

„Monospaced“ unterstützt werden. Unter W<strong>in</strong>dows werden die Standardnamen auf die „True-Type-<br />

Fonts“ „Arial“, „TimesNewRoman“ und „CourierNew“ abgebildet.<br />

style: Auswahl der Ausprägung (fett, kursiv)<br />

Name Wert Bedeutung<br />

Font.PLAIN 0 Standard-Font<br />

Font.BOLD 1 fett 162<br />

Font.ITALIC 2 kursiv<br />

size: Angabe der Größe der gewünschten Schriftart <strong>in</strong> Pixel (Punktgrößen)<br />

public void setFont(Font font) wird zum E<strong>in</strong>tragen des Font-Objekts <strong>in</strong> den<br />

Grafikkontext verwendet.<br />

public void getFont() ermittelt den aktuellen Font.<br />

Die Klasse Fontmetrics<br />

Diese Klasse bietet Methoden zur Bestimmung der Größe der angezeigten Zeichen<br />

<strong>in</strong> der festgelegten Schrift an.<br />

Begriffe für Schriften und Text.<br />

Basel<strong>in</strong>e (Grundl<strong>in</strong>ie): Damit ist die imag<strong>in</strong>äre L<strong>in</strong>ie geme<strong>in</strong>t, auf der der Text steht.<br />

Descent (Unterstand): Damit ist geme<strong>in</strong>t, wie weit e<strong>in</strong> Buchstabe über die Grundl<strong>in</strong>ie geht.<br />

Ascent (Überstand): damit ist geme<strong>in</strong>t, wie weit e<strong>in</strong> Buchstabe über die Grundl<strong>in</strong>ie geht.<br />

Lead<strong>in</strong>g (Zeileabstand): Damit ist der Raum zwischen dem Descent e<strong>in</strong>es Buchstabens und dem<br />

Ascent der nächsten Zeile geme<strong>in</strong>t.<br />

Methoden.<br />

Methode Aktion<br />

str<strong>in</strong>gWidth() Gibt die volle Breite e<strong>in</strong>er Zeichenmkette <strong>in</strong> Pixel aus<br />

charWidth() Gibt die Breite e<strong>in</strong>es bestimmten zeichens aus<br />

getAscent() Gibt die Entfernung zwischen der Grundl<strong>in</strong>ie und der oberen Grenze der Buchstaben<br />

aus<br />

getDescent() Gibt die Entfernung zwischen der Grundl<strong>in</strong>ie und der unteren Grenze der Buchstaben<br />

aus (z.B. p und g)<br />

getLead<strong>in</strong>g() Gibt den Abstand zwischen dem Überstand e<strong>in</strong>er Zeile und dem Überstand der<br />

nächsten Zeile aus<br />

getHeight() gibt die Gesamthöhe der Schrift aus, d.h. die Summe von Überstand, Unterstand und<br />

Zeilenabstand<br />

Abb.: Fontmetrics-Methoden<br />

Bsp. 163 :<br />

162 BOLD und ITALIC können auch geme<strong>in</strong>sam verwendet werden, <strong>in</strong>dem beide Konstanten mit „+“<br />

zusammengefügt werden.<br />

163 PR41301<br />

190


import java.applet.*;<br />

import java.awt.*;<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class AllAnfAppl extends Applet<br />

{<br />

private static f<strong>in</strong>al Str<strong>in</strong>g spruch = "Aller Anfang ist schwer!";<br />

private Font font;<br />

private FontMetrics fontMetrics;<br />

private <strong>in</strong>t spruchBreite;<br />

private <strong>in</strong>t spruchAscent;<br />

private <strong>in</strong>t spruchDescent;<br />

private <strong>in</strong>t spruchX;<br />

private <strong>in</strong>t spruchY;<br />

// Methoden<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.white);<br />

font = new Font("Helvetica",Font.BOLD,24);<br />

fontMetrics = null;<br />

}<br />

//<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Oval mit Farbe yellow<br />

g.setColor(Color.yellow);<br />

g.fillOval(0,0,getSize().width,getSize().height);<br />

// Roter Rahmen; da <strong>Java</strong> ke<strong>in</strong>e L<strong>in</strong>ienbreite kennt,<br />

// wird die L<strong>in</strong>ienbreite durrch 4 Ovale, (die sich<br />

// um Pixelbreite unterscheiden,) simuliert<br />

g.setColor(Color.red);<br />

g.drawOval( 3, 3,getSize().width-6,getSize().height-6);<br />

g.drawOval( 2, 2,getSize().width-4,getSize().height-4);<br />

g.drawOval( 1, 1,getSize().width-2,getSize().height-2);<br />

g.drawOval( 0, 0,getSize().width,getSize().height);<br />

g.setColor(Color.black);<br />

g.setFont(font);<br />

if (fontMetrics == null)<br />

{<br />

fontMetrics = g.getFontMetrics();<br />

spruchBreite = fontMetrics.str<strong>in</strong>gWidth(spruch);<br />

spruchAscent = fontMetrics.getAscent();<br />

spruchDescent = fontMetrics.getDescent();<br />

}<br />

<strong>in</strong>t breite = getSize().width;<br />

<strong>in</strong>t hoehe = getSize().height;<br />

spruchX = (breite - spruchBreite) / 2;<br />

spruchY = (hoehe + spruchAscent - spruchDescent) / 2;<br />

g.drawStr<strong>in</strong>g(spruch,spruchX,spruchY);<br />

}<br />

}<br />

191


4.1.4 Die <strong>Java</strong>-Zeichenmodi<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Graphics-Klasse verfügt über zwei verschiedene Modi zum Zeichnen: den Pa<strong>in</strong>t-<br />

Modus und den XOR-Modus.<br />

4.2 Das Zeichnen von Bildern (Bitmaps)<br />

4.2.1 Kopieren von Speicher <strong>in</strong> e<strong>in</strong> Bild<br />

E<strong>in</strong> möglicher Typ für das Produzieren von Bildern ist e<strong>in</strong> Datenfeld mit ganzen<br />

Zahlen, die für die farbe e<strong>in</strong>es jeden Pixels stehen. Möglich wird das durch die<br />

Klasse MemoryImageSource.<br />

Bsp.: Das folgende Applet erzeugt e<strong>in</strong> Speicherbild, e<strong>in</strong>e MemoryImageSource und<br />

zeichnet das Bild im Zeichenbereich.<br />

import java.applet.*;<br />

import java.awt.*;<br />

import java.awt.image.*;<br />

/* das Applet zeichnet e<strong>in</strong> Image und benutzt dazu<br />

e<strong>in</strong>en Array mit Pixeln<br />

*/<br />

public class SpeicherBild extends Applet<br />

{<br />

private f<strong>in</strong>al static <strong>in</strong>t b = Color.blue.getRGB();<br />

private f<strong>in</strong>al static <strong>in</strong>t r = Color.red.getRGB();<br />

private f<strong>in</strong>al static <strong>in</strong>t g = Color.green.getRGB();<br />

<strong>in</strong>t pixels[] = {<br />

b, b, b, b, b, b, b, b, b, b,<br />

b, b, b, b, b, b, b, b, b, b,<br />

b, b, g, g, g, g, g, g, b, b,<br />

b, b, g, g, g, g, g, g, b, b,<br />

b, b, g, g, r, r, g, g, b, b,<br />

b, b, g, g, r, r, g, g, b, b,<br />

b, b, g, g, g, g, g, g, b, b,<br />

b, b, g, g, g, g, g, g, b, b,<br />

b, b, b, b, b, b, b, b, b, b,<br />

b, b, b, b, b, b, b, b, b, b<br />

};<br />

Image me<strong>in</strong>Bild;<br />

public void <strong>in</strong>it()<br />

{<br />

/* Erzeigen des Bilds aus dem Array pixels.<br />

Die Pixels werden zeilenweise von Postion 0<br />

aus dem Array gelesen. e<strong>in</strong>e Zeile umfasst 10<br />

Postionen.<br />

*/<br />

me<strong>in</strong>Bild = createImage(<br />

new MemoryImageSource(10,10,pixels,0,10));<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

// Zeichen das Bild.<br />

// Breite und Hoehe des Bilds werden 10fach vergroessert<br />

g.drawImage(me<strong>in</strong>Bild,0,0,100,100,this);<br />

}<br />

}<br />

192


Abb.: Darstellung von SpeicherBild<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die PixelGrabber-Klasse nimmt e<strong>in</strong> Bild und macht aus diesem e<strong>in</strong> Datenfeld mit<br />

ganzen Zahlen.<br />

Der PixelGrabber ist für Modifikationen bereits existierender Bilder nützlich.<br />

4.2.2 Laden und Anzeigen e<strong>in</strong>er Bitmap<br />

Das Anzeigen e<strong>in</strong>er Bitmap kann <strong>in</strong> zwei Schritte unterteilt werden:<br />

- Das Laden der Bitmap von e<strong>in</strong>em externen Speichermedium oder aus dem Netz<br />

- Die eigentliche Ausgabe auf dem Bildschirm<br />

Laden von Bitmaps. Es erfogt mit der Methode getImage, die es <strong>in</strong> verschiedenen<br />

Varianten 164 gibt:<br />

4.2.3 Die Klasse Mediatracker<br />

4.2.4 Entwicklung e<strong>in</strong>er eigenen Bitmap-Componente<br />

4.2.5 Abspielen e<strong>in</strong>er Foge von Bitmaps<br />

164 Sie unterscheiden sich dadurch, aus welcher Quelle sie die Bitmap-datei laden.<br />

193


4.3 2D <strong>Java</strong><br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

2D <strong>Java</strong> ist Bestandteil der <strong>Java</strong> Foundation Classes (JFC), e<strong>in</strong> Teil dessen, was<br />

Sun Sw<strong>in</strong>g nennt und sämtliche Techniken umfaßt, die die GUI-Fähigkeit von <strong>Java</strong><br />

ausmachen. Das neue <strong>Java</strong>-2D-API ist e<strong>in</strong> Satz von Klassen für erweiterte 2D-Grafik<br />

und die Bildverarbeitung.<br />

4.3.1 Das Zeichnen unter <strong>Java</strong> 2D-API<br />

Zeichnen unter dem AWT Draw<strong>in</strong>g Model<br />

Dieses Modell wurde bisher zum Zeichnen verwendet, z. B.:<br />

import java.awt.*;<br />

import java.applet.*;<br />

public class MaleGefRechteck extends Applet<br />

{<br />

// Zeichnen unter dem AWT Draw<strong>in</strong>g Model<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

g.setColor(Color.red);<br />

g.fillRect(300,300,200,100);<br />

}<br />

}<br />

Die Vorgehensweise beim Bearbeiten für jede Komponente kann aus diesem Bsp.<br />

unmittelbar abgeleitet werden:<br />

1. Spezifikation der notwendigen Atribute für die zu zeichnende Form, z.B. die Farbe mit „setColor“.<br />

2. Def<strong>in</strong>ition der zu zeichnenden Form<br />

3. Festlegen des genauen Aussehens der Form, z.B. über e<strong>in</strong>e passende Grafikmethode.<br />

Zeichnen unter <strong>Java</strong> 2D-API<br />

Das <strong>Java</strong> 2D-API umfaßt zusätzliche unterstützende Features zur Spezifizierung von<br />

Zeichenstiften, komplexe Formen und diverse Zeichenprozesse. Zur Nutzung dieser<br />

Möglichkeit muß der Graphics-Parameter der pa<strong>in</strong>t()-Mthode <strong>in</strong> e<strong>in</strong> Graphics2D-<br />

Objekt gebracht werden („gecastet“) werden, z.B.:<br />

import java.awt.*;<br />

import java.applet.*;<br />

import java.awt.geom.*;<br />

public class MaleGefRechteck extends Applet<br />

{<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

Graphics2D g2d = (Graphics2D) g;<br />

// Spezifikation der Attribute<br />

g2d.setColor(Color.red);<br />

// Def<strong>in</strong>ition der Form (Verwende Even-Odd-Regel)<br />

GeneralPath path = new GeneralPath();<br />

path.moveTo(300.0f,400.0f); // untere l<strong>in</strong>ke Ecke<br />

194


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

path.l<strong>in</strong>eTo(500.0f,400.0f); // untere rechte Ecke<br />

path.l<strong>in</strong>eTo(500.0f,300.0f); // obere rechte Ecke<br />

path.l<strong>in</strong>eTo(300.0f,300.0f); // obere l<strong>in</strong>ke Ecke<br />

path.closePath(); // Schliessen des Rechtecks<br />

// Fuellen der Form<br />

g2d.fill(path);<br />

}<br />

}<br />

Zur Def<strong>in</strong>ition des Rechtecks wird die neue <strong>Java</strong> 2D-API-Klasse GeneralPath<br />

(Bestandteil des geom-Pakets 165 ) herangezogen. Das Erstellen von Standardformen<br />

(z.B. Rechtecke Ellipsen, Bögen, Kurven) kann e<strong>in</strong>facher über diverse Subklassen<br />

der Klasse Shape (<strong>in</strong> Verb<strong>in</strong>dung mit GeneralPath) erfolgen.<br />

Verfahrensweise beim Zeichnen mit den <strong>Java</strong> 2D-API-Klassen<br />

1. Spezifikation der notwendigen beschreibenden Attribute<br />

2. Def<strong>in</strong>ition der Form, e<strong>in</strong>es Textstr<strong>in</strong>gs oder e<strong>in</strong>es Bilds.<br />

Das <strong>Java</strong> 2-D-API behandelt Positionsangeben (Pfade), Texte und Bilder gleichartig.<br />

Sie können rotiert, skaliert, verzerrt und mit diversen Methoden zusammengesetzt<br />

werden. Das „Shape“-Interface def<strong>in</strong>iert e<strong>in</strong>en ganzen Satz von Methoden zur<br />

Beschreibung von geometrischen PATH-Objekten. GeneralPath ist e<strong>in</strong>e<br />

Implementation vom Shape-Interface, das zur Def<strong>in</strong>ition von beliebig komplexen<br />

Formen verwendet werden kann.<br />

3. Festlegen vom Aussehen der Form, des Textstr<strong>in</strong>gs oder des Bildes über<br />

passende Graphics2D-Methoden.<br />

<strong>Java</strong> 2D API-Klassen<br />

Außer der Klasse java.awt.Graphics2D umfaßt <strong>Java</strong> 2D API Klassen <strong>in</strong> den<br />

Paketen java.awt.geom (geometrische Formen, Pfade und Transformationen),<br />

java.awt.font, java.awt.color (Farbräume), java.awt.image und<br />

java.awt.image.renderable (Bitmaps und Filter) sowie java.awt.pr<strong>in</strong>t<br />

(Drucken).<br />

4.3.3 Farbmanagement unter 2D-<strong>Java</strong><br />

4.3.4 2D-Bildverarbeitung<br />

4.3.5 Render<strong>in</strong>g<br />

165 Graphics2D ist Bestandteil des Pakets java.awt<br />

195


5. AWT<br />

5.1 Bestandteile des AWT<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

In <strong>Java</strong> wird die Kommunikation mit dem Anwender hauptsächlich über e<strong>in</strong> eigenes<br />

Konzept realisiert – dem Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit. Das AWT besitzt zur<br />

Kommunikation mit dem Anwender e<strong>in</strong> Application Programm<strong>in</strong>g Interface (API).<br />

Darüber können allgeme<strong>in</strong>e Komponenten der Benutzeroberfläche, z.B.<br />

Schaltflächen oder Menüs, plattformunabhängig genutzt werden.<br />

5.2 Die AWT-Komponenten<br />

Die AWT stellt Komponenten für den Anwender bereit. Die von Anfang an<br />

vorhandenen Komponenten 166 des AWT s<strong>in</strong>d: Schaltflächen (Buttons), Labels,<br />

Kontrollkästchen (Checkbuttons), Optionsfelder (Radiobuttons), Listen,<br />

Auswahlfelder, Textfelder, Menüs, Zeichenbereiche.<br />

Zusätzlich gibt es Conta<strong>in</strong>er, <strong>in</strong> die die Komponenten zum Erstellen vollständiger und<br />

s<strong>in</strong>nvoller Anwendungsschnittstellen <strong>in</strong>tegriert se<strong>in</strong> müssen. Die Conta<strong>in</strong>er im AWT<br />

s<strong>in</strong>d Fenster, Panels, Frames, Dialoge.<br />

E<strong>in</strong> weiterer Bestandteil der AWT s<strong>in</strong>d Layout-Manager. E<strong>in</strong> Layout-Manager ist <strong>in</strong><br />

jedem Conta<strong>in</strong>er enthalten. Er f<strong>in</strong>det – angepaßt an die jeweilige Situation –<br />

automatisch heraus, an welche Stelle die Komponenten am besten passen. Der<br />

AWT stellt 5 verschiedene Typen von Layout-Managern zur Verfügung: Flow-,<br />

Border-, Grid-, Gridbag-Layout.<br />

Schließlich stellt AWT die Mittel zur Reaktion auf Ereignisse zur Verfügung, die vom<br />

Anwender über Komponenten ausgelöst werden können.<br />

Die Wurzel fast aller AWT-Komponenten ist die Klasse Component. Sie enthält die<br />

grundlegenden Anzeige- und Event-Handl<strong>in</strong>g-Funktionen.<br />

Component<br />

Canvas Conta<strong>in</strong>er TextComponent Button<br />

Panel W<strong>in</strong>dow TextField<br />

Applet Frame Dialog<br />

Abb. AWT-Klassenhierarchie<br />

166 <strong>Java</strong> 1.2 und das Sw<strong>in</strong>g-Konzept erweitern diese Komponenten noch e<strong>in</strong>mal um e<strong>in</strong>en satz von neuen und<br />

ergänzenden Komponenten.<br />

196


5.2.1 Schaltflächen (Buttons)<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Erzeugen. Schaltflächen (Buttons) s<strong>in</strong>d Elemente e<strong>in</strong>er grafischen<br />

Benutzeroberfläche, die auf Knopfdruck Aktionen <strong>in</strong> der Fensterklasse auslösen. Mit<br />

den folgenden Konstruktoren kann e<strong>in</strong>e Schaltfläche erstellt werden:<br />

- Button() erzeugt e<strong>in</strong>e leere Schaltfläche ohne Beschriftung<br />

- Button(Str<strong>in</strong>g label) erzeugt e<strong>in</strong>e Schaltfläche mit der durch das Str<strong>in</strong>g-Objekt<br />

bezeichneten Beschriftung.<br />

In e<strong>in</strong>em Applet 167 reicht dafür aus: add(new Button(“Auf los geht’s<br />

los!“));.<br />

Beschriftungen e<strong>in</strong>er Schaltfläche können dynamisch zur Laufzeit gesetzt und wieder<br />

verändert werden. Dazu dient die Methode: public void setLabel(Str<strong>in</strong>g<br />

label). Welche Beschriftung die Schaltfläche angenommen hat, ermittelt die<br />

Methode public Str<strong>in</strong>g getLabel();.<br />

Reaktionen auf die Betätigung von Schaltflächen (JDK 1.1). Falls e<strong>in</strong> Button gedrückt<br />

wird, sendet es e<strong>in</strong> Action-Event an se<strong>in</strong>e Ereignisempänger. Diese müssen das<br />

Interface ActionListener implementieren und sich durch den Aufruf von<br />

„addActionListener“ registrieren:<br />

public void addActionListener(ActionListener l)<br />

public void removeActionListener(ActionListener l)<br />

Das Action-Event führt im Ereignisempfänger zum Aufruf der Methode public<br />

void actionPerformed(ActionEvent ae) ,die die Methode<br />

getActionCommand aufrufen kann, mit der die Beschriftung des Button abgefragt<br />

werden kann. Falls das Action-Kommando nicht mit der Beschriftung identisch ist,<br />

kann es <strong>in</strong> der Button-Klasse durch „public void setActionCommand(Str<strong>in</strong>g<br />

kommando)“ geändert werden.<br />

Bsp.: Setzen von H<strong>in</strong>tergrundfarben nach verschiedenen Buttonklicks 168<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class SchaltApplet extends java.applet.Applet<br />

{<br />

private Button schalt1 = new Button("Rot");<br />

private Button schalt2 = new Button("Blau");<br />

private Button schalt3 = new Button("Gruen");<br />

private Button schalt4 = new Button("Gelb");<br />

private Button schalt5 = new Button("Schwarz");<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.white);<br />

schalt1.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.red);<br />

}<br />

});<br />

schalt2.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

167 Abgeleitet von der Panel-Klasse<br />

168 PR52105<br />

197


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

setBackground(Color.blue);<br />

}<br />

});<br />

schalt3.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.green);<br />

}<br />

});<br />

schalt4.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.yellow);<br />

}<br />

});<br />

schalt5.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.black);<br />

}<br />

});<br />

this.setLayout(new BorderLayout(15,15));<br />

Panel p = new Panel();<br />

p.setLayout(new FlowLayout(FlowLayout.CENTER,15,15));<br />

p.add(schalt1);<br />

p.add(schalt2);<br />

p.add(schalt3);<br />

p.add(schalt4);<br />

p.add(schalt5);<br />

this.add("South",p);<br />

// this.pack();<br />

}<br />

}<br />

Reaktionen auf die Betätigung von Schaltflächen (JDK 1.0). Die Komponenten<br />

<strong>in</strong>nerhalb der AWT-Oberfläche besitzen e<strong>in</strong>e action()-Methode, die aufgerufen<br />

wird, wenn bei e<strong>in</strong>er Komponente e<strong>in</strong>e Aktion ausgführt wurde. Beim Betätigen<br />

(Auslösen) e<strong>in</strong>er Schaltfläche wird die action()-Methode aufgerufen. Die<br />

action()-Methode gehört zu den Ereignisbehandlungsmethoden des Event<br />

Handl<strong>in</strong>g. Die Syntax der action()-Methode ist bei allen Komponenten identisch:<br />

public boolean action(Event ereignis, Objekct welcheAktion).<br />

Ereignis: Ereignis, das bei der Komponente aufgetreten ist<br />

welcheAktion: steht für das, was geschehen ist<br />

Bei Schaltflächen ist die Art der Aktion (welcheAktion) ganz e<strong>in</strong>fach über das Label<br />

(Beschriftung) der Schaltfläche auszuwerten, die ausgelöst wurde. Der „Event“-<br />

Parameter enthält spezifische Informationen über die Aktion, z.B.:<br />

event.target (Komponente, bei der die Aktion e<strong>in</strong>getreten ist)<br />

event.when (Zeitpunkt, zu dem die Aktion geschehen ist)<br />

Mit dem <strong>in</strong>stanceof-Operator kann die event.target-Variable überprüft<br />

werden, ob die Aktion auch für das Objekt erfolgt, das gewünscht wird.<br />

Bsp.: Setzen von H<strong>in</strong>tergrundfarben nach verschiedenen Buttonklicks 169<br />

169 vgl. PR52105<br />

198


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

import java.awt.*;<br />

public class KnopfAktApplet extends java.applet.Applet<br />

{<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.white);<br />

this.setLayout(new BorderLayout(15,15));<br />

Panel p = new Panel();<br />

p.setLayout(new FlowLayout(FlowLayout.CENTER,15,15));<br />

p.add(new Button(„Rot“));<br />

p.add(new Button(„Blau“));<br />

p.add(new Button(„Gruen“));<br />

p.add(new Button(„Gelb“));<br />

p.add(new Button(„Schwarz“));<br />

this.add(„South“,p);<br />

}<br />

public boolean action(Event e, Object arg)<br />

{<br />

// Test auf Schaltflaechenaktion<br />

if (e.target <strong>in</strong>stanceof Button)<br />

aendereFarbe((Str<strong>in</strong>g) arg);<br />

return true;<br />

}<br />

void aendereFarbe(Str<strong>in</strong>g knopfName)<br />

{<br />

// Aendern der H<strong>in</strong>tergrundfarbe<br />

if (knopfName.equals(„Rot“)) setBackground(Color.red);<br />

else if (knopfName.equals(„Blau“)) setBackground(Color.blue);<br />

else if (knopfName.equals(„Gruen“)) setBackground(Color.green);<br />

else if (knopfName.equals(„Gelb“)) setBackground(Color.yellow);<br />

else if (knopfName.equals(„Schwarz“)) setBackground(Color.black);<br />

else;<br />

}<br />

}<br />

5.2.2 Labels<br />

Labels s<strong>in</strong>d Zeichenketten zur Beschriftung anderer Komponenten der<br />

Benutzeroberfläche. E<strong>in</strong> Label umfaßt e<strong>in</strong>e Zeile Text, die auf dem Bildschirm<br />

angezeigt wird und vom Programm veränder werden kann.<br />

Konstruktoren. public Label()<br />

public Label(Str<strong>in</strong>g text)<br />

public Label(Str<strong>in</strong>g text, <strong>in</strong>t ausrichten)<br />

Der Parameter „ausrichten“ bestimmt die Ausrichtung des Texts. Hier kann e<strong>in</strong>e<br />

der Konstanten Label.LEFT, Label.Right, Label.CENTER übergeben werden.<br />

Methoden. Public void setText(Str<strong>in</strong>g text)<br />

// Zugriff auf die Textzeile des Label<br />

public Str<strong>in</strong>g getText()<br />

// Zugriff auf die Textzeile des Label<br />

public void setAlignment(<strong>in</strong>t ausrichten)<br />

// Ausrichten der Textzeile<br />

public <strong>in</strong>t getAlignment()<br />

// Ausrichten der Textzeiele<br />

5.2.3 Kontrollkästchen und Optionsfelder<br />

199


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Erzeugen von Kontrollkästchen. E<strong>in</strong> Kontrollkästchen (Checkbutton / Checkbox)<br />

hat zwei Bestandteile: e<strong>in</strong> Label (Text, der neben dem Kontrollkästchen angelegt<br />

wird) und e<strong>in</strong>em Zustand (boolesche Variable, die angibt, ob die Box e<strong>in</strong>geschaltet<br />

wurde oder nicht 170 ). Zum Erzeugen von Kontrollkästchen gibt es 5 Konstruktoren<br />

- Checkbox()<br />

(Kontrollkästchen ohne Label)<br />

- Checkbox(Str<strong>in</strong>g label)<br />

(Kontrollkästchen mit Beschriftung)<br />

- Checkbox(Str<strong>in</strong>g label,boolean zustand)<br />

Checkbox mit Vorgabe des Anfangszustands<br />

- Checkbox(Str<strong>in</strong>g label,CheckboxGroup cbg,boolean zustand)<br />

(Kontrollkästchen, das jenach gesetzter boolescher Zustandsvariable vorselektiert (true) ist oder<br />

nicht (false). Das mittlere Argument ist bei Kontrollkästchen immer auf Null gesetzt. Falls das nicht<br />

der Fall ist, dient der Parameter cbg zum Gruppieren von Radiobuttons.<br />

- Checkbox(Str<strong>in</strong>g label, boolean zustand,CheckboxGroup cbg)<br />

Plazieren von Kontrollkästchen <strong>in</strong> e<strong>in</strong>em Conta<strong>in</strong>er. Es erfolgt über die Methode<br />

add(), z.B.: add(new Checkbox(“<strong>Java</strong>“));.<br />

Überprüfen und Setzen von Kontrollkästchen. Mit der Methode public boolean<br />

getState() kann überprüft werden, ob e<strong>in</strong> Kontrollkästchen angeglickt wurde. Die<br />

Methode public void setState(boolean zustand) setzt den Status (true<br />

für gesetzt). Die getlabel()-Methode fragt das Label des jeweiligen<br />

Kontrollkästchens ab.<br />

Reaktion auf Zustandsänderungen. E<strong>in</strong>e Checkbox generiert e<strong>in</strong> Item-Event, wenn<br />

die Markierung vom Anwender gesetzt oder zurückgenommen wird. Zur Reaktion auf<br />

dieses Event ist durch den Aufruf von addItemListener e<strong>in</strong> Objekt, das das<br />

Interface ItemListener implementiert, bei der Checkbox zu registrieren. In<br />

diesem Fall wird e<strong>in</strong> Ereignisempfänger die Methode itemStateChanged mit<br />

e<strong>in</strong>em Argument vom Typ ItemEvent aufgerufen:<br />

public abstract void itemStateChanged(ItemEvent e)<br />

Über das ItemEvent kann die Methode getItemSelectable aufgerufen werden,<br />

mit der ermittelt werden kann, durch welche Checkbox das Ereignis ausgelöst wurde:<br />

public ItemSelectable getItemSelectable().<br />

Der Rückgabewert kann <strong>in</strong> e<strong>in</strong> Objekt des Typs Checkbox konvertiert werden. Durch<br />

Aufruf von „getState“ kann der aktuelle Zustand bestimmt werden.<br />

Bsp.: import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR52301 extends Frame<br />

{<br />

Checkbox<br />

cb1 = new Checkbox(„Checkbox 1“),<br />

cb2 = new Checkbox(„Checkbox 2“,true),<br />

cb3 = new Checkbox(„Checkbox_3“,false);<br />

public PR52301()<br />

{<br />

setLayout(new GridLayout(3,1));<br />

setBackground(Color.lightGray);<br />

cb1.addItemListener(new CBL());<br />

cb2.addItemListener(new CBL());<br />

170 Standardmäßig ist die Box ausgeschaltet (Wert ist false oder „off“).<br />

200


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

cb3.addItemListener(new CBL());<br />

add(cb1);<br />

add(cb2);<br />

add(cb3);<br />

}<br />

public class CBL implements ItemListener<br />

{<br />

public void itemStateChanged(ItemEvent e)<br />

{<br />

Checkbox cb = (Checkbox) e.getItemSelectable();<br />

System.out.pr<strong>in</strong>tln(cb.getLabel() + „: „ + cb.getState());<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR52301 f = new PR52301();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(100,150);<br />

f.setVisible(true);<br />

}<br />

}<br />

Def<strong>in</strong>tion zur CheckboxGroup. E<strong>in</strong>e CheckboxGroup ist die <strong>Java</strong>-Variante e<strong>in</strong>er<br />

Gruppe von Radiobuttons (Optionsfelder), von den genau immer e<strong>in</strong>er aktiviert wird.<br />

Wird e<strong>in</strong>e anderer Button aktiviert, so änder er se<strong>in</strong>en <strong>in</strong>ternen Status auf „true“<br />

und der zuvor gesetzte wird „false“. E<strong>in</strong>e CheckboxGroup ist nichts Anderes als<br />

e<strong>in</strong>e Checkbox, deren CheckboxGroup-Parameter gesetzt ist.<br />

Erzeugen von Optionsfeldern (Radiobuttons). Erforderlich ist zunächst e<strong>in</strong>e<br />

Checkbox-Gruppe, die über die betreffenden Konstruktoren erstellt werden kann.<br />

Dieser Gruppe werden die e<strong>in</strong>zelnen Optionsfelder h<strong>in</strong>zugefügt.<br />

Plazieren von Optionsfeldern <strong>in</strong> e<strong>in</strong>em Conta<strong>in</strong>er. Auch Optionsfelder müssen wie<br />

alle Komponenten nach der Erzeugung <strong>in</strong> e<strong>in</strong>en Conta<strong>in</strong>er gebracht werden. Das<br />

geschieht über die Methode add().<br />

Setzen und Überprüfen von Optionsfeldern. Die Methoden getState() und<br />

getLabel() funktionieren auch bei Optionsfeldern. Zum Zugriff auf die Gruppe<br />

e<strong>in</strong>es Optionsfelds und zum Ändern gibt es die Methoden:<br />

public CheckboxGroup getCheckboxGroup()<br />

public void setCheckboxGroup(CheckboxGroup g)<br />

Zum Holen und Setzen des momentan ausgewählten Optionsfelds dienen<br />

public Checkbox getCurrent()<br />

public void setCurrent(Checkbox box)<br />

Bsp.: import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR52302 extends Frame<br />

{<br />

CheckboxGroup<br />

cbg = new CheckboxGroup();<br />

public PR52302()<br />

{<br />

setLayout(new GridLayout(3,1));<br />

setBackground(Color.lightGray);<br />

201


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Checkbox cb1 = new Checkbox(„rot“,cbg,false);<br />

Checkbox cb2 = new Checkbox(„blau“,cbg,false);<br />

Checkbox cb3 = new Checkbox(„gruen“,cbg,false);<br />

cb1.addItemListener(new CBL());<br />

cb2.addItemListener(new CBL());<br />

cb3.addItemListener(new CBL());<br />

add(cb1);<br />

add(cb2);<br />

add(cb3);<br />

}<br />

public class CBL implements ItemListener<br />

{<br />

public void itemStateChanged(ItemEvent e)<br />

{<br />

Checkbox cb = (Checkbox) e.getItemSelectable();<br />

if (cb.getLabel() == „rot“)<br />

{<br />

if (cb.getState())<br />

{<br />

System.out.pr<strong>in</strong>tln(„rot“);<br />

}<br />

}<br />

if (cb.getLabel() == „blau“)<br />

{<br />

if (cb.getState())<br />

{<br />

System.out.pr<strong>in</strong>tln(„blau“);<br />

}<br />

}<br />

if (cb.getLabel() == „gruen“)<br />

{<br />

if (cb.getState())<br />

{<br />

System.out.pr<strong>in</strong>tln(„gruen“);<br />

}<br />

}<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR52302 f = new PR52302();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(100,150);<br />

f.setVisible(true);<br />

}<br />

}<br />

Reaktionen auf Kontrollfelder und Radiobuttons im JDK1.0. Kontrollfelder und<br />

Radiobuttons verfügen wie alle Komponenten über die action()-Methode. Sie wird<br />

bei e<strong>in</strong>er Auswahl aufgerufen, sobald e<strong>in</strong> Feld selektiert wird.<br />

Bsp. 171 : import java.awt.*;<br />

public class CheckAktApplet extends java.applet.Applet<br />

{<br />

CheckboxGroup me<strong>in</strong>eCheckboxGruppe = new CheckboxGroup();<br />

public void <strong>in</strong>it()<br />

171 PR54305<br />

202


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

add(new Checkbox(„Blau“,me<strong>in</strong>eCheckboxGruppe,false));<br />

add(new Checkbox(„Rot“,me<strong>in</strong>eCheckboxGruppe,false));<br />

add(new Checkbox(„Gruen“,me<strong>in</strong>eCheckboxGruppe,false));<br />

add(new Checkbox(„Gelb“,me<strong>in</strong>eCheckboxGruppe,true));<br />

// H<strong>in</strong>tergrundfarbe passend zur Vore<strong>in</strong>stellung<br />

setBackground(Color.yellow);<br />

}<br />

public boolean action(Event e, Object welcheAktion)<br />

{<br />

// Test auf Kontrollkaestchen oder Radiobutton<br />

if (!(e.target <strong>in</strong>stanceof Checkbox))<br />

return false;<br />

// Instanz der Ereignisse<br />

Checkbox welcheAuswahl = (Checkbox) e.target;<br />

// Status des Radiobuttons zur Kontrolle<br />

boolean CheckboxStatus = welcheAuswahl.getState();<br />

// Auswahl Blau<br />

if (welcheAuswahl.getLabel() == „Blau“)<br />

{<br />

if (CheckboxStatus)<br />

setBackground(Color.blue);<br />

return true;<br />

}<br />

// Auswahl Rot<br />

if (welcheAuswahl.getLabel() == „Rot“)<br />

{<br />

if (CheckboxStatus)<br />

setBackground(Color.red);<br />

return true;<br />

}<br />

// Auswahl Gruen<br />

if (welcheAuswahl.getLabel() == „Gruen“)<br />

{<br />

if (CheckboxStatus)<br />

setBackground(Color.green);<br />

return true;<br />

}<br />

if (welcheAuswahl.getLabel() == „Gelb“)<br />

{<br />

if (CheckboxStatus)<br />

setBackground(Color.yellow);<br />

return true;<br />

}<br />

return false; // ke<strong>in</strong>e der Optionen wird aufgefangen<br />

}<br />

}<br />

203


5.2.4 Auswahlmenüs<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Es handelt sich um Popup- bzw. Pulldown-Menüs, die sich beim Anklicken öffnen<br />

und mehrere auszuwählende Optionen anzeigen, von denen dann e<strong>in</strong>e Option<br />

ausgewählt werden kann.<br />

Konstruktor: public Choice()<br />

// erstellt e<strong>in</strong> Choice-Objekt mit e<strong>in</strong>er leeren Liste.<br />

Bearbeiten der Liste (Combobox) zum Auswahlmenü: public void<br />

addItem(Str<strong>in</strong>g item) Jeder Aufruf von addItem hängt das übergebende<br />

Element „item“ an das Ende der Liste an. Die Elemente werden <strong>in</strong> der Reihenfolge<br />

der Aufrufe von addItem e<strong>in</strong>gefügt.<br />

Zugriff auf die Elemente der Combobox: public <strong>in</strong>t getSelectionIndex()<br />

liefert den Index des ausgwählten Elements. Durch Übergabe dieses Werts (an<br />

„getItem“ kann das aktuelle Element beschafft werden: public Str<strong>in</strong>g<br />

getItem(<strong>in</strong>t n). Über public Str<strong>in</strong>g getSelectedItem() kann ohne<br />

Kenntnis der <strong>in</strong>ternen Nummer (Index) das ausgewählte Element beschafft werden.<br />

Programmseitige Auswahl e<strong>in</strong>es Elements:<br />

public select(<strong>in</strong>t)<br />

// Auswahl über den Index<br />

public select(Str<strong>in</strong>g s)<br />

// Auswahl über den angegebenen Wert von Str<strong>in</strong>g<br />

Ereignisbehandlung. Ebenso wie e<strong>in</strong>e Checkbox sendet auch e<strong>in</strong> Choice-Element<br />

„Item“-Ereignisse, wenn e<strong>in</strong> Element ausgewählt wurde. Zur Reaktion auf dieses<br />

Element muß e<strong>in</strong> ItemListener durch Aufruf von public void<br />

addItemListener(ItemListener l) registriert se<strong>in</strong>. E<strong>in</strong> „ItemEvent“ wird<br />

immer dann gesendet, wenn e<strong>in</strong> Element ausgewählt wurde. In diesem Fall wird e<strong>in</strong><br />

Ereignisempfänger die Methode itemStateChanged mit e<strong>in</strong>em Argument vom Typ<br />

ItemEvent aufrufen: public abstract void<br />

itemStateChanged(ItemEvent e). Das „ItemEvent“ stellt die Methode<br />

public ItemSelectable getItemSelectable() zur Verfügung, mit der<br />

ermittelt werden kann, durch welches Choice-Element das Ereignis ausgewählt<br />

wurde. Zusätzlich gibt es public Object getItem(), die das ausgewählte<br />

Element als Str<strong>in</strong>g zur Verfügung stellt.<br />

Bsp.:<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14174 extends Frame<br />

{<br />

TextField t = new TextField(30);<br />

Choice auswahl = new Choice();<br />

public PR14174()<br />

{<br />

auswahl.addItem(„rot“);<br />

auswahl.addItem(„blau“);<br />

auswahl.addItem(„gruen“);<br />

auswahl.addItem(„p<strong>in</strong>k“);<br />

auswahl.addItem(„orange“);<br />

auswahl.addItem(„gelb“);<br />

auswahl.addItem(„cyan“);<br />

add(auswahl);<br />

pack();<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR14174 f = new PR14174();<br />

f.addW<strong>in</strong>dowListener(<br />

new W<strong>in</strong>dowAdapter()<br />

204


}<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setBackground(Color.lightGray);<br />

f.setVisible(true);<br />

}<br />

5.2.5 Listenfelder<br />

E<strong>in</strong>e Instanz der Klasse List ist e<strong>in</strong>e listenartige Darstellung von Werten, aus denen<br />

Anwender e<strong>in</strong>en oder mehrere auswählen kann. Anders als e<strong>in</strong> Choice-Element ist<br />

e<strong>in</strong> Element der Klasse List ständig <strong>in</strong> voller Größe auf dem Bildschirm sichtbar.<br />

Erzeugen von Listenfeldern. Public List()<br />

// legt e<strong>in</strong>e leere Liste an, deren dargestellte Größe durch den<br />

// Layoutmanager begrenzt wird.<br />

public List(<strong>in</strong>t groesse)<br />

// Der Parameter groesse legt die Anzahl der angezeigten Zeilen fest.<br />

public List(<strong>in</strong>t groesse, boolean multiselect)<br />

// ist multiselect „true“, kann der Anwender nicht nur e<strong>in</strong> Element, sondern<br />

//auch andere Elemente auswählen<br />

Mehrfachauswahl ausgewählter Elemente. „List“ bietet nahezu dieselbe<br />

Funktionalität wie Choice an. Zusätzlich stehen zur Verfügung:<br />

public <strong>in</strong>t[] getSelectedIndexes()<br />

// liefert e<strong>in</strong>en Array mit den Indexpositionen der ausgewählten<br />

// Elemente.<br />

public Str<strong>in</strong>g[] getSelectedItems()<br />

// liefert e<strong>in</strong>e Liste der Werte.<br />

Auswahl e<strong>in</strong>zelner Elemente.<br />

Public void select(<strong>in</strong>t <strong>in</strong>dex)<br />

public void deselect(<strong>in</strong>t <strong>in</strong>dex)<br />

Entfernen, Verändern von Elementen.<br />

Public void delItem(<strong>in</strong>t <strong>in</strong>dex)<br />

// löscht das Element an der Position <strong>in</strong>dex<br />

public void remove(<strong>in</strong>t <strong>in</strong>dex)<br />

// löscht das Element an der Position <strong>in</strong>dex<br />

public void replaceItem(Str<strong>in</strong>g neuerWert,<strong>in</strong>t <strong>in</strong>dex)<br />

// ersetzt das Element an der Position <strong>in</strong>dex durch die Postion<br />

// neuerWert.<br />

Item- und Action-Ereignisse. E<strong>in</strong> Listenelement sendet Item- und Action-<br />

Ereignisse. E<strong>in</strong> Action-Ereignis wird generiert, wenn e<strong>in</strong> Listenelement durch<br />

Doppelklick ausgewählt wurde. E<strong>in</strong> Item-Ereignis wird ausgelöst, nachdem <strong>in</strong> der<br />

Liste e<strong>in</strong> Element ausgewählt wurde.<br />

Bsp.:<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14177 extends Frame<br />

{<br />

Str<strong>in</strong>g[] farben = {„rot“,“blau“,“gruen“,“p<strong>in</strong>k“,“orange“,<br />

„gelb“,“cyan“};<br />

List lst = new List(6,true);<br />

public PR14177()<br />

{<br />

205


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

setLayout(new FlowLayout());<br />

for (<strong>in</strong>t i = 0; i < 7; i++)<br />

lst.addItem(farben[i]);<br />

add(lst);<br />

lst.addItemListener(new ILL());<br />

lst.addActionListener(new ALL());<br />

pack();<br />

}<br />

public class ILL implements ItemListener<br />

{<br />

public void itemStateChanged(ItemEvent e)<br />

{<br />

List lst = (List) e.getItemSelectable();<br />

Str<strong>in</strong>g str = lst.getSelectedItem();<br />

<strong>in</strong>t pos = ((Integer) e.getItem()).<strong>in</strong>tValue();<br />

System.out.pr<strong>in</strong>tln(„event.getSelectedItem: „ + str + „ „ + pos);<br />

}<br />

}<br />

class ALL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

Object obj = e.getSource();<br />

if (obj <strong>in</strong>stanceof List)<br />

{<br />

System.out.pr<strong>in</strong>tln(„Listenfeld-Aktion: „<br />

+ e.getActionCommand());<br />

}<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR14177 f = new PR14177();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

// f.setVisible(false);<br />

System.exit(0);<br />

}<br />

});<br />

f.setBackground(Color.lightGray);<br />

// f.setSize(100,160);<br />

f.setVisible(true);<br />

}<br />

}<br />

5.2.6 Textbereiche und Textfelder<br />

Das AWT verfügt über Klassen zur E<strong>in</strong>gabe von Text (Klasse TextField für<br />

Textfelder und Klasse TextArea für Textbereiche). Textfelder begrenzen die Menge<br />

des e<strong>in</strong>zugebenden Textes und können nicht gescrollt werden. In Textbereichen<br />

können mehrere Zeilen verarbeitet werden, außerdem s<strong>in</strong>d Textbereiche scrollbar.<br />

TextField<br />

E<strong>in</strong> TextField dient zur Darstellung von Text. Anwender und Programm können den<br />

dargestellten Text e<strong>in</strong>lesen und verändern.<br />

Erzeugen von Textfeldern. Es stehen folgende Konstruktoren zur Verfügung:<br />

206


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public TextField()<br />

erzeugt e<strong>in</strong> leeren Textfeld, <strong>in</strong> das der Anwender Text e<strong>in</strong>geben kann.<br />

Public TextField(<strong>in</strong>t greite)<br />

Erzeugt e<strong>in</strong> leeres Textfeld bestimmter Breite. Die Anzahl e<strong>in</strong>zugebender Zeichen ist nicht begrenzt. Ist<br />

der Text länger, so scrollt er <strong>in</strong>nerhalb des Textfelds<br />

public TextField(Str<strong>in</strong>g text)<br />

Über den Parameter text kann e<strong>in</strong>e Zeichenkette vorgegeben werden, die beim aufruf des Textfelds<br />

vorgelegt wird.<br />

public TextField(Str<strong>in</strong>g text, <strong>in</strong>t breite)<br />

Methoden zum Zugriff bzw. Verändern von Textfeldern.<br />

public Str<strong>in</strong>g getText();<br />

public void setText(Str<strong>in</strong>g text)<br />

Mit<br />

public <strong>in</strong>t getColumns()<br />

kann die Anzahl der darstellbaren Zeichen e<strong>in</strong>es Textfelds abgefragt und mit<br />

public void setColumns(<strong>in</strong>t spalten)<br />

verändert werden.<br />

Markieren von Text. public void selectAll()<br />

markiert den kompletten Bereich<br />

public void select(<strong>in</strong>t erstes, <strong>in</strong>t letztes)<br />

markiert den Bereich von „erstes“ bis „letztes“. Das „Zählen“ beg<strong>in</strong>nt bei 0.<br />

Mit<br />

public <strong>in</strong>t getSelectionStart()<br />

bzw.<br />

public <strong>in</strong>t getSelectEnd()<br />

kann die aktuelle Auswahl begefragt werden. Mit<br />

public <strong>in</strong>t getCaretPosition()<br />

und<br />

public void setCaretPosition(<strong>in</strong>t position)<br />

kann auf die aktuelle Cursorposition zugegriffen werden.<br />

Bearbeiten von Textfeldern. Über<br />

public void setEditable(boolean erlaubt)<br />

// Aufruf mit Parameter false unterb<strong>in</strong>det weitere E<strong>in</strong>gaben<br />

bzw.<br />

public boolean isEditable() // Abfrage des aktuellen Status<br />

kann mit die Veränderung von Text verh<strong>in</strong>dern. Mit<br />

public void setEchoCharacter(char z)<br />

(Übergabe e<strong>in</strong>es Zeichens, das beim Tastendruck anstelle des vom anwender e<strong>in</strong>gegebenen Zeichens<br />

ausgegeben wird)<br />

bzw.<br />

public char getEchochar()<br />

besteht die Möglichkeit verdeckter E<strong>in</strong>gaben (z.B. für Paßwörter).<br />

Generieren e<strong>in</strong>es Action-Event erfolgt beim Drücken der „Enter-„Taste <strong>in</strong>nerhalb des<br />

Textfelds. Die Methode getActionCommand des Action-Events liefert den Inhalt<br />

des Textfelds.<br />

Generieren e<strong>in</strong>es Text-Ereignisses bei jeder Änderung im Textfeld. E<strong>in</strong> Empfänger<br />

207


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

kann mit der Methode addTextListener vom Textfeld registriert werden. Als<br />

Argument wird e<strong>in</strong> Objekt erwartet, das das Interface TextListener implementiert.<br />

Beim Auftreten e<strong>in</strong>es Text-Ereignisses wird vom TextListener die Methode<br />

textValueChanged mit e<strong>in</strong>em „TextEvent“ als Parameter aufgerufen.<br />

„TextEvent“ ist aus „AWTEvent“ abgeleitet und erbt die Methoden getID,<br />

getSource. Typischerweise wird <strong>in</strong>nerhalb von textValueChanged mit<br />

getSource das zugehörige Textfeld beschafft und mit getText auf se<strong>in</strong>en Inhalt<br />

zugegriffen.<br />

Bsp.: import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14170 extends Frame<br />

{<br />

Button<br />

b1 = new Button(„Hole Text“),<br />

b2 = new Button(„Setze Text“);<br />

TextField<br />

t1 = new TextField(30),<br />

t2 = new TextField(30),<br />

t3 = new TextField(30);<br />

Str<strong>in</strong>g s = new Str<strong>in</strong>g();<br />

public PR14170()<br />

{<br />

setLayout(new FlowLayout());<br />

b1.addActionListener(new B1A());<br />

b2.addActionListener(new B2A());<br />

t1.addTextListener(new T1());<br />

t1.addActionListener(new T1A());<br />

add(b1);<br />

add(b2);<br />

add(t1);<br />

add(t2);<br />

add(t3);<br />

}<br />

class T1 implements TextListener<br />

{<br />

public void textValueChanged(TextEvent e)<br />

{<br />

t2.setText(t1.getText());<br />

}<br />

}<br />

class T1A implements ActionListener<br />

{<br />

private <strong>in</strong>t zaehler = 0;<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

t3.setText(„t1 ActionEvent „ + zaehler++);<br />

}<br />

}<br />

class B1A implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

s = t1.getSelectedText();<br />

if (s.length() == 0) s = t1.getText();<br />

t1.setEditable(true);<br />

}<br />

}<br />

class B2A implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

208


TextArea<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

t1.setText(„E<strong>in</strong>gefuegt durch Button 2: „ + s);<br />

t1.setEditable(false);<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR14170 f = new PR14170();<br />

f.addW<strong>in</strong>dowListener(<br />

new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(300,200);<br />

f.setBackground(Color.lightGray);<br />

f.setVisible(true);<br />

}<br />

}<br />

Mit dieser Klasse können mehrzeilige Textfelder erzeugt werden. Zusätzlich kann der<br />

Text <strong>in</strong> allen Richtungen „scrollen“, so daß auch größere Texte bequem bearbeitet<br />

werden können.<br />

Konstruktoren.<br />

public TextArea()<br />

erzeugt e<strong>in</strong> leeres TextArea-Objekt <strong>in</strong> e<strong>in</strong>er vom System vorgegebenen Größe.<br />

public TextArea(<strong>in</strong>t zeilen, <strong>in</strong>t spalten)<br />

erzeugt e<strong>in</strong>e leeres TextArea-Objekt mit e<strong>in</strong>er bestimmten Anzahl von sichtbaren Zeilen und Spalten.<br />

public TextArea(Str<strong>in</strong>g text, <strong>in</strong>t zeilen, <strong>in</strong>t spalten)<br />

erzeugt e<strong>in</strong> TextArea-Objekt mit Text.<br />

public TextArea(Str<strong>in</strong>g text, <strong>in</strong>t zeilen, <strong>in</strong>t spalten, <strong>in</strong>t scroll)<br />

erzeugt e<strong>in</strong> TextArea-Objekt, <strong>in</strong> dem über scroll die Ausstattung der TextArea mit<br />

Schieberegistern festgelegt werden kann. Dazu stellt TextArea die Konstanten SCROLLBARS_BOTH,<br />

SROLLBARS_NONE, SCROLLBARS_VERTICAL_ONLY, SCROLLBARS_HORIZONTAL_ONLY zur<br />

Verfügung, die als Argumente übergeben werden können.<br />

Zusätzliche <strong>in</strong> der Klasse bereitgestellte Methoden zum Verändern von Teilen des<br />

Texts. Neben den bereits <strong>in</strong> der Klasse TextField angegebenen Methoden stehen<br />

zur Verfügung:<br />

public void <strong>in</strong>sert(Str<strong>in</strong>g str, <strong>in</strong>t pos)<br />

verändert die Zeichenkette str ab Position pos. Der dah<strong>in</strong>ter stehende Text wird entsprechend nach<br />

h<strong>in</strong>ten verschoben.<br />

public void append(Str<strong>in</strong>g str)<br />

hängt den über str übergebenen Text h<strong>in</strong>ten an.<br />

public void replaceRange(Str<strong>in</strong>g text, <strong>in</strong>t start, <strong>in</strong>t ende)<br />

ersetzt den Text zwischen start und end durch den Str<strong>in</strong>g text.<br />

Senden von Text-Events. E<strong>in</strong> Objekt der Klasse TextArea sendet Text-Events,<br />

so wie es bei TextField beschrieben wurde.<br />

209


5.2.7 Schieber und Bildlaufleisten<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Listen und Textbereiche besitzen standardmäßig die Eigenschaft bei Bedarf nicht <strong>in</strong><br />

den Anzeigebereich passenden Inhalt über Bildlaufleisten und Schieber zu scrollen.<br />

Bildlaufleisten können auch <strong>in</strong>dividuell erstellt werden und dienen zur (quasi-)<br />

analogen Anzeige bzw. E<strong>in</strong>gabe e<strong>in</strong>es Werts aus e<strong>in</strong>em vorgebenen Wertebereich.<br />

Der Schieberegler kann horizotal und vertikal angeordnet werden und besitzt e<strong>in</strong>en<br />

Schieber, dessen Größe veränderlich ist. Der <strong>in</strong>terne Wert e<strong>in</strong>es Schiebereglers und<br />

die Anzeigeposition se<strong>in</strong>es Schiebers s<strong>in</strong>d untrennbar mite<strong>in</strong>ander verbunden.<br />

Ändert der Anwender die Position des Schiebers, ändert sich automatisch auch se<strong>in</strong><br />

<strong>in</strong>terner Wert. Wird vom Programm der Wert verändert, führt das automatisch zu<br />

e<strong>in</strong>er Positionierung des Schiebers. Zur Änderung des aktuellen Werts e<strong>in</strong>er<br />

Bildlaufleiste können drei verschieden Teile der Bildlaufleiste verwendet werden:<br />

- Pfeile an beiden Enden zum Erhöhen / Erniedrigen des Werts um e<strong>in</strong>e E<strong>in</strong>heit (standardmäßig 1)<br />

- E<strong>in</strong> Bereich <strong>in</strong> der Mitte zum Erhöhen / Erniedrigen e<strong>in</strong>es Werts um je e<strong>in</strong>e größere E<strong>in</strong>heit<br />

(standardmäßig 10)<br />

- E<strong>in</strong> Bildlauffeld (Schieber) <strong>in</strong> der Mitte, der den momentan gewählten Wert anzeigt. Durch<br />

Verschieben des Bildlauffelds mit dem Mauszeiger kann <strong>in</strong>nerhalb der Bildlaufleiste e<strong>in</strong> anderer Wert<br />

gewählt werden.<br />

Nötig ist nur die Festlegung e<strong>in</strong>es Höchst- und M<strong>in</strong>destwerts für die Bildlaufleiste.<br />

Der Rest wird von <strong>Java</strong> erledigt.<br />

Konstruktoren.<br />

public Scrollbar()<br />

erzeugt e<strong>in</strong>en vertikalen Schieberegler mit 0,0 als anfänglichen Höchst-, M<strong>in</strong>destwert.<br />

Public Scrollbar(<strong>in</strong>t orientierung)<br />

„orientierung“ bezeichnet die Ausrichtung und kann über Scrollbar.HORIZONTAL bzw.<br />

Scrollbar.VERTICAL festgelegt werden.<br />

public Scollbar(<strong>in</strong>t orientierung, <strong>in</strong>t wert, <strong>in</strong>t bh, <strong>in</strong>t m<strong>in</strong>imum,<br />

<strong>in</strong>t maximum)<br />

orientierung...bestimmt die Ausrichtung des Schiebereglers<br />

wert...Anfangswert des Schiebereglers (Wert zwischen dem Höchst- und M<strong>in</strong>destwert<br />

bh...Breite bzw. Höhe der dem Schieberegler zugeteilten Box (Seite)<br />

m<strong>in</strong>imum, maximum...bezeichnet den M<strong>in</strong>dest-, Höchstwert des Schiebereglers<br />

Methoden der Scrollbar-Klasse versorgen die Handhabung der Werte des<br />

Schiebereglers:<br />

Methode Bedeutung<br />

public <strong>in</strong>t getValue() Zugriff auf den aktuellen Wert des Schiebereglers<br />

public void setValue(<strong>in</strong>t wert) Setzt den aktuellen Wert des Schiebereglers<br />

public <strong>in</strong>t getOrientation() Bestimmt die Ausrichtung des Schiebereglers<br />

public <strong>in</strong>t getM<strong>in</strong>imum() Zugriff auf den M<strong>in</strong>destwert<br />

public <strong>in</strong>t getMaximum() Zugriff auf den Höchstwert<br />

public <strong>in</strong>t getUnitIncrement() Zugriff der Parameter, die die Stärke der Veränderung des<br />

Werts beim Klicken auf die Buttons bzw. die Schaltfläche<br />

zwischen Schieber und Button bestimmen.<br />

public void setUnitIncrement(<strong>in</strong>t l) Veränderung der Parameter, die die Stärke der Veränderung<br />

des Werts beim Klicken auf die Buttons zwischen Schieber<br />

und Button bestimmen<br />

public <strong>in</strong>t getBlockIncrement() Zugriff der Parameter, die die Stärke der Veränderung des<br />

Werts beim Klicken auf die Buttons bzw. die Schaltfläche<br />

zwischen Schieber und Button bestimmen<br />

public void setBlockIncrement(<strong>in</strong>t l) Veränderung der Parameter, die die Stärke der Veränderung<br />

des Werts beim Klicken auf die Schaltfläche zwischen<br />

Schieber und Button bestimmen<br />

210


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Ereignisse. E<strong>in</strong> Scrollbar sendet Adjustment-Ereignisse an se<strong>in</strong>e<br />

Ereignisempfänger. Diese müssen das Interface AdjustmentListener<br />

implementieren und sich durch Aufruf von public void<br />

addAdjustmentListener(AdjustmentListener l) registrieren. Das<br />

Adjustment-Ereignis führt im Ereignisempfänger zum Aufruf der Methode:<br />

public abstract void adjustmentValueChanged(AdjustmentEvent e),<br />

die e<strong>in</strong> AdjustmentEvent übergeben bekommt. Dieses besitzt die Metode<br />

getAdjustable(), mit der der auslösende Scrollbar bestimmt werden kann.<br />

Zusätzlich gibt es die Methode „getAdjustmentType“, die Auskunft darüber gibt,<br />

welche Benutzeraktion zur Auslösung des Ereignisses führte.<br />

Konstanten, die von getAdjustmentType Bedeutung<br />

zurückgegeben werden<br />

AdjustmentEvent.UNIT_INCREMENT Der Wert durch Klicken e<strong>in</strong>es „Button“ um e<strong>in</strong>e<br />

E<strong>in</strong>heit erhöht.<br />

AdjustmentEvent.UNIT_DECREMENT Der Wert durch Klicken e<strong>in</strong>es „Button“ um e<strong>in</strong>e<br />

E<strong>in</strong>heit erniedrigt.<br />

AdjustmentEvent.BLOCK_INCREMENT Der Wert wurde durch Klicken der Schaltfläche<br />

zwischen Button und Schieber um e<strong>in</strong>e Seite erhöht<br />

AdjustmentEvent.BLOCK_DECREMENT Der Wert wurde durch Klicken der Schaltfläche<br />

zwischen Button und Schieber um e<strong>in</strong>e Seite<br />

verm<strong>in</strong>dert<br />

AdjustmentEvent.TRACK Der Wert wurde durch Ziehen des Schiebers<br />

verändert<br />

Bsp.: import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR14175 extends Frame<br />

{<br />

public PR14175()<br />

{<br />

Panel p = new Panel();<br />

p.setLayout(new BorderLayout());<br />

Scrollbar hsb = new Scrollbar(Scrollbar.HORIZONTAL,1,10,1,100);<br />

hsb.addAdjustmentListener(new HsbAL());<br />

p.add(„South“,hsb);<br />

Scrollbar vsb = new Scrollbar(Scrollbar.VERTICAL,1,10,1,100);<br />

vsb.addAdjustmentListener(new VsbAL());<br />

p.add(„East“,vsb);<br />

add(p);<br />

pack();<br />

}<br />

public class HsbAL implements AdjustmentListener<br />

{<br />

public void adjustmentValueChanged(AdjustmentEvent e)<br />

{<br />

switch(e.getAdjustmentType())<br />

{<br />

case AdjustmentEvent.UNIT_INCREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.UNIT_INCREMENT“);<br />

break;<br />

case AdjustmentEvent.UNIT_DECREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.UNIT_DECREMENT“);<br />

break;<br />

case AdjustmentEvent.BLOCK_INCREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.BLOCK_INCREMENT“);<br />

break;<br />

case AdjustmentEvent.BLOCK_DECREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.BLOCK_DECREMENT“);<br />

break;<br />

211


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

case AdjustmentEvent.TRACK:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.TRACK“);<br />

break;<br />

}<br />

System.out.pr<strong>in</strong>tln(„Wert: „ + e.getValue());<br />

}<br />

}<br />

public class VsbAL implements AdjustmentListener<br />

{<br />

public void adjustmentValueChanged(AdjustmentEvent e)<br />

{<br />

switch(e.getAdjustmentType())<br />

{<br />

case AdjustmentEvent.UNIT_INCREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.UNIT_INCREMENT“);<br />

break;<br />

case AdjustmentEvent.UNIT_DECREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.UNIT_DECREMENT“);<br />

break;<br />

case AdjustmentEvent.BLOCK_INCREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.BLOCK_INCREMENT“);<br />

break;<br />

case AdjustmentEvent.BLOCK_DECREMENT:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.BLOCK_DECREMENT“);<br />

break;<br />

case AdjustmentEvent.TRACK:<br />

System.out.pr<strong>in</strong>tln(„Adjustment.TRACK“);<br />

break;<br />

}<br />

System.out.pr<strong>in</strong>tln(„Wert: „ + e.getValue());<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR14175 f = new PR14175();<br />

f.addW<strong>in</strong>dowListener(<br />

new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setBackground(Color.lightGray);<br />

f.setVisible(true);<br />

}<br />

}<br />

5.2.8 ScrollPane<br />

E<strong>in</strong> ScrollPane ist e<strong>in</strong> Conta<strong>in</strong>er für automatisches horizontales und vertikales<br />

Scroll<strong>in</strong>g. ScrollPane unterscheidet sich durch zwei Eigenschaften von e<strong>in</strong>em<br />

gewöhnlichen Panel:<br />

- Es kann genau e<strong>in</strong> Dialogelement aufnehmen und benötigt ke<strong>in</strong>en eigenen Layoutmanager<br />

- Es ist <strong>in</strong> der lage, e<strong>in</strong>e virtuelle Ausgabefläche zu verwalten, die größer ist als die auf dem Bildschirm<br />

zur Verfügung stehende Ausgabefläche.<br />

Die von e<strong>in</strong>em ScrollPane angezeigte Komponente arbeitet mit e<strong>in</strong>er virtuellen<br />

Ausgabefläche ( und merkt nichts von evtl. Größenbeschränkungen auf dem<br />

Bildschirm). Falls die benötigte Ausgabefläche größer ist als die anzeigbare, blendet<br />

212


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

e<strong>in</strong> ScrollPane automatisch die erforderlichen Schieberegister e<strong>in</strong>, um<br />

Dialogelemente horizontal und vertikal verschieben zu können.<br />

Konstruktoren.<br />

public ScrollPane()<br />

public ScrollPane(<strong>in</strong>t scrollbarDisplayPolicy)<br />

“srollbarDisplayPolicy“ def<strong>in</strong>iert die Strategie zur Anzeige der Schieberegler entsprechend den<br />

<strong>in</strong> der folgende Liste aufgelisteten Konstanten:<br />

ScrollPane.SCROLLBARS_AS_NEEDED Die Schieberegler werden genau dann angezeigt,<br />

wenn es erforderlich ist, d.h.: Es wird mehr Platz<br />

benötigt, als für sie zur Anzeige zur Verfügung steht.<br />

ScrollPane.SCROLLBARS_ALWAYS Die Schieberegler werden immer angezeigt<br />

ScrollPane.SCROLLBARS_NEVER Die Schieberegler werden nie angezeigt, der<br />

Bildschirm kann nur vom Programm aus verschoben<br />

werden<br />

5.2.9 Zeichenbereiche<br />

E<strong>in</strong> Canvas ist e<strong>in</strong> frei def<strong>in</strong>iertes Dialogelement, das <strong>in</strong> der Grundversion praktisch<br />

ke<strong>in</strong>e Funktionalität zur Verfügung stellt. Damit e<strong>in</strong> Canvas etwas S<strong>in</strong>nvolles tun<br />

kann, muß daraus e<strong>in</strong>e eigene Klasse abgeleitet werden.<br />

Konstruktor: public Canvas()<br />

Die Methode pa<strong>in</strong>t(Graphics g). Durch Überlagerung von public void<br />

pa<strong>in</strong>t(Graphics g) sorgt e<strong>in</strong>e Canvas-Komponente für die Darstellung auf dem<br />

Bildschirm. Die vom System bereitgestellte Version zeichnet nur die Ausgabefläche<br />

<strong>in</strong> der aktuellen H<strong>in</strong>tergrundfarbe. E<strong>in</strong>e überlagerte Version kann hier natürlich e<strong>in</strong><br />

beliebig komplexes Darstellungsverhalten erzielen. Der Punkt (0,0) des übergebenen<br />

Graphics-Objekts entspricht dabei der l<strong>in</strong>ken oberen Ecke des Ausgabebereichs.<br />

Ereignisse. Da die Klasse Canvas aus Component abgeleitet ist, bekommt e<strong>in</strong><br />

Canvas-Objekt alle Ereignisse zugestellt, die auch an e<strong>in</strong>e Komponente gehen.<br />

Hierzu zählen Tastatur-, Maus-, Mausbewegungs-, Fokus- und<br />

Komponentenereignisse.<br />

Bsp.: Die von Canvas abgeleitete Klasse ZeichneCanvas<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class ZeichneCanvas extends Canvas<br />

{<br />

// Instanzvariable<br />

public boolean zeichneObjekte;<br />

private Font font;<br />

// Konstruktoren<br />

public ZeichneCanvas()<br />

{<br />

this(400,400);<br />

}<br />

public ZeichneCanvas(<strong>in</strong>t breite,<strong>in</strong>t hoehe)<br />

{<br />

super();<br />

setSize(breite,hoehe);<br />

setBackground(Color.white);<br />

bere<strong>in</strong>igen();<br />

font = new Font(„Helvetica“,Font.BOLD,24);<br />

}<br />

// Instanzmethoden<br />

public void bere<strong>in</strong>igen()<br />

213


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

{<br />

zeichneObjekte = false;<br />

repa<strong>in</strong>t();<br />

}<br />

public void zeichnen()<br />

{<br />

zeichneObjekte = true;<br />

repa<strong>in</strong>t();<br />

}<br />

public void pa<strong>in</strong>t(Graphics g)<br />

{<br />

System.out.pr<strong>in</strong>tln(<br />

„Methode pa<strong>in</strong>t wurde aufgerufen, zeichneObjekte = „<br />

+ zeichneObjekte);<br />

if (zeichneObjekte)<br />

{<br />

// Individuelle Auspraegung der Zeichnung<br />

<strong>in</strong>t r = 8;<br />

<strong>in</strong>t i, j;<br />

<strong>in</strong>t x, y;<br />

g.setColor(Color.red);<br />

for (i=1; i


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

});<br />

setLayout(new BorderLayout());<br />

Panel panelN = new Panel();<br />

panelN.add(new Label(„x: „));<br />

xFeld = new TextField(5);<br />

xFeld.setEditable(false);<br />

panelN.add(xFeld);<br />

panelN.add(new Label(„y: „));<br />

yFeld = new TextField(5);<br />

yFeld.setEditable(false);<br />

panelN.add(yFeld);<br />

add(„North“,panelN);<br />

zeichenflaeche = new ZeichneCanvas(breite,hoehe);<br />

zeichenflaeche.addMouseMotionListener(this);<br />

add(„Center“,zeichenflaeche);<br />

Panel panelS = new Panel();<br />

zeichne = new Button(„Zeichne“);<br />

zeichne.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

zeichenflaeche.zeichnen();<br />

}<br />

});<br />

panelS.add(zeichne);<br />

bere<strong>in</strong>ige = new Button(„Bere<strong>in</strong>ige“);<br />

bere<strong>in</strong>ige.addActionListener(new ActionListener()<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

zeichenflaeche.bere<strong>in</strong>igen();<br />

}<br />

});<br />

panelS.add(bere<strong>in</strong>ige);<br />

add(„South“,panelS);<br />

pack();<br />

setVisible(true);<br />

}<br />

// Implementierung des MouseMotionListener-Interface<br />

public void mouseMoved(MouseEvent e)<br />

{<br />

xFeld.setText(„ „ + e.getX());<br />

yFeld.setText(„ „ + e.getY());<br />

}<br />

public void mouseDragged(MouseEvent e)<br />

{<br />

xFeld.setText(„ „ + e.getX());<br />

yFeld.setText(„ „ + e.getY());<br />

}<br />

// Start der GUI<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

ZeichneGUI gui = new ZeichneGUI();<br />

}<br />

}<br />

215


5.3 Conta<strong>in</strong>er<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Conta<strong>in</strong>er s<strong>in</strong>d allgeme<strong>in</strong>e Komponenten, die andere Komponenten oder auch<br />

andere Conta<strong>in</strong>er enthalten.<br />

5.3.1 Panels<br />

E<strong>in</strong>e sehr häufig vorkommende Conta<strong>in</strong>er-Form ist das sog. Panel, das e<strong>in</strong>en<br />

Conta<strong>in</strong>er darstellt, der am Bildschirm dargestellt werden kann. E<strong>in</strong> Panel ist e<strong>in</strong><br />

„re<strong>in</strong>er“ Conta<strong>in</strong>er, ke<strong>in</strong> eigenes Fenster. Se<strong>in</strong> e<strong>in</strong>ziger Zweck ist es, Komponenten <strong>in</strong><br />

e<strong>in</strong>em Fenster anzuordnen.<br />

Erzeugen e<strong>in</strong>es Panels. Das Erzeugen erfolgt mit Hilfe des Konstruktors „Panel()“,<br />

z.B.: Panel me<strong>in</strong>Panel = new Panel();<br />

H<strong>in</strong>zufügen von e<strong>in</strong>em Panel <strong>in</strong> e<strong>in</strong>en anderen Conta<strong>in</strong>er. E<strong>in</strong> Panel kann bspw. mit<br />

„add(me<strong>in</strong>Panel) <strong>in</strong> e<strong>in</strong> Applet e<strong>in</strong>gebaut werden.<br />

Verschachteln von Panels. Panels lassen sich <strong>in</strong> beliebig vielen Ebenen<br />

verschachteln. S<strong>in</strong>n machen solche verschachtelten Panels vor allem <strong>in</strong> Verb<strong>in</strong>dung<br />

mit den verschiedenen Layouts.<br />

5.3.2 Frames<br />

E<strong>in</strong> Frame ist e<strong>in</strong> voll funktionsfähiges Fenster mit eigenem Titel und Icon. Frames<br />

können Pulldown-Menüs haben und verschieden gestaltete Mauszeiger verwenden.<br />

Erzeugen von Frames. Mit der Frame-Klasse kann e<strong>in</strong> funktionsfähiges Fenster mit<br />

Menüleiste erstellt werden. Zum Erzeugen von Frames stehen verschiedene<br />

Konstruktoren zur Verfügung:<br />

public Frame()<br />

Damit kann e<strong>in</strong> Frame erzeugt werden, der zu Beg<strong>in</strong>n nicht sichtbar ist und ke<strong>in</strong>en Titel hat.<br />

Public Frame(Str<strong>in</strong>g titel)<br />

Diese Version vergibt e<strong>in</strong>en Titel bei der Erzeugung, das Frame ist zu Beg<strong>in</strong>n nicht sichtbar.<br />

Verändern der Titelzeile. Sie läßt sich <strong>in</strong> den Klassen Frame und Dialog mit den<br />

Methoden<br />

public void setTitle(Str<strong>in</strong>g titel)<br />

// ändert die Beschriftung der Titelleiste <strong>in</strong> titel<br />

public Str<strong>in</strong>g getTitle()<br />

// Abfrage der Titelleiste<br />

bee<strong>in</strong>flussen.<br />

E<strong>in</strong>stellen des Standard-Font. E<strong>in</strong> Fenster hat e<strong>in</strong>en Standard-Font, der zur Ausgabe<br />

der Schrift verwendet wird, (wenn nicht im Grafik-Kontext e<strong>in</strong> anderer Font<br />

ausgewählt wird). Der Standard-Font e<strong>in</strong>es Fensters wird mit „public void<br />

setFont (Font f)“ der Klasse Component e<strong>in</strong>gestellt.<br />

E<strong>in</strong>stellen von Vorder- Und H<strong>in</strong>tergrundfarbe. Die Vordergrundfarbe dient zur<br />

Ausgabe von Grafik- und Textobjekten, wenn im Grafik-Kontext ke<strong>in</strong>e andere Farbe<br />

216


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

gesetzt wird. Wird die E<strong>in</strong>stellung nicht geändert, werden für Vordergrund- und<br />

H<strong>in</strong>tergrundfarbe die unter W<strong>in</strong>dows e<strong>in</strong>gestellten Standardfarben verwendet. Mit<br />

public void setBackground(Color farbe)<br />

public void setForeground(Color farbe)<br />

können Vordergrund- und H<strong>in</strong>tergrundfarbe des Fensters geändert werden.<br />

Größe und Position e<strong>in</strong>es Fensters können bestimmt werden über<br />

public void setSize(<strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />

// verändert die Größe des Fensters auf den Wert (breite, hoehe)<br />

public void setSize(Dimension d)<br />

public void setBounds(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />

// positioniert e<strong>in</strong> Fenster der Größe (breite,hoehe) an die Position (x,y)<br />

public void setBounds(Rectangle r)<br />

public void setLocation(<strong>in</strong>t x, <strong>in</strong>t y)<br />

// bewegt die l<strong>in</strong>ke obere Ecke an die Bildschirmposition (x,y)<br />

public void setLocation(Po<strong>in</strong>t p);<br />

Anzeigen, Wegblenden und Löschen von Frames. Die Konstruktoren haben das<br />

Frame unsichtbar gelassen. Frames müssen vor Gebrauch sichtbar gemacht<br />

werden. Der 1. Schritt besteht dar<strong>in</strong>, e<strong>in</strong>en Frame e<strong>in</strong>e Größe mit der Methode<br />

public void resize(<strong>in</strong>t breite /* Breite vom Frame <strong>in</strong> Pixel */,<br />

<strong>in</strong>t hoehe / Hoehe <strong>in</strong> Pixel */) zu geben. Sichtbar wird der Frame über die<br />

show()-Methode172 . Mit public void hide() 173 kann der Frame wieder<br />

unsichtbar gemacht werden. Über public void dispose() wird der Frame<br />

beendet. Mit public boolean isShow<strong>in</strong>g() kann geprüft werden, ob das<br />

Fenster bereits angezeigt ist.<br />

Standardlayout für Fenster: Border-Layout.<br />

H<strong>in</strong>zufügen von Komponenten: Rahmen s<strong>in</strong>d Conta<strong>in</strong>er wie Panels, andere<br />

Komponenten können mit der add()-Methode h<strong>in</strong>zugefügt werden.<br />

5.3.3 Menüs<br />

Jedes Fenster / Frame kann e<strong>in</strong>e eigene Menüleiste besitzen. Jede Menüleiste kann<br />

mehrere Menüs enthalten und jedes Menü beliebige E<strong>in</strong>träge. <strong>Java</strong> unterstützt die<br />

Konstruktion von Menüs durch e<strong>in</strong>e Reihe speziell dafür vorgesehenen Klassen:<br />

Klasse Bedeutung<br />

MenuBar Beschreibt die Menüzeile (-leiste)e<strong>in</strong>es Fensters<br />

Menu Beschreibet e<strong>in</strong> e<strong>in</strong>zelnes, der <strong>in</strong> der Menüzeile enthaltenen Menüs<br />

MenuItem Bildet die vom Anwender auswählbaren E<strong>in</strong>träge <strong>in</strong>nerhalb der Menüs<br />

CheckboxmenuItem<br />

Die Menüleiste<br />

Sie beschreibt das Hauptmenü e<strong>in</strong>es Fensters. Sie bef<strong>in</strong>det sich unterhalb der<br />

Titelleiste am oberen Rand des Fensters und zeigt die Namen der dar<strong>in</strong> enthaltenen<br />

Menüs an. E<strong>in</strong>e Menüleiste wird durch Instanzen der Klasse MenuBar erzeugt:<br />

172 Für show() aus dem Paket java.awt.Component gibt es als neue Variante die Methode<br />

setVisible(boolean)<br />

173 hide() ist <strong>in</strong> java.awt.Frame als „deprecated“ deklariert. Statt dessen steht setVisible(boolean) zur<br />

Verfügung<br />

217


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Konstruktor. Public MenuBar()<br />

E<strong>in</strong>fügen von Menüs. Public void add(Menu m).<br />

Entfernen von bestehenden Menüs. Public void remove(<strong>in</strong>t <strong>in</strong>dex)<br />

public void remove(MenuComponent m)<br />

Zugrff auf e<strong>in</strong> beliebiges Menü. Public Menu getMenu(<strong>in</strong>t <strong>in</strong>dex).<br />

getMenu liefert das Menüobjekt, das sich an der Position mit dem angegebenen<br />

Index bef<strong>in</strong>det. Zum B<strong>in</strong>den e<strong>in</strong>er Menüleiste an e<strong>in</strong> Fenster mit dem angegebenen<br />

Index (<strong>in</strong>dex) bef<strong>in</strong>det.<br />

B<strong>in</strong>den e<strong>in</strong>er Menüleiste an e<strong>in</strong>en Frame. Public void setMenubar(Menubar<br />

mb) .Durch Aufruf dieser Methode wird die angegebene Menüleiste im Fenster<br />

angezeigt und beim Auswählen des Menüpunkts werden Nachrichen ausgelöst und<br />

an das Fenster gesendet. Die Fensterklasse kann diese Nachrichen durch das<br />

Registrieren e<strong>in</strong>es Objekts vom Typ ActionListener bearbeiten.<br />

Menüs.<br />

Sie bilden die Bestandteile e<strong>in</strong>er Menüleiste und werden durch Instanzen der Klasse<br />

Menu repräsentiert.<br />

Konstruktor. public Menu(Str<strong>in</strong>g label)<br />

// label gibt den Namen des Menüs an<br />

Standardhilfe-Menü: public void setHelpMenu(Menu m) erzeugt e<strong>in</strong><br />

spezielles Standardhilfemenü.<br />

Menüe<strong>in</strong>träge<br />

E<strong>in</strong>fache Menüe<strong>in</strong>träge s<strong>in</strong>d die elementaren Bestandteile e<strong>in</strong>es Menüs. Sie besitzen<br />

e<strong>in</strong>en Text, mit dem sie dem Anwender die dah<strong>in</strong>terstehende Funktion anzeigen.<br />

Wenn der zugehörige Menüpunkt aufgerufen wird, sendet das Programm e<strong>in</strong>e<br />

Nachricht an das zugehörige Fenster, die dann zum Aufruf der entsprechenden<br />

Methode führt.<br />

Erzeugen von Menüe<strong>in</strong>trägen: public MenuItem(Str<strong>in</strong>g label). „label“ ist<br />

der Name des Menüe<strong>in</strong>trags.<br />

Zugriff auf den Namen bzw. Setzen des Namens e<strong>in</strong>es Menüe<strong>in</strong>trags:<br />

public Str<strong>in</strong>g getLabel()<br />

public void setLabel(Str<strong>in</strong>g label)<br />

Neben dem Namen besitzt e<strong>in</strong> Menüe<strong>in</strong>trag e<strong>in</strong>e <strong>in</strong>terne Zustandsvariable. Sie zeigt<br />

an, ob der Menüe<strong>in</strong>trag aktiv ist oder nicht. Nur e<strong>in</strong> aktiver E<strong>in</strong>trag kann vom<br />

Anwender ausgewählt werden und so e<strong>in</strong>e Nachricht auslösen. Nach dem Aufruf des<br />

Konstruktors ist e<strong>in</strong> Menüe<strong>in</strong>trag zunächst aktiviert. Er kann durch public void<br />

setEnabled(boolean b) mit Parameterwert „false“ deaktiviert und mit<br />

Parameterwert true aktiviert werden. Über public boolean isEnabled() kann<br />

der aktuelle Zustand abgefragt werden.<br />

Methoden für die Bearbeitung von Menüe<strong>in</strong>trägen.<br />

public void add(MenuItem m)<br />

public void add(str<strong>in</strong>g label)<br />

public void remove(<strong>in</strong>t <strong>in</strong>dex)<br />

public void remove(MenuComponent Item)<br />

Seperatoren für Menüe<strong>in</strong>träge. E<strong>in</strong> Seperator wird als waagrechter Strich zur<br />

Trennung der Menüe<strong>in</strong>träge angezeigt:<br />

public void addSeperator()<br />

// fügt den Seperator h<strong>in</strong>ter dem zuletzt e<strong>in</strong>gefügten Menüe<strong>in</strong>trag e<strong>in</strong><br />

public void <strong>in</strong>sertSeperator(<strong>in</strong>t <strong>in</strong>dex)<br />

218


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

// E<strong>in</strong>fügepostion kann frei angegeben werden.<br />

Zugriff auf Menüe<strong>in</strong>trag. Public MenuItem getItem(<strong>in</strong>t <strong>in</strong>dex)<br />

Anzahl der E<strong>in</strong>träge. Public <strong>in</strong>t getItemCount()<br />

Die Klasse CheckboxMenuItem. Sie ist aus MenuItem abgeleitet und besitzt<br />

zusätzlich e<strong>in</strong>e <strong>in</strong>terne Zustandsvariable, die zwischen true und false umgeschaltet<br />

werden kann. Die visuelle Darstellung der Zustandsvariablen erfolgt durch Anfügen<br />

oder Entfernen e<strong>in</strong>es „Häkchens“ neben dem Menüe<strong>in</strong>trag.<br />

Die Instanzierung e<strong>in</strong>es CkeckboxMenuItem erfogt wie bei e<strong>in</strong>em MenuItem.<br />

Zusätzlich stehen die beiden Methoden setState und getState zum Setzen und<br />

Abfragen des Zustands zur Verfügung:<br />

public void setState(boolean status)<br />

public boolean getState()<br />

Menüaktionen: E<strong>in</strong> Menü macht nur S<strong>in</strong>n, wenn damit e<strong>in</strong>e Aktion ausgelöst werden<br />

kann. Diese Aktion kann wie jede andere Aktion mit der Methode actionPerformed<br />

behandelt werden.<br />

Bsp.: Zusammenstellung der wesentlichen Elemente zur Gestaltung von Menüs<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

public class PR53331 extends Frame<br />

{<br />

// TextField t = new TextField(„Ke<strong>in</strong>e Anzeige“,30);<br />

public PR53331()<br />

{<br />

// Menueleiste erzeugen<br />

MenuBar mb = new MenuBar();<br />

// Menueleiste an Rahmen verankern<br />

setMenuBar(mb);<br />

// Menuepunkt erzeugen<br />

Menu m1 = new Menu(„Farben“); // Menuepunkt 1<br />

// E<strong>in</strong> Untermenue erzeugen<br />

// Menuee<strong>in</strong>traege <strong>in</strong> der Menuezeile plazieren<br />

mb.add(m1);<br />

// E<strong>in</strong>traege <strong>in</strong> Menuepunkt 1<br />

MenuItem rot = new MenuItem(„Rot“);<br />

m1.add(rot);<br />

rot.addActionListener(new RotL());<br />

MenuItem blau = new MenuItem(„Blau“);<br />

m1.add(blau);<br />

blau.addActionListener(new BlauL());<br />

MenuItem gruen = new MenuItem(„Gruen“);<br />

m1.add(gruen);<br />

gruen.addActionListener(new GruenL());<br />

MenuItem gelb = new MenuItem(„Gelb“);<br />

m1.add(gelb);<br />

gelb.addActionListener(new GelbL());<br />

// Untermenue erzeugen<br />

Menu unterMenue = new Menu(„Farbanpassung“);<br />

// Trennl<strong>in</strong>ie<br />

MenuItem trennL<strong>in</strong>ie = new MenuItem(„-„);<br />

m1.add(trennL<strong>in</strong>ie);<br />

// Untermenue h<strong>in</strong>zufuegen<br />

m1.add(unterMenue);<br />

MenuItem farbe = new MenuItem(„Farbe“);<br />

MenuItem mono = new MenuItem(„Mono“);<br />

farbe.addActionListener(new FarbeL());<br />

mono.addActionListener(new MonoL());<br />

unterMenue.add(farbe);<br />

unterMenue.add(mono);<br />

// Menue zur Dateibearbeitung<br />

219


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Menu d = new Menu(„Datei“);<br />

MenuItem[] datei =<br />

{<br />

//<br />

new MenuItem(„Open“),<br />

// menu shortcut<br />

new MenuItem(„Exit“,new MenuShortcut(KeyEvent.VK_E))<br />

};<br />

ML ml = new ML();<br />

datei[0].setActionCommand(„Open“);<br />

datei[0].addActionListener(ml);<br />

datei[1].setActionCommand(„Exit“);<br />

datei[1].addActionListener(ml);<br />

for (<strong>in</strong>t i = 0; i < datei.length; i++)<br />

d.add(datei[i]);<br />

mb.add(d);<br />

// CheckboxMenuItem<br />

Menu s = new Menu(„Sicherheit“);<br />

CheckboxMenuItem[] sicherung =<br />

{<br />

new CheckboxMenuItem(„Wache“),<br />

new CheckboxMenuItem(„Versteck“)<br />

};<br />

CMIL cmil = new CMIL();<br />

sicherung[0].setActionCommand(„Wache“);<br />

sicherung[0].addItemListener(cmil);<br />

sicherung[1].setActionCommand(„Versteck“);<br />

sicherung[1].addItemListener(cmil);<br />

for (<strong>in</strong>t i = 0; i < sicherung.length; i++)<br />

s.add(sicherung[i]);<br />

d.add(s);<br />

// Hilfsmenue<br />

Menu me<strong>in</strong>eHilfe = new Menu(„Hilfe“);<br />

mb.setHelpMenu(me<strong>in</strong>eHilfe);<br />

// E<strong>in</strong>traege im Hilfsmenue<br />

me<strong>in</strong>eHilfe.add(new MenuItem(„Info“));<br />

me<strong>in</strong>eHilfe.add(new MenuItem(„Hilfe“));<br />

// Textfeld <strong>in</strong>itialisieren<br />

// t.setEditable(false);<br />

// add(t,BorderLayout.CENTER);<br />

}<br />

class ML implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

MenuItem ziel = (MenuItem) e.getSource();<br />

Str<strong>in</strong>g aktionsKommando = ziel.getActionCommand();<br />

if (aktionsKommando.equals(„Open“))<br />

{<br />

System.out.pr<strong>in</strong>tln(„Oeffnen“);<br />

}<br />

else if (aktionsKommando.equals(„Exit“))<br />

{<br />

dispatchEvent(new W<strong>in</strong>dowEvent(PR53331.this,<br />

W<strong>in</strong>dowEvent.WINDOW_CLOSING));<br />

}<br />

}<br />

}<br />

class CMIL implements ItemListener<br />

{<br />

public void itemStateChanged(ItemEvent e)<br />

{<br />

CheckboxMenuItem ziel = (CheckboxMenuItem) e.getSource();<br />

Str<strong>in</strong>g aktionsKommando = ziel.getActionCommand();<br />

if (aktionsKommando.equals(„Wache“))<br />

{<br />

System.out.pr<strong>in</strong>tln(„Wache „ + ziel.getState());<br />

220


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

}<br />

else if (aktionsKommando.equals(„Versteck“))<br />

{<br />

System.out.pr<strong>in</strong>tln(„Versteck „ + ziel.getState());<br />

}<br />

}<br />

}<br />

class RotL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.red);<br />

}<br />

}<br />

class BlauL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.blue);<br />

}<br />

}<br />

class GruenL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.green);<br />

}<br />

}<br />

class GelbL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

setBackground(Color.yellow);<br />

}<br />

}<br />

class FarbeL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(„Im Untermenue wurde Farbe ausgewaehlt“);<br />

}<br />

}<br />

class MonoL implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

System.out.pr<strong>in</strong>tln(„Im Untermenue wurde Mono gewaehlt“);<br />

}<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

PR53331 f = new PR53331();<br />

f.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

});<br />

f.setSize(300,200);<br />

f.setVisible(true);<br />

}<br />

}<br />

221


5.3.4 Dialoge<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Unter e<strong>in</strong>em Dialog versteht man e<strong>in</strong> Popup-Fenster. Dialoge werden entweder<br />

„modal“ oder „non-modal“ erzeugt. „modal“ bedeutet: Das Dialogfeld blockiert andere<br />

Fenster, wenn es angezeigt wird.<br />

Erzeugen. E<strong>in</strong> modaler Dialog muß immer von der Klasse Dialog abgeleitet se<strong>in</strong>.<br />

Dialog bietet 4 Konstruktoren an<br />

public Dialog(Frame eltern)<br />

public Dialog(Frane eltern, boolean modal)<br />

public Dialog(Frame eltern,Str<strong>in</strong>g titel)<br />

public Dialog(Frame eltern,Str<strong>in</strong>g titel, boolean modal)<br />

Der Parameter modal entscheidet, ob der Dialog modal wird oder nicht.<br />

Zugriff auf modale bzw. „nicht modale“ Eigenschaft. Dafür gibt es die Methoden<br />

public boolean isModal()<br />

// Rückgabewert ist true, falls der Dialog modal ist. Anderenfalls ist er<br />

// false.<br />

Public void setModal(boolean b)<br />

Unterb<strong>in</strong>den der Veränderbarkeit der Größe e<strong>in</strong>es Fensters. Das kann über<br />

public void setResizable(boolean rezisable)<br />

public boolean isResizable()<br />

geschehen bzw. überprüft werden.<br />

5.4 Die Layout-Manager<br />

Das AWT-System kümmert sich weitgehend selbstständig um Größenanpassung<br />

und Postionierung von Komponenten auf der Oberfläche. Je nach Plattform und<br />

Bed<strong>in</strong>gungen werden Komponenten <strong>in</strong> die Oberfläche optimal angepaßt. Über<br />

Layout-Manager kann das AWT angewiesen werden, wo Komponenten im<br />

Verhältnis zu anderen Komponenten stehen sollen. Der Layout-Manager bestimmt<br />

nach gewissen Regeln, an welche Stelle die Komponenten am besten passen und<br />

ermittelt die optimale Größe der Komponenten.<br />

222


5.4.1 Layout-Regeln<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Drei Aspekte bestimmen das Aussehen e<strong>in</strong>er AWT-Oberfläche:<br />

1. Die Plattform und die Bed<strong>in</strong>gungen, die unter dieser Plattform vorliegen. <strong>Java</strong> ist<br />

plattformunabhängig, daher kann der Programmierer hier ke<strong>in</strong>e Aussagen<br />

machen.<br />

2. Die Reihenfolge, <strong>in</strong> der die AWT-Komponenten <strong>in</strong> e<strong>in</strong>en Conta<strong>in</strong>er e<strong>in</strong>gefügt<br />

werden.<br />

3. Die Art des Layout-Managers. Das AWT umfaßt 5 verschiedene Typen von<br />

Layout-Managern, die die Oberfläche unterschiedlich aufgliedern:<br />

- Flow-Layout<br />

- Grid-Layout<br />

- Border-Layout<br />

- Card-Layout<br />

- GridBag-Layout<br />

Jedes Panel kann e<strong>in</strong>en eigenen Layout-Manager verwenden.<br />

Erstellen e<strong>in</strong>es Layout-Managers. Zum Erstellen e<strong>in</strong>es Layout-Managers für e<strong>in</strong>en<br />

Panel kann ( <strong>in</strong> der <strong>in</strong>it()-Methode) die Methode public void<br />

setLayout(LayoutManager mgr) verwendet werden, z.B.: setLayout(new<br />

FlowLayout());<br />

5.4.2 Die e<strong>in</strong>zelnen Layout-Manager<br />

Die FlowLayout-Klasse<br />

FlowLayout ordnet Komponenten von l<strong>in</strong>ks nach rechts an, bis ke<strong>in</strong>e weiteren<br />

Komponenten mehr <strong>in</strong> die Zeile passen. Dann geht es zur nächsten Zeile und<br />

bewegt sich wieder von l<strong>in</strong>ks nach rechts. Die Standard-.Ausrichtung für e<strong>in</strong><br />

FlowLayout ist zentriert.<br />

Der FlowLayout-Manager ist der Standard-Layout-Manager für alle Applets.<br />

Bsp.: Plazierung von Schaltflächen.<br />

Die Komponenten werden <strong>in</strong> der Reihenfolge, <strong>in</strong> der sie <strong>in</strong> den Conta<strong>in</strong>er e<strong>in</strong>gefügt<br />

werden, spaltenweise von l<strong>in</strong>ks nach rechts e<strong>in</strong>geordnet, bis ke<strong>in</strong>e weiteren<br />

Komponenten mehr <strong>in</strong> e<strong>in</strong>e Zeile passen. So führt der folgende Quellcode<br />

import java.awt.*;<br />

public class FlowLayoutTestApplet extends java.applet.Applet<br />

{<br />

public void <strong>in</strong>it()<br />

{<br />

setBackground(Color.yellow);<br />

setLayout(new FlowLayout());<br />

Button me<strong>in</strong>Knopf1 = new Button(„Rot“);<br />

add(me<strong>in</strong>Knopf1);<br />

Button me<strong>in</strong>Knopf2 = new Button(„Blau“);<br />

add(me<strong>in</strong>Knopf2);<br />

Button me<strong>in</strong>Knopf3 = new Button(„Gruen“);<br />

add(me<strong>in</strong>Knopf3);<br />

Button me<strong>in</strong>Knopf4 = new Button(„P<strong>in</strong>k“);<br />

add(me<strong>in</strong>Knopf4);<br />

Button me<strong>in</strong>Knopf5 = new Button(„Rosa“);<br />

223


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

add(me<strong>in</strong>Knopf5);<br />

Button me<strong>in</strong>Knopf6 = new Button(„Gelb“);<br />

add(me<strong>in</strong>Knopf6);<br />

Button me<strong>in</strong>Knopf7 = new Button(„Cyan“);<br />

add(me<strong>in</strong>Knopf7);<br />

}<br />

}<br />

mit den im Applet-Tag angegebenen Abmessungen<br />

<br />

<br />

FlowLayout-Test<br />

<br />

<br />

<br />

<br />

<br />

<br />

zur folgenden Darstellung<br />

E<strong>in</strong>e Veränderung <strong>in</strong> der Größe des Applet macht den zeilenweisen Aufbau deutlich:<br />

<br />

<br />

FlowLayout-Test<br />

<br />

<br />

<br />

<br />

<br />

<br />

224


Die BorderLayout-Klasse<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die BorderLayout-Klasse unterteilt e<strong>in</strong>en Conta<strong>in</strong>er <strong>in</strong> fünf Bereiche: North, South,<br />

East, West, Center. Falls e<strong>in</strong>em Conta<strong>in</strong>er Komponenten h<strong>in</strong>zugefügt werden,<br />

geschieht das über e<strong>in</strong> spezielles Exemplar der add()-Methode ( mit e<strong>in</strong>em dieser<br />

fünf Bereichsnamen).<br />

Bsp.: BorderLayout-Applet, das e<strong>in</strong>em Applet e<strong>in</strong>ige Schaltfläche h<strong>in</strong>zufügt.<br />

Der Quellcode ist<br />

import java.awt.*;<br />

import java.applet.*;<br />

public class BorderLayoutTestApplet extends Applet<br />

{<br />

public void <strong>in</strong>it()<br />

{<br />

<strong>in</strong>t i = 0;<br />

setBackground(Color.yellow);<br />

setLayout(new BorderLayout());<br />

add(„North“,new Button(„Schaltflaeche „ + i++));<br />

add(„South“,new Button(„Schaltflaeche „ + i++));<br />

add(„East“,new Button(„Schaltflaeche „ + i++));<br />

add(„West“,new Button(„Schaltflaeche „ + i++));<br />

add(„Center“,new Button(„Schaltflaeche „ + i++));<br />

}<br />

}<br />

Für das Applet wurde folgende Größe vere<strong>in</strong>bart:<br />

<br />

<br />

FlowLayout-Test<br />

<br />

<br />

<br />

<br />

<br />

<br />

Das führt zu dem folgenden Layout:<br />

Die GridLayout-Klasse<br />

Diese Klasse teilt den Conta<strong>in</strong>er <strong>in</strong> e<strong>in</strong> Gitter mit gleich großen Zellen e<strong>in</strong>.<br />

H<strong>in</strong>zugefügte Komponenten werden von l<strong>in</strong>ks nach rechts angeordnet, begonnen<br />

wird bei den l<strong>in</strong>ken, oberen Zellen.<br />

Bsp.: Plazieren von Schaltflächen<br />

Der folgende Quellcode<br />

225


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

import java.awt.*;<br />

import java.applet.*;<br />

public class GridLayoutTestAppl extends Applet<br />

{<br />

public void <strong>in</strong>it()<br />

{<br />

setLayout(new GridLayout(7,3));<br />

for (<strong>in</strong>t i = 0; i < 20; i++)<br />

add(new Button(„Schaltflaeche „ + i));<br />

}<br />

}<br />

führt über die folgende Größe im Applet-Tag<br />

<br />

<br />

FlowLayout-Test<br />

<br />

<br />

<br />

<br />

<br />

<br />

zu der folgenden Darstellung<br />

Die GridBagLayout-Klasse und die GridBagConstra<strong>in</strong>t-Klasse<br />

Die Klasse GridBagLayout ermöglicht die Anordnung der Komponenten <strong>in</strong> e<strong>in</strong>em<br />

rasterähnlichen Layout. Zusätzlich zum GridLayout kann kontrolliert werden: Die<br />

Werte e<strong>in</strong>zelner Zellen im Raster, die Proportionen zwischen Zeilen und Spalten<br />

sowie die Anordnung von Komponenten <strong>in</strong>nerhalb der Zellen im Raster. Zur<br />

Erstellung e<strong>in</strong>es GridLayout dienen zwei Klassen:<br />

- GridBagLayout, die den Layoutmanager bereitstellt<br />

- GridBagConstra<strong>in</strong>ts, die die Eigenschaften jeder Komponente im Raster bestimmt.<br />

Die GridBagLayout-Klasse ermöglicht e<strong>in</strong>er Komponente auch die Belegung von<br />

mehr als e<strong>in</strong>er Zelle. Der gesamte Bereich, den die Komponente e<strong>in</strong>nimmt, wird<br />

„display area“ genannt. Bevor e<strong>in</strong>em Conta<strong>in</strong>er e<strong>in</strong>e Komponente h<strong>in</strong>zugefügt<br />

wird, müssen GridBagLayout Vorschläge unterbreitet werden, wo die Komponente<br />

h<strong>in</strong>gestellt werden soll. Die GridBagConstra<strong>in</strong>t-Klasse besitzt verschiedene<br />

Variable zur Steuerung der Anordnung der Komponenten:<br />

226


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

- die Variablen gridx und gridy (Koord<strong>in</strong>aten der Zelle <strong>in</strong> der die nächste Komponente plaziert<br />

werden soll). Die obere l<strong>in</strong>ke Ecke von GridBagLayout liegt bei (0,0), der Standardwert ist<br />

GridBagConstra<strong>in</strong>ts.RELATIVE<br />

- die Variablen gridwidth und gridheight bestimmen, wie viele Zellen hoch und breit e<strong>in</strong>e<br />

Komponente se<strong>in</strong> sollte (Standardwert ist 1). Der Wert GridBagConstra<strong>in</strong>t.REMAINDER für<br />

gridwidth bestimmt, daß e<strong>in</strong>e Komponente die letzte <strong>in</strong> der Spalte se<strong>in</strong> sollte.<br />

- Die Variable fill gibt an, welche Dimension e<strong>in</strong>er Komponente sich verändern soll, wenn e<strong>in</strong>e<br />

Komponente kle<strong>in</strong>er als der Anzeigebereich ist. Gültige Werte s<strong>in</strong>d: NONE, BOTH, HORIZONTAL<br />

und VERTICAL. „GridBagConstra<strong>in</strong>t.BOTH“ sorgt für e<strong>in</strong>e Streckung der Komponenten <strong>in</strong><br />

beiden Richtungen so, daß sie den Anzeigebereich voll ausfüllen.<br />

- Die Variable weightx und weighty def<strong>in</strong>ieren die Gewichtung für freien Raum <strong>in</strong>nerhalb e<strong>in</strong>es<br />

Conta<strong>in</strong>ers und bestimmen die relative Größe der Komponenten. E<strong>in</strong> Komponente mit e<strong>in</strong>em Wert<br />

von 2.0 für weightx nimmt doppelt soviel Platz <strong>in</strong> horizontaler Richtung wie e<strong>in</strong>e Komponente mit<br />

dem Wert 1.0 für weightx.<br />

- Durch „<strong>in</strong>sets“ (Objekte der Klasse Insets) wird der freizuhaltende Rand zwischen Komponente<br />

und Gitter festgelegt. Die Standardwerte für alle 4 Seiten s<strong>in</strong>d Null.<br />

- Die Elemente können zum Teil auch vergrößert werden. Die Pixel, die rechts und l<strong>in</strong>ks zuzufügen<br />

s<strong>in</strong>d, gibt isapdx an. Wieviel obeb und unten h<strong>in</strong>zukommen, speichert isapdy (isapdx, isapdy<br />

s<strong>in</strong>d standardmäßig 0).<br />

Bsp. 174 : Plazieren von Schaltflächen<br />

import java.awt.*;<br />

import java.util.*;<br />

import java.applet.Applet;<br />

public class GridBagBsp extends Applet<br />

{<br />

protected void macheSchalter(Str<strong>in</strong>g name,<br />

GridBagLayout gridbag,<br />

GridBagConstra<strong>in</strong>ts c)<br />

{<br />

Button schalter = new Button(name);<br />

gridbag.setConstra<strong>in</strong>ts(schalter, c);<br />

add(schalter);<br />

}<br />

public void <strong>in</strong>it()<br />

{<br />

GridBagLayout gridbag = new GridBagLayout();<br />

GridBagConstra<strong>in</strong>ts c = new GridBagConstra<strong>in</strong>ts();<br />

setFont(new Font(„Helvetica“, Font.PLAIN, 14));<br />

setLayout(gridbag);<br />

c.fill = GridBagConstra<strong>in</strong>ts.BOTH;<br />

c.weightx = 1.0;<br />

macheSchalter(„Schaltflaeche1“, gridbag, c);<br />

macheSchalter(„Schaltflaeche2“, gridbag, c);<br />

macheSchalter(„Schaltflaeche3“, gridbag, c);<br />

// letzter Schalter <strong>in</strong> der Zeile:<br />

c.gridwidth = GridBagConstra<strong>in</strong>ts.REMAINDER;<br />

macheSchalter(„Schaltflaeche4“, gridbag, c);<br />

// neue Zeile, weightx wiederherstellen:<br />

c.weightx = 0.0;<br />

macheSchalter(„Schaltflaeche5“, gridbag, c);<br />

// vorletztes Element der Zeile:<br />

c.gridwidth = GridBagConstra<strong>in</strong>ts.RELATIVE;<br />

macheSchalter(„Schaltflaeche6“, gridbag, c);<br />

// letztes Element:<br />

c.gridwidth = GridBagConstra<strong>in</strong>ts.REMAINDER;<br />

macheSchalter(„Schaltflaeche7“, gridbag, c);<br />

// neue Zeile, Wert wiederherstellen:<br />

c.gridwidth = 1;<br />

c.gridheight = 2;<br />

c.weighty = 1.0;<br />

174 vgl. PR54205<br />

227


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

macheSchalter(„Schaltflaeche8“, gridbag, c);<br />

c.weighty = 0.0;<br />

c.gridwidth = GridBagConstra<strong>in</strong>ts.REMAINDER;<br />

c.gridheight = 1;<br />

macheSchalter(„Schaltflaeche9“, gridbag, c);<br />

macheSchalter(„Schaltflaeche10“, gridbag, c);<br />

resize(300, 100);<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Frame f = new Frame(„GridBag Layout Beispiel“);<br />

GridBagBsp bsp = new GridBagBsp();<br />

bsp.<strong>in</strong>it();<br />

f.add(„Center“, bsp);<br />

f.pack();<br />

f.resize(f.preferredSize());<br />

f.show();<br />

}<br />

Die CardLayout-Klasse<br />

Das Null-Layout<br />

E<strong>in</strong> Aufruf der Methode „setLayout“ mit dem Argument null erzeugt e<strong>in</strong> Null-<br />

Layout. In diesem Fall verwendet das Fenster ke<strong>in</strong>en Layoutmanager, sondern<br />

überläßt die Positionierung der Komponenten der Anwendung. Je Komponente s<strong>in</strong>d<br />

drei Schritte auszuführen<br />

- Erzeugen der Komponente<br />

- Festlegung von Größe und Position der Komponente<br />

- Übergabe der Komponente an das Fenster.<br />

Größe und Position des Dialogelements können mit<br />

public void setBounds(<strong>in</strong>t x, <strong>in</strong>t y,<strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />

festgelegt werden. Der Punkt (x,y) bestimmt die Anfangsposition und<br />

(breite,hoehe) die Größe.<br />

228


Bsp.:<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public class NL extends Frame<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

NL f = new NL();<br />

f.setVisible(true);<br />

}<br />

public NL()<br />

{<br />

addW<strong>in</strong>dowListener(new W<strong>in</strong>dowAdapter()<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

setVisible(false);<br />

dispose();<br />

System.exit(0);<br />

}<br />

});<br />

setSize(300,250);<br />

setLayout(null);<br />

for (<strong>in</strong>t i = 0; i < 5; i++)<br />

{<br />

Button schalter = new Button("Schalter" + (i+1));<br />

schalter.setBounds(10+i*35,40+i*35,100,30);<br />

add(schalter);<br />

}<br />

}<br />

}<br />

229


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

5.5 Die Event-Modelle 1.0 und 1.1<br />

5.5.1 Der AWT-Handler 1.0<br />

Die Methode handleEvent<br />

Die handleEvent()-Methode 175 ist unter dem AWT-Event-Handler die<br />

allgeme<strong>in</strong>ste Art, wie das AWT auf irgendwelche Ereignisse e<strong>in</strong>geht, die auf der<br />

Benutzeroberfläche stattf<strong>in</strong>den. Ereignisse werden <strong>in</strong>nerhalb der handleEvent()-<br />

Methode <strong>in</strong>terpretiert und dann gezielt passende Methoden aufgerufen. Damit die<br />

handleEvent()-Funktion nicht zu groß und unübersichtlich wird, ruft<br />

handleEvent() mehrere Hilfsfunktionen (mouseEnter, keydown, action, ... )<br />

auf, die die jeweils zugeordneten Events bearbeiten. Die Verarbeitung von<br />

Ereignissen stützt sich auf die Klasse Event. Die Instanzvariable „id“ der Klasse<br />

Event enthält die Art des Ereignisses und liefert alle notwendigen Informationen. Das<br />

Attribut „target“ enthält die Information, welches Objekt das Ereignis ausgelöst hat.<br />

Bsp.: Darstellung e<strong>in</strong>er Datei im Textbereich e<strong>in</strong>es Fensters (Frame)<br />

import java.awt.*;<br />

import java.io.*;<br />

public class DateiDarsteller extends Frame<br />

{<br />

// Instanzvariable<br />

Str<strong>in</strong>g dateiName;<br />

// Konstruktoren<br />

public DateiDarsteller() throws IOException<br />

{<br />

super("Dateidarsteller ");<br />

MenuBar menue = new MenuBar();<br />

Menu m = new Menu("Datei");<br />

m.add(new MenuItem("Oeffnen"));<br />

m.add(new MenuItem("Schliessen"));<br />

menue.add(m);<br />

// Installiere diesen Menuebalken<br />

setMenuBar(menue);<br />

this.show();<br />

}<br />

// Methoden<br />

public void dateiDarstellen() throws IOException<br />

{<br />

try {<br />

File d = new File(dateiName);<br />

<strong>in</strong>t groesse = (<strong>in</strong>t) d.length();<br />

<strong>in</strong>t anzZeich = 0;<br />

FileInputStream e<strong>in</strong> = new FileInputStream(d);<br />

byte[] daten = new byte[groesse];<br />

while (anzZeich < groesse)<br />

anzZeich += e<strong>in</strong>.read(daten,anzZeich,groesse);<br />

Str<strong>in</strong>g s = new Str<strong>in</strong>g(daten,0);<br />

TextArea textBereich = new TextArea(s,24,80);<br />

textBereich.setFont(new Font("Helvetiva",Font.PLAIN,10));<br />

textBereich.setEditable(false);<br />

this.add("Center",textBereich);<br />

175 Die Methode ist <strong>in</strong> der Klasse Component def<strong>in</strong>iert, von der die Klasse java.applet.Applet<br />

abgeleitet ist. Dadurch steht die Methode allen Applets zur Verfügung,<br />

230


}<br />

catch (IOException e) { }<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

this.show();<br />

}<br />

public boolean handleEvent(Event e)<br />

{<br />

if ((e.id == Event.ACTION_EVENT) && (e.target <strong>in</strong>stanceof<br />

MenuItem))<br />

{<br />

if (((MenuItem) e.target).getLabel().equals("Oeffnen"))<br />

{<br />

FileDialog fd = new FileDialog(this,"Dateidialog");<br />

fd.show();<br />

dateiName = fd.getFile();<br />

System.out.pr<strong>in</strong>tln("Date<strong>in</strong>ame: " + dateiName);<br />

try { this.dateiDarstellen(); }<br />

catch (IOException a ) { }<br />

return true;<br />

}<br />

if (((MenuItem) e.target).getLabel().equals("Schliessen"))<br />

{<br />

this.hide();<br />

this.dispose();<br />

System.exit(0);<br />

return true; }<br />

}<br />

return false;<br />

}<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g argv[]) throws IOException<br />

{<br />

try {<br />

DateiDarsteller DD = new DateiDarsteller();<br />

}<br />

catch (IOException e) { System.out.pr<strong>in</strong>tln(e); }<br />

}<br />

}<br />

Behandlung von Aktionsereignissen<br />

Aktionsereignisse werden über public boolean action(Event e, Object<br />

arg) behandelt. Zuerst muß <strong>in</strong>nerhalb der methode überprüft werden, welche<br />

Komponente der Benutzeroberfläche die Aktion erzeugt hat. Zur vere<strong>in</strong>fachten<br />

Bearbeitung be<strong>in</strong>haltet das Event-Objekt, das beim Aufruf von action() erhalten<br />

wird, e<strong>in</strong>e "target"-Instanzvariable, die e<strong>in</strong>e Referenz zu dem Objekt, das das<br />

Ereignis aufgenommen hat, enthält. Mit dem <strong>in</strong>stanceof-Operator kann dann<br />

bestimmt werden, von welcher Komponente das Ereignis ausg<strong>in</strong>g. Das zweite<br />

Argument dient zum Bestimmen des Labels 176 , der Elemente, des Inhalts der<br />

Komponenten 177 . Anstatt des zusätzlichen Arguments kann auch die Methode 178<br />

getLabel verwendet werden.<br />

Behandlung von Fokus-Ereignissen<br />

Für die Ereignisse "Fokuserhalt" und "Fokusverlust" können die Methoden<br />

176 vgl. PR52105<br />

177 Nicht vergessen: Das Argument <strong>in</strong> den richtigen Objekt-Typ zu casten<br />

178 vgl. PR54305<br />

231


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public boolean getFocus(Enet evt, Object arg)<br />

bzw.<br />

public boolean lostFocus(Event evt, Object arg)<br />

verwendet werden.<br />

Ereignisse von Listenfeldern<br />

Listenfelder erzeugen drei verschiedene Ereignisarten: Auswahl bzw. Abwahl e<strong>in</strong>es<br />

E<strong>in</strong>trags <strong>in</strong> der Liste bzw. Doppelklick auf e<strong>in</strong>en E<strong>in</strong>trag. E<strong>in</strong> Doppelklick auf e<strong>in</strong>en<br />

E<strong>in</strong>trag kann mit der Methode action bearbeitet werden. Auswahl und Abwahl<br />

e<strong>in</strong>es Listene<strong>in</strong>trags kann mit "handleEvent" und Überprüfen auf die Ereignisse mit<br />

LIST_SELECT und LIST_DESELECT erfolgen.<br />

5.5.2 Das Event-Handl<strong>in</strong>g <strong>in</strong> <strong>Java</strong> 1.1 bzw. <strong>Java</strong> 1.2<br />

Im neuen Ereignismodell erben die Ereignisklassen von der Klasse<br />

java.util.EventObject. AWT-Events erben von der Klasse<br />

java.awt.AWTEvent.<br />

EventListener<br />

Falls e<strong>in</strong>e Klasse im Ereignisbehandlungsmodell von <strong>Java</strong> 1.2 aus e<strong>in</strong> Ereignis<br />

reagieren will, muß diese e<strong>in</strong>e Schnittstelle implementieren, die dieses Ereignis<br />

verarbeitet. Diese Schnittstellen werden als EventListener bezeichnet. Jeder<br />

Listener behandelt e<strong>in</strong>e bestimmte Ereignisart. E<strong>in</strong>e Klasse kann so viele<br />

Listener implementieren, wie benötigt werden. Die folgenden EventListener<br />

stehen zur Verfügung:<br />

ActionListener Aktionsereignisse, die durch den Benutzer ausgelöst werden, z.B.<br />

Klick auf e<strong>in</strong>e Schaltfläche<br />

AdjustmentListener Ereignisse, die erzeugt werden, wenn werte e<strong>in</strong>er Komponente<br />

e<strong>in</strong>gestellt werden (z.B. Bewegung e<strong>in</strong>es Schiebers e<strong>in</strong>er<br />

Bildlaufleiste)<br />

FocusListener Ereignisse, die erzeugt werden, wenn e<strong>in</strong>e Komponente, z.B. e<strong>in</strong><br />

textfeld, den e<strong>in</strong>gabefokus erhält oder verliert.<br />

ItemListener Ereignisse, die erzeugt werden, wenn e<strong>in</strong> Element, z.B. e<strong>in</strong><br />

Kontrollkästchen, verändert wurde<br />

KeyListener Tastaturereignisse, die bei Tastature<strong>in</strong>gaben erzeugt werden.<br />

MouseListener Mausereignisse, die erzeugt werden, wenn mit der maus geklickt<br />

wird, die Maus <strong>in</strong> den Bereich e<strong>in</strong>er Komponente e<strong>in</strong>tritt bzw. diese<br />

wieder verläßt<br />

MouseMotionListener Mausereignisse, die die Bewegung e<strong>in</strong>er Maus über e<strong>in</strong>e<br />

Komponente verfolgen<br />

W<strong>in</strong>dowListener Ereignisse, die von Fenstern erzeugt werden<br />

Das Paket java.awt.event be<strong>in</strong>haltet alle elementaren EventListener. Über<br />

import java.awt.event.* erfolgt das Importieren <strong>in</strong> die Anwendungen.<br />

232


Event-Handl<strong>in</strong>g mit Hilfe lokaler Klasse<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Für die Ereignisbehandlung werden lokale Klassen herangezogen. Im JDK 1.0<br />

wurden Klassen nur auf Paketen def<strong>in</strong>iert, e<strong>in</strong>e Schachtelung war nicht möglich. Im<br />

JDK 1.1 kann <strong>in</strong>nerhalb bestehender Klassen e<strong>in</strong>e neue Klasse def<strong>in</strong>iert werden<br />

(Konzept der „Inner Classes“), die nur <strong>in</strong>nerhalb der bestehenden Klasse sichtbar ist.<br />

Objekt<strong>in</strong>stanzen der <strong>in</strong>neren Klasse können nur aus der umfassenden Klasse heraus<br />

erzeugt werden. Allerd<strong>in</strong>gs kann die <strong>in</strong>nere Klasse auf die Instanzvariablen der<br />

äußeren Klasse zugreifen.<br />

Mit Hilfe lokaler Klassen werden die benötigten EventListener implementiert. Dazu<br />

wird <strong>in</strong> dem GUI-Objekt, das e<strong>in</strong>en Event-Handler benötigt, e<strong>in</strong>e lokale Klasse<br />

def<strong>in</strong>iert (und aus e<strong>in</strong>er passenden AdapterKlasse abgeleitet).<br />

E<strong>in</strong> e<strong>in</strong>führendes Bsp.: Event-Handl<strong>in</strong>g nach der Bearbeitung von Schaltflächen des<br />

AWT <strong>in</strong> Version 1.0 und 1.1<br />

// E<strong>in</strong>fangen von Klicks auf Schaltflaechen<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

import java.applet.*;<br />

public class SchalterAppl extends Applet<br />

{<br />

Button sch1 = new Button("Schaltflaeche 1");<br />

Button sch2 = new Button("Schaltflaeche 2");<br />

public void <strong>in</strong>it()<br />

{<br />

sch1.addActionListener(new Sch1());<br />

sch2.addActionListener(new Sch2());<br />

add(sch1);<br />

add(sch2);<br />

}<br />

class Sch1 implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

getAppletContext().showStatus("Schaltflaeche 1");<br />

}<br />

}<br />

class Sch2 implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

getAppletContext().showStatus("Schaltflaeche 2");<br />

}<br />

}<br />

/*<br />

public boolean action(Event e, Object welcheAktion)<br />

{<br />

if (e.target.equals(sch1))<br />

getAppletContext().showStatus("Schaltflaeche 1");<br />

else if (e.target.equals(sch2))<br />

getAppletContext().showStatus("Schaltflaeche 2");<br />

else<br />

return super.action(e,welcheAktion);<br />

return true;<br />

}<br />

*/<br />

}<br />

233


E<strong>in</strong>fügen / Entfernen passender Listener<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Das neue Event-Modell von <strong>Java</strong> 1.1 bzw. 1.2 hat mit dem JDK 1.0 offensichtlich nur<br />

noch wenig geme<strong>in</strong>sam. Alle AWT-Komponenten haben im neuen AWT-Event-<br />

Handl<strong>in</strong>g „addXXXListener()“- und „removeXXXListener()“-Methoden<br />

erhalten. „XXX“ beschreibt den Typ des Events. Die folgende Tabelle zeigt<br />

Ereignisse, „Listeners“, Methoden und Komponenten, die über addXXXListener()<br />

bzw. removeXXXListener() auf spezifische Ereignisse reagieren:<br />

Event, „listener <strong>in</strong>terface“ und „add“- bzw.<br />

„remove“-Methoden<br />

ActionEvent<br />

ActionListener<br />

addActionListener()<br />

removeActionListener()<br />

AdjustmentEvent<br />

AdjustmentListener<br />

addAdjustmentListener()<br />

removeAdjustmentListener()<br />

ComponenEvent<br />

ComponenListener<br />

addComponenListener()<br />

removeComponentListener()<br />

Conta<strong>in</strong>erEvent<br />

Conta<strong>in</strong>erListener<br />

addConta<strong>in</strong>erListener()<br />

removeConta<strong>in</strong>erListener()<br />

FocusEvent<br />

FocusListener<br />

addFocusListener()<br />

removeFocusListener()<br />

KeyEvent<br />

KeyListener<br />

addKeyListener()<br />

removeKeyListener()<br />

MouseEvent<br />

MouseListener<br />

addMouseListener()<br />

removeMouseListener()<br />

MouseEvent<br />

MouseMotionListener<br />

addMouseMotionListener()<br />

removeMouseMotionListener()<br />

W<strong>in</strong>dowEvent<br />

W<strong>in</strong>dowListener<br />

addW<strong>in</strong>dowListener()<br />

removeW<strong>in</strong>dowListener()<br />

ItemEvent<br />

ItemListener<br />

addItemListener()<br />

removeItemListener()<br />

TextEvent<br />

TextListener<br />

234<br />

Komponenten, die dieses Ereignis unterstützen<br />

Button, List, TextField, MenuItem und se<strong>in</strong>e<br />

abkömml<strong>in</strong>ge e<strong>in</strong>schl. CheckboxmenuItem, menu<br />

und PopupMenu<br />

Scrollbar,<br />

alles was mit der Erzeugung vom „Adjustable“-<br />

Interface zu tun hat<br />

Component und se<strong>in</strong>e Abkömml<strong>in</strong>ge, e<strong>in</strong>schl.<br />

Button, Canvas, Checkbox, Choice, Conta<strong>in</strong>er,<br />

Panel, Applet, ScrollPane, W<strong>in</strong>dow, Dialog,<br />

FileDialog, Frame, Label, List, Scrollbar, TextArea,<br />

TextField<br />

Conta<strong>in</strong>er und se<strong>in</strong>e Abkömml<strong>in</strong>ge, e<strong>in</strong>schl. Panel,<br />

Applet, ScrollPane, W<strong>in</strong>dow, Dialog, FileDialog,<br />

Frame<br />

Component und se<strong>in</strong>e Abkömml<strong>in</strong>ge e<strong>in</strong>schl.<br />

Button, Canvas, Conta<strong>in</strong>er, Panel, Applet,<br />

ScrollPane, W<strong>in</strong>dow, Dialog, FileDialog,<br />

FrameLabel, List, Scrollbar, TextArea, TextField<br />

Component und se<strong>in</strong>e Abkömml<strong>in</strong>ge e<strong>in</strong>schl.<br />

Button, Canvas, Checkbox, Choice, Conta<strong>in</strong>er,<br />

Panel, Applet, ScrollPane, W<strong>in</strong>dow, Dialog,<br />

FileDialog, Frame, Label, List, Scrollbar, TextArea,<br />

TextField<br />

Component und se<strong>in</strong>e Abkömml<strong>in</strong>ge e<strong>in</strong>schl.<br />

Button, Canvas, Checkbox, Choice, Conta<strong>in</strong>er,<br />

Panel, Applet, ScrollPane, W<strong>in</strong>dow, Dialog,<br />

FileDialog, Frame, Label, List, Scrollbar, TextArea,<br />

TextField<br />

Component und se<strong>in</strong>e Abkömml<strong>in</strong>ge e<strong>in</strong>schl.<br />

Button, Canvas, Checkbox, Choice, Conta<strong>in</strong>er,<br />

Panel, Applet, ScrollPane, W<strong>in</strong>dow, Dialog,<br />

FileDialog, Frame, Label, List, Scrollbar, TextArea,<br />

TextField<br />

W<strong>in</strong>dow und se<strong>in</strong>e Abkömml<strong>in</strong>ge e<strong>in</strong>schl. Dialog,<br />

FileDialog und Frame<br />

Checkbox, CkeckboxMenuItem, Choice, List und<br />

alles, was das ItemSelectable Interface<br />

implementiert<br />

Alles was von TextComponent e<strong>in</strong>schl. TextArea<br />

und TextField abgeleitet ist


addTextListener()<br />

removeTextListener()<br />

Abb.: Event- und Listener-Typen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Jeder Komponenten-Typ unterstützt nur bestimmte Ereignis-Typen:<br />

Komponenten-Typ Ereignis, das durch die Komponente unterstützt<br />

wird<br />

Adjustable AdjustmentEvent<br />

Applet Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

Button ActionEvent,<br />

Canvas FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

Checkbox ItemEvent, FocusEvent, KexEvent, MouseEvent,<br />

ComponentEvent<br />

CheckboxMenuItem ActionEvent, ItemEvent<br />

Choice ItemEvent, FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

Component FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

Conta<strong>in</strong>er Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

Dialog Conta<strong>in</strong>erEvent, W<strong>in</strong>dowEvent, FocusEvent,<br />

KeyEvent, MouseEvent, ComponentEvent<br />

FileDialog Conta<strong>in</strong>erEvent, W<strong>in</strong>dowEvent, FocusEvent,<br />

KeyEvent, MouseEvent, ComponentEvent<br />

Frame Conta<strong>in</strong>erEvent, W<strong>in</strong>dowEvent, FocusEvent,<br />

KeyEvent, MouseEvent, ComponentEvent<br />

Label FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

List ActionEvent, FocusEvent, KeyEvent, MouseEvent,<br />

ItemEvent, ComponentEvent<br />

Menu ActionEvent<br />

MenuItem ActionEvent<br />

Panel Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

PopupMenu ActionEvent<br />

Scrollbar AdjustmentEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

ScrollPane Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

TextArea TextEvent, FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

TextComponent TextEvent, FocusEvent, KeyEvent, MouseEvent,<br />

ComponentEvent<br />

TextField ActionEvent, TextEvent, FocusEvent, KeyEvent,<br />

MouseEvent, ComponentEvent<br />

W<strong>in</strong>dow Conta<strong>in</strong>erEvent, W<strong>in</strong>dowEvent, FocusEvent,<br />

KeyEvent, MouseEvent, ComponentEvent<br />

Abb.: Komponenten-Typ und Ereignisse<br />

Methoden für die Ereignisbehandlung<br />

Da nun bekannt ist, welche Ereignisse e<strong>in</strong>e bestimmte Komponente unterstützt, kann<br />

das zugehörige „Listener“-Interface angegeben werden:<br />

235


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

„Listener“-Interface Methoden<br />

ActionListener actionPerformed(ActionEvent)<br />

AdjustmentListener adjustmentValueChanged(<br />

ComponentListener<br />

ComponentAdapter<br />

Conta<strong>in</strong>erListener<br />

Conta<strong>in</strong>erAdapter<br />

FocusListener<br />

FocusAdapter<br />

KeyListener<br />

KeyAdapter<br />

MouseListener<br />

MouseAdapter<br />

236<br />

AdjustmentEvent)<br />

componentHidden(ComponentEvent)<br />

componentShown(ComponentEvent)<br />

componentMoved(ComponentEvent)<br />

componentResized(ComponentEvent)<br />

componentAdded(Conta<strong>in</strong>erEvent)<br />

componentRemoved(Conta<strong>in</strong>erEvent)<br />

focusGa<strong>in</strong>ed(FocusEvent)<br />

focusLost(FocusEvent)<br />

keyPressed(KeyEvent)<br />

keyReleased(KeyEvent)<br />

keyTyped(KeyEvent)<br />

mouseClicked(MouseEvent)<br />

mouseEntered(MouseEvent)<br />

mouseExited(MouseEvent)<br />

mousePressed(MouseEvent)<br />

mouseReleased(MouseEvent)<br />

mouseDragged(MouseEvent)<br />

MouseMotionListener<br />

MouseMotionAdapter<br />

mouseMoved(MouseEvent)<br />

W<strong>in</strong>dowListener<br />

w<strong>in</strong>dowOpened(W<strong>in</strong>dowevent)<br />

W<strong>in</strong>dowadapter<br />

w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent)<br />

w<strong>in</strong>dowClosed(W<strong>in</strong>dosEvent)<br />

w<strong>in</strong>dowActivated(W<strong>in</strong>dowEvent)<br />

w<strong>in</strong>dowDeactivated(W<strong>in</strong>dowEvent)<br />

w<strong>in</strong>dowIconified(W<strong>in</strong>dowEvent)<br />

w<strong>in</strong>dowDeiconified(W<strong>in</strong>dowEvent)<br />

ItemListener ItemStateChanged(ItemEvent)<br />

TextListener textValueChanged(TextEvent)<br />

Abb.: Listener-Interface<br />

Adapter besorgen Default-Methoden für jede Methode im Interface. Nur die<br />

Methode, die geändert wird, muß überschrieben werden.<br />

Komponenten des AWT <strong>in</strong> Fenstern bzw. Applets unter <strong>Java</strong> 1.1<br />

Die <strong>in</strong> den folgenden Programmen verwendeten Komponenten können <strong>in</strong> e<strong>in</strong>em<br />

Fenster (Frame) über die Instanz e<strong>in</strong>es Applet dargestellt werden. Das Programm<br />

enthält deshalb zusätzlich zu den für Applets nötigen Methoden e<strong>in</strong>e ma<strong>in</strong>()-<br />

Methode, die e<strong>in</strong>e Instanz e<strong>in</strong>es Applets <strong>in</strong>nerhalb e<strong>in</strong>es Frame aufbaut.


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bsp.: Bearbeitung von zwei Schaltflächen und e<strong>in</strong>em Textfeld 179<br />

// E<strong>in</strong>e Anwendung und e<strong>in</strong> Applet<br />

import java.awt.*;<br />

import java.awt.event.*;<br />

import java.applet.*;<br />

public class SchalterApplet extends Applet<br />

{<br />

Button sch1 = new Button("Schaltflaeche 1");<br />

Button sch2 = new Button("Schaltflaeche 2");<br />

TextField t = new TextField(20);<br />

public void <strong>in</strong>it()<br />

{<br />

sch1.addActionListener(new Sch1());<br />

sch2.addActionListener(new Sch2());<br />

add(sch1);<br />

add(sch2);<br />

add(t);<br />

}<br />

class Sch1 implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

t.setText("Schaltflaeche 1");<br />

}<br />

}<br />

class Sch2 implements ActionListener<br />

{<br />

public void actionPerformed(ActionEvent e)<br />

{<br />

t.setText("Schaltflaeche 2");<br />

}<br />

}<br />

// Schliessen der Applikation<br />

static class WL extends W<strong>in</strong>dowAdapter<br />

{<br />

public void w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)<br />

{<br />

System.exit(0);<br />

}<br />

}<br />

// ma<strong>in</strong>()-Methode fuer die Applikation<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

SchalterApplet applet = new SchalterApplet();<br />

Frame e<strong>in</strong>Rahmen = new Frame("Schalterdarstellung");<br />

e<strong>in</strong>Rahmen.addW<strong>in</strong>dowListener(new WL());<br />

e<strong>in</strong>Rahmen.add(applet,BorderLayout.CENTER);<br />

e<strong>in</strong>Rahmen.setSize(300,200);<br />

applet.<strong>in</strong>it();<br />

applet.start();<br />

e<strong>in</strong>Rahmen.setVisible(true);<br />

}<br />

}<br />

179 PR55202<br />

237


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

5.6 Benutzerschnittstellen mit Sw<strong>in</strong>g<br />

Sw<strong>in</strong>g-Komponenten s<strong>in</strong>d Subklassen der Klasse JComponent.<br />

5.6.1 Komponenten und Conta<strong>in</strong>er<br />

238


6. Utilities<br />

6.1 Collections<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Collections s<strong>in</strong>d Datenstrukturen zur Aufnahme und Verarbeitung von Datenmengen.<br />

Typische Collections s<strong>in</strong>d Stacks, Queues, Deques, Priority Queues, Listen oder<br />

Trees (Bäume).<br />

In <strong>Java</strong> existieren seit der Version 1.0 die Collections Vector, Stack, Hashtable und<br />

Bitset. Die Kritik an diesem Collection-Konzept führte zu e<strong>in</strong>er Sammlung von 20<br />

Klassen und Interfaces im Paket java.util des JDK 1.2. Im Wesentlichen s<strong>in</strong>d dies:<br />

Set, List und Map.<br />

- E<strong>in</strong>e List ist e<strong>in</strong>e beliebig große Liste von Elementen beliebigen Typs, auf die wahlfrei und sequentiell<br />

zugegriffen werden kann<br />

- E<strong>in</strong> Set ist e<strong>in</strong>e Menge von Elementen (ohne Duplikate), auf die mit typischen Mngenoperationen<br />

zugegriffen werden kann.<br />

- E<strong>in</strong>e Map ist e<strong>in</strong>e Abbildung von Elementen e<strong>in</strong>es Typs auf Elemente e<strong>in</strong>es anderen Typs (Menge<br />

zusammengehöriger Paare).<br />

Jede dieser Grundformen ist als Interface und den angegebenen Namen<br />

implementiert. Zudem gibt es jeweils e<strong>in</strong>e oder mehrere konkrete<br />

Implementierungen. So gibt es bspw. für das Interface List die<br />

Implementierungsvarianten L<strong>in</strong>kedList bzw. die abstrakte Implementierung<br />

AbstractList.<br />

6.1.1 Die Klasse Vector<br />

Objekte der Klasse Vector s<strong>in</strong>d Repräsentationen e<strong>in</strong>er l<strong>in</strong>earen Liste. Die Liste<br />

kann Elemente beliebigen Typs enthalten, ihre Länge ist zur Laufzeit veränderbar.<br />

Vector erlaubt das E<strong>in</strong>fügen von Elementen an beliebiger Stelle, bietet<br />

sequentiellen und wahlfreien Zugriff auf die Elemente. Das JDK realisiert Vector als<br />

Array von Elementen des Typs Object.<br />

Anlegen e<strong>in</strong>es neuen Vektors (Konstruktor): public Vector()<br />

E<strong>in</strong>fügen von Elementen: public void addElement(Object obj)<br />

// Anhängen an des Ende der bisher vorliegenden Liste von Elementen<br />

Eigenschaften: public f<strong>in</strong>al boolean isEmpty()<br />

// Prüfen, ob der Vektor leer ist<br />

public f<strong>in</strong>al <strong>in</strong>t size()<br />

// bestimmt die Anzahl der Elemente<br />

E<strong>in</strong>fügen an beliebiger Stelle <strong>in</strong>nerhalb der Liste:<br />

public void <strong>in</strong>sertElementAt(Object obj, <strong>in</strong>t <strong>in</strong>dex) throws<br />

ArrayIndexOutOfBoundsException<br />

// fügt obj an die Position <strong>in</strong>dex <strong>in</strong> den „Vector“ e<strong>in</strong>.<br />

Zugriff auf Elemente: Für den sequentiellen Zugriff steht e<strong>in</strong> Iterator zur Verfügung.<br />

Wahlfreier Zugriff erfolgt über:<br />

public Object firstElement() throws ArrayIndexOutOfBoundException;<br />

public Object lastElement() throws ArrayIndexOutOfBoundException;<br />

public Object elementAt() throws ArrayIndexOutOfBoundException;<br />

239


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

firstElement liefert das erste, lastElement das letzte Element- Mit<br />

elementAt() wird auf das Element an der Position <strong>in</strong>dex zugegriffen. Alle 3<br />

Methoden verursachen e<strong>in</strong>e Ausnahme, wenn das gewünschte Element nicht<br />

vorhanden ist. E<strong>in</strong> Iterator wird <strong>in</strong> <strong>Java</strong> durch das Interface Enumeration<br />

bereitgestellt 180 .<br />

Das Interface Enumeration.<br />

public Interface Enumeration<br />

{<br />

public boolean hasMoreElements();<br />

public Object nextElement() throws NoSuchElementException;<br />

// setzt den <strong>in</strong>ternen zeiger auf das nächste Element<br />

}<br />

In der Klasse Vector liefert die Methode public Enumeration elements()<br />

e<strong>in</strong>en Enumerator für alle Elemente, die sich <strong>in</strong> Vector bef<strong>in</strong>den, z.B.:<br />

6.1.2 Die Klasse Stack<br />

E<strong>in</strong> Stack ist e<strong>in</strong>e nach dem LIFO-Pr<strong>in</strong>zip arbeitende Datenstruktur. Elemente<br />

werden vorn (am vorderen Ende der Liste) e<strong>in</strong>gefügt und von dort auch wieder<br />

entnommen. In <strong>Java</strong> ist e<strong>in</strong> Stack e<strong>in</strong>e Ableitung von Vector mit neuen<br />

Zugriffsfunktionen für die Implementierung des typischen Verhaltens von e<strong>in</strong>em<br />

Stack.<br />

Konstruktor: public Stack();<br />

H<strong>in</strong>zufügen neuer Elemente: public Object push(Object item);<br />

Zugriff auf das oberste Element:<br />

public Object pop();<br />

// Zugriff und Entfernen des obersten Element<br />

public Object peek()<br />

// Zugriff auf das oberste Element<br />

Suche im Stack: public <strong>in</strong>t search(Object o)<br />

// Suche nach beliebigem Element,<br />

// Rueckgabewert: Distanz zwischen gefundenem und<br />

// obersten Stack-Element<br />

Test: public boolean empty()<br />

// bestimmt, ob der Stack leer ist<br />

Anwendung: „Umrechnen von Dezimalzahlen <strong>in</strong> andere Basisdarstellungen<br />

Aufgabenstellung: Defaultmäßig werden Zahlen dezimal ausgegeben. E<strong>in</strong> Stapel,<br />

der Ganzzahlen aufnimmt, kann dazu verwendet werden, Zahlen bezogen auf e<strong>in</strong>e<br />

andere Basis als 10 darzustellen. Die Funktionsweise der Umrechnung von<br />

Dezimalzahlen <strong>in</strong> e<strong>in</strong>e Basis e<strong>in</strong>es anderen Zahlensystem zeigen die folgenden<br />

Beispiele:<br />

2810 = 3⋅ 8 + 4 = 348<br />

180 und wird deshalb <strong>in</strong> der <strong>Java</strong>-Welt Enumerator genannt.<br />

240


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

7210 = 1⋅ 64 + 0⋅ 16 + 2 ⋅ 4 + 0 = 10204<br />

5310 = 1⋅ 32 + 1⋅ 16 + 0⋅ 8 + 1⋅ 4 + 0⋅ 2 + 1 = 1101012<br />

Mit e<strong>in</strong>em Stapel läßt sich die Umrechnung folgendermaßen unterstützen:<br />

241<br />

6<br />

7 7<br />

4 4 4<br />

1 1 1 1<br />

leerer Stapel n%8=1 n%8=4 n%8=7 n%8=6<br />

n = 3553 10 n/8=444 n/8=55 n/8=6 n/6=0<br />

n = 444 10 n = 55 10 n = 6 10 n = 0 10<br />

Abb.: Umrechnung von 355310 <strong>in</strong> 67418 mit Hilfe e<strong>in</strong>es Stapel<br />

Algorithmus zur Lösung der Aufgabe:<br />

1) Die am weitesten rechts stehende Ziffer von n ist n%b. Sie ist auf dem Stapel abzulegen.<br />

2) Die restlichen Ziffern von n s<strong>in</strong>d bestimmt durch n/b. Die Zahl n wird ersetzt durch n/b.<br />

3) Wiederhole die Arbeitsschritte 1) und 2) bis ke<strong>in</strong>e signifikanten Ziffern mehr übrig bleiben.<br />

4) Die Darstellung der Zahl <strong>in</strong> der neuen Basis ist aus dem Stapel abzulesen. Der Stapel ist zu diesem<br />

Zweck zu entleeren.<br />

Implementierung: Das folgende kle<strong>in</strong>e Testprogramm 181 realisiert den Algorithmus<br />

und benutzt dazu e<strong>in</strong>e Instanz von Stack.<br />

import java.util.*;<br />

public class PR61210<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

<strong>in</strong>t zahl = 3553; // Dezimalzahl<br />

<strong>in</strong>t b = 8; // Basis<br />

Stack s = new Stack(); // Stapel<br />

do<br />

{<br />

s.push(new Integer(zahl % b));<br />

zahl /= b;<br />

} while (zahl != 0);<br />

while (!s.empty())<br />

{<br />

System.out.pr<strong>in</strong>t(s.pop());<br />

}<br />

System.out.pr<strong>in</strong>tln();<br />

}<br />

}<br />

181 PR61210


6.1.3 Die Klasse Hashtable<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Klasse Hashtable ist e<strong>in</strong>e Konkretisierung der abstrakten Klasse Dictionary.<br />

Diese Klasse beschreibt e<strong>in</strong>en assoziativen Speicher, der Schlüssel auf Werte<br />

abbildet und über den Schlüsselbegriff e<strong>in</strong>en effizienten Zugriff auf den Wert<br />

ermöglicht.<br />

Konstruktor. public Hashtable()<br />

E<strong>in</strong>fügen von Elementen. public Object put(Object key, Object wert)<br />

Der Auruf von „put“ fügt das Schlüssel-Werte-Paar (key,wert) <strong>in</strong> die Hashtable<br />

e<strong>in</strong>. Weder key noch wert dürfen dabei null se<strong>in</strong>. Falls bereits e<strong>in</strong> Wertepaar mit<br />

dem Schlüssel key vorliegt, wird der bisherige Wert gegen den neuen ausgetauscht,<br />

und put liefert <strong>in</strong> diesem Fall den Wert zurück, der bisher dem Schlüssel zugeordnet<br />

war<br />

Zugriff auf Elemente. public Object get(Object key)<br />

// get() erwartet e<strong>in</strong> Schlüsselobjekt<br />

// und liefert den dazu passenden Wert<br />

Zusätzlich gibt es noch:<br />

public boolean conta<strong>in</strong>s(Object wert)<br />

// Test auf e<strong>in</strong>en bestimmten Wert<br />

public boolean conta<strong>in</strong>sKey(Object key)<br />

// Test auf e<strong>in</strong>en bestimmten Schlüssel<br />

Iteratoren. In der Klasse HahTable gibt es zwei Iteratoren:<br />

public Enumeration elements()<br />

// Iterator für die Auflistung aller Werte der Hashtabelle.<br />

public Enumeration keys()<br />

// Iterator für die Auflistung aller schlüssel<br />

Bsp.: Hashtabelle zum Test der Zufälligkeit von Zufallszahlen der Klasse<br />

Math.random.<br />

import java.util.*;<br />

class Zaehler<br />

{<br />

<strong>in</strong>t i = 1;<br />

public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />

{<br />

return Integer.toStr<strong>in</strong>g(i);<br />

}<br />

}<br />

class Statistik<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />

{<br />

Hashtable h = new Hashtable();<br />

for (<strong>in</strong>t i = 0; i < 10000; i++)<br />

{<br />

// Erzeuge e<strong>in</strong>e Zahl zwischen 0 und 20<br />

Integer r = new Integer((<strong>in</strong>t)(Math.random() * 20));<br />

if (h.conta<strong>in</strong>sKey(r))<br />

((Zaehler) h.get(r)).i++;<br />

else h.put(r,new Zaehler());<br />

}<br />

System.out.pr<strong>in</strong>tln(h);<br />

}<br />

}<br />

242


6.1.4 Die Klasse Properties<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die Klasse Properties ist aus HashTable abgeleitet.<br />

6.1.5 Die Klasse BitSet<br />

6.2 <strong>Java</strong> 2 Collections<br />

6.2.1 Die Collection des Typs List<br />

6.3 Die Klasse Str<strong>in</strong>gTokenizer<br />

6.4 Die Klasse Random<br />

6.5 Die Klassen Date, Calendar<br />

243


7. E<strong>in</strong>- und Ausgabe<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

In <strong>Java</strong> werden E<strong>in</strong>-, Ausgabeoperationen über sog. Datenströme182 realisiert. Es<br />

stehen zur Behandlung des Datenstrommodells zwei abstrakte Klassen zur<br />

Verfügung: InputStream und OutputStream. Die beiden Klassen gehören zu<br />

dem Paket java.io183 , das bei jedem Programm mit E<strong>in</strong>-/Ausgabeoperationen<br />

importiert werden muß.<br />

E<strong>in</strong>fache Strom-Methoden erlauben nur das Versenden von Bytes mit Hilfe von<br />

Datenströmen184 . E<strong>in</strong> nicht <strong>in</strong>terpretierbarer Bytestrom kann von jeder beliebigen<br />

Quelle kommen. Quelle bzw. Ziel des Stroms s<strong>in</strong>d völlig verschiedene Erzeuger bzw.<br />

Verbraucher von Bytes.<br />

Allgeme<strong>in</strong>e Methoden, die von jeder beliebigen Quelle lesen können, akzeptieren e<strong>in</strong><br />

Stromargument zur Bezeichnung der Quelle. Allgeme<strong>in</strong>e Methoden zum Schreiben<br />

akzeptieren e<strong>in</strong>en Strom zur Zielbestimmung. Filter haben zwei Stromargumente. Sie<br />

lesen vom ersten, verarbeiten die Daten und Schreiben <strong>in</strong>s zweite.<br />

Zum Senden/Empfangen verschiedener Datentypen gibt es die Schnittstellen<br />

DataInput und DataOutput. Sie legen Methoden zum Senden/Empfangen<br />

anderer <strong>Java</strong>-Datentypen fest. Mit Hilfe der Schnittstellen ObjectInput und<br />

ObjectOutput lassen sich ganze Objekte über e<strong>in</strong>en Strom senden.<br />

Alle Methoden, die sich mit E<strong>in</strong>- und Ausgabeoperationen beschäftigen, werden <strong>in</strong><br />

der Regel mit throws IOException abgesichert. Diese Subklasse von Exception<br />

enthält alle potentiellen I/O-Fehler, die bei der Verwendung von Datenströmen<br />

auftreten können.<br />

Die I/O-Exceptions können direkt mit e<strong>in</strong>em try-catch-Block aufgefangen oder an<br />

übergeordnete Methoden weitergegeben werden.<br />

182 Der Begriff Strom kommt aus dem Betriebssystem Unix und bezieht sich auf „Pipes“. E<strong>in</strong>e Pipe ist e<strong>in</strong> nicht<br />

<strong>in</strong>terprtierbarer Strom von Bytes, der zur Kommunikation zwischen Programmen (bzw. „gegabelten Kopien“<br />

e<strong>in</strong>es Programms) oder zum Lesen und Schreiben von verschiedenen Geräten und Dateien benutzt wird.<br />

E<strong>in</strong> Strom ist e<strong>in</strong> Kommunikationspfad zwischen der Quelle und dem Ziel e<strong>in</strong>es Informationsblocks.<br />

183 Die Klasse java.io enthält e<strong>in</strong>e große Anzahl von Klassen zur E<strong>in</strong>-/Ausgabe. Die meisten dieser Klassen<br />

leiten sich von InputStream bzw. OutputStream ab.<br />

184 E<strong>in</strong> Strom von Bytes kann mit e<strong>in</strong>em Wasserstrom verglichen werden. Wird aus e<strong>in</strong>em Strom Wasser<br />

entnommen, dann wird er als E<strong>in</strong>gabestrom benutzt. Wird <strong>in</strong> e<strong>in</strong>en Strom Wasser geschüttet, dann wird er als<br />

Ausgabestrom verwendet. Die Verb<strong>in</strong>dung von Strömen kann mit dem Verb<strong>in</strong>den von Wasserschläuchen<br />

verglichen werden.<br />

244


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

ByteArrayInputStream<br />

FileInputStream BufferedInputSteam<br />

DataInput DataInputStram<br />

FilterInputStream<br />

L<strong>in</strong>eNumberInputSteam<br />

InputStream PipedInputStream PushbackInputStream<br />

SequenceInputStream<br />

Str<strong>in</strong>gBufferedInputStream<br />

Object RandomAccessFile<br />

Abb.: java.io<br />

OutputStream<br />

ByteArrayOutputStream<br />

FileOutputStram<br />

FilterOutputStream BufferdOutputStream<br />

DataOutput DataOutputStream<br />

PipedOutputStream Pr<strong>in</strong>tStream<br />

EOFException<br />

FileNotFoundException<br />

Throwable Exception IOException InterruptedIOException<br />

UTFDataFormatException<br />

7.1 Die abstrakten Klassen InputStream und OutputStream<br />

7.1.1 InputStream<br />

Aufgabenbeschreibung<br />

Mit dieser Klasse können Leseoperationen e<strong>in</strong>es Bytestroms verwirklicht werden.<br />

Woher die Bytes kommen und wie sie befördert werden, spielt ke<strong>in</strong>e Rolle. Sie<br />

müssen dem e<strong>in</strong>lesenden Objekt nur zur Verfügung stehen. Die Aufgabe der Klasse<br />

InputStream ist die Repräsentation von Klassen, die E<strong>in</strong>gaben aus verschiedenen<br />

Quellen produzieren.<br />

Klasse Funktion Argument für den Konstruktor<br />

Nutzungsmöglichkeit<br />

ByteArrayInputStream E<strong>in</strong> Puffer im arbeitsspeicher Der Puffer aus dem Bytes geholt<br />

wird ald E<strong>in</strong>gabestrom benutzt. werden.<br />

Als Datenquelle. Verbunden mit<br />

e<strong>in</strong>em FileInputStream-Objekt<br />

kann daraus e<strong>in</strong> nützliches<br />

Str<strong>in</strong>gBufferInputStream Konvertiert e<strong>in</strong>en Str<strong>in</strong>g <strong>in</strong> e<strong>in</strong>en<br />

Interface gestaltet werden.<br />

E<strong>in</strong> Str<strong>in</strong>g. Die zugrundeliegende<br />

InputStream<br />

Implementierung benutzt e<strong>in</strong>en<br />

Str<strong>in</strong>gBuffer.<br />

Als Datenquelle. Verbunden mit<br />

e<strong>in</strong>em FiIenputStream-Objekt<br />

245


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

kann daraus e<strong>in</strong> nützliches<br />

Interface gestaltet werden.<br />

FileInputStream Dient zum Lesen aus e<strong>in</strong>er Datei E<strong>in</strong> Str<strong>in</strong>g der den Date<strong>in</strong>amen<br />

enthält oder e<strong>in</strong> File- bzw.<br />

FileDescriptor-Objekt<br />

Als Datenquelle. Verbunden mit<br />

e<strong>in</strong>em FilterInputStream-Objekt<br />

kann daraus e<strong>in</strong> nützliches<br />

PipedInputStream Produziert Daten für den<br />

PipedOutputStream (implentiert<br />

das „Pipe“-Konzept.<br />

SequenceInputStream Konvertiert zwei oder mehrere<br />

„InputStream“-Objekte <strong>in</strong> e<strong>in</strong>en<br />

e<strong>in</strong>zelnen InputStream.<br />

Abb.: E<strong>in</strong>gabestrom-Typen<br />

Quellen zu e<strong>in</strong>em E<strong>in</strong>gabestrom können se<strong>in</strong>:<br />

246<br />

Interface gestaltet werden.<br />

PipedOutputStram.<br />

Als Datenquelle im<br />

Multithread<strong>in</strong>g. Verbunden mit<br />

e<strong>in</strong>em FilterInputStream-Objekt<br />

kann daraus e<strong>in</strong> nützliches<br />

Interface gestaltet werden.<br />

Zwei InputStream-Objekte oder<br />

e<strong>in</strong>e Enumeration für e<strong>in</strong>en<br />

Conta<strong>in</strong>er von InputStream-<br />

Objekten.<br />

Als Datenquelle. Verbunden mit<br />

e<strong>in</strong>em FilterInputStream-Objekt<br />

kann daraus e<strong>in</strong> nützliches<br />

Interface gestaltet werden.<br />

1. E<strong>in</strong> Array von Bytes<br />

2. E<strong>in</strong> Zeichenketten-Objekt<br />

3. E<strong>in</strong>e Datei<br />

4. E<strong>in</strong>e „Pipe“<br />

5. E<strong>in</strong>e Folge von Strömen, die zu e<strong>in</strong>em umfassenden, e<strong>in</strong>zelnen Strom gesammelt werden können.<br />

6. Anders beschaffene Quellen, z.B. e<strong>in</strong>e Internet-Verb<strong>in</strong>dung<br />

Die „read“-Methoden<br />

Zum E<strong>in</strong>lesen von Datenströmen gibt es die „read“-Methode. Die e<strong>in</strong>fachste Form<br />

ist: public abstract <strong>in</strong>t read() throws IOException. E<strong>in</strong> e<strong>in</strong>zelnes Byte<br />

wird aus dem E<strong>in</strong>gabestrom gelesen und ausgegeben. Falls der Bytestrom das Ende<br />

erreicht hat, wird „-1“ 185 ausgageben. Die Methode führt e<strong>in</strong> blockierendes Lesen<br />

aus, d.h.: Es wird auf Daten gewartet, falls sie nicht unmittelbar zur Verfügung<br />

stehen.<br />

Die Methode public <strong>in</strong>t read(byte[] bytes) throws IOException füllt<br />

e<strong>in</strong> Datenfeld mit Bytes, die aus e<strong>in</strong>em Strom gelesen wurden und gibt die Anzahl<br />

Bytes zurück. Bei Bedarf (z.B. im Datenstrom s<strong>in</strong>d nicht genügend Bytes vorhanden)<br />

werden weniger Bytes gelesen, als das Datenfeld aufnehmen kann.<br />

„public <strong>in</strong>t read(byte[] bytes, <strong>in</strong>t offset, <strong>in</strong>t length)“ füllt e<strong>in</strong><br />

Datenfeld ab Position „offset“ mit bis zu length Bytes aus dem Strom. Es wird<br />

entweder die Anzahl der gelesenen Bytes oder –1 für das Dateiende ausgegeben.<br />

Weitere nützliche Methoden<br />

185 Rückgabe „-1“ bedeutet zum Unterschied von C nicht, daß e<strong>in</strong> Fehler aufgetreten ist.


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public <strong>in</strong>t available throws IOException<br />

Allen „read“-Methoden ist geme<strong>in</strong>sam: Sie warten auf das Ende aller angeforderten<br />

E<strong>in</strong>gaben. Es kann dabei zu längeren Blockaden beim E<strong>in</strong>lesen von Daten kommen.<br />

Die Methode „available“ gibt die Anzahl Bytes zurück, die ohne Blockieren<br />

gelesen werden kann.<br />

public long skip(long n)<br />

Die „skip“-Methode benutzt „read“ zum Überspr<strong>in</strong>gen und blockiert deshalb unter<br />

den gleichen Bed<strong>in</strong>gungen wie „read“. Die gibt die Anzahl Bytes zurück, die sie<br />

übersprungen hat, oder „-1“, falls das Ende des Stroms erreicht wurde<br />

public boolean markSupported()<br />

Die Methode gibt „true“ zurück, falls der Sttrom Markierungen unterstützt.<br />

public synchronized void mark(<strong>in</strong>t readLimit)<br />

Die Methode markiert die aktuelle Position im Strom für e<strong>in</strong>e spätere Rückkehr.<br />

public synchronized void reset() throws IOException<br />

Mit dieser Methode kann der Strom auf die Markierung zurücksetzen.<br />

public void close throws IOException<br />

Diese Methode schließt die Verarbeitung von e<strong>in</strong>em Strom. Die meisten Ströme<br />

werden automatisch bei der Garbage Collection geschlossen.<br />

7.1.2 OutputStream<br />

Aufgabenbeschreibung<br />

Der Ausgabestrom ist e<strong>in</strong> Empfänger von Daten. Man f<strong>in</strong>det Ausgabeströme fast nur<br />

<strong>in</strong> Verb<strong>in</strong>dung mit E<strong>in</strong>gabeströmen. Die Aufgabe der Klasse OutputStream ist die<br />

Repräsentation von Klassen zur Festlegung der Datensenke. Das kann e<strong>in</strong> „Array<br />

von Bytes“, e<strong>in</strong>e Datei oder e<strong>in</strong>e „Pipe“ se<strong>in</strong>.<br />

Klasse Funktion Argumente für den Konstruktur<br />

Nutzungsmöglichkeit<br />

ByteArrayOutputStream Kreiert e<strong>in</strong>en Arbeits-speicher- Optional: zu <strong>in</strong>itialisierende<br />

Puffer. Alle vom Strom Puffergröße<br />

gesendeten Daten werden hier Zum Bestimmen des Datenziels.<br />

plaziert.<br />

Verbunden mit e<strong>in</strong>em<br />

FilterOutputStream-Objekt kann<br />

daraus e<strong>in</strong> nützliches Interface<br />

gestaltet werden.<br />

FileOutputStream Zum Schreiben e<strong>in</strong>er Datei E<strong>in</strong>e Zeichenkette, die den<br />

Namen der Datei repräsentiert ,<br />

bzw. e<strong>in</strong> File- oder<br />

FileDescriptor-Objekt.<br />

Zum Bestimmen e<strong>in</strong>es<br />

Datenziels. Verbunden mit e<strong>in</strong>em<br />

FileOutputStream-Objekt kann<br />

PipedOutputStream Information zum Schreiben ist<br />

daraus e<strong>in</strong> nützliches Interface<br />

gestaltet werden.<br />

PipedInputStream<br />

E<strong>in</strong>gabe für den assoziierten Zum Bestimmen des datenziels<br />

PipedInputStream<br />

für „Multuthread<strong>in</strong>g“. Verbunden<br />

mit e<strong>in</strong>em FilterOutputStream-<br />

Objekt kann daraus e<strong>in</strong><br />

nützliches<br />

werden.<br />

Interface gestaltet<br />

247


Abb.: Ausgabestrom-Typen<br />

Die „write“-Methoden<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public abstract void write(<strong>in</strong>t b) throws IOException<br />

Die Methode schreibt e<strong>in</strong> e<strong>in</strong>zelnes Byte <strong>in</strong> den Ausgabestrom.<br />

public void write(byte[] bytes) throws IOException<br />

Die Methode schreibt den Inhalt des Datenfelds bytes <strong>in</strong> den Ausgabestrom.<br />

public void write(byte[] bytes, <strong>in</strong>t offset, <strong>in</strong>t length)<br />

Die Methode schreibt „length“ Bytes ab Position „offset“ aus dem Datenfeld<br />

bytes.<br />

public void flush() throws IOException<br />

Diese Methode leert e<strong>in</strong>en Ausgabestrom<br />

public void close() throws IOException<br />

Auch Ausgabeströme sollten am Ende e<strong>in</strong>er Verarbeitung geschlossen werden.<br />

7.2 Gefilterte Ströme<br />

Die Klassen FilterInputStream und FilterOutputStream zum Verknüpfen<br />

von Strömen<br />

Diese Klassen ermöglichen das Verknüpfen von Strömen, ke<strong>in</strong>e neuen Methoden.<br />

Der große Vorteil liegt <strong>in</strong> der Verb<strong>in</strong>dung mit e<strong>in</strong>em anderen Strom. Die<br />

Konstruktoren für den FilterInputStream und den FilterOutputStream<br />

haben deshalb InputStream- und OutputStream-Objekte als Parameter:<br />

public FilterInputStream(InpuStream e<strong>in</strong>)<br />

public FilterOutpuStream(OutputStream aus)<br />

Nützliche Subklassen von FilterInputStream s<strong>in</strong>d:<br />

Klasse Funktion Konstruktor-Argumente<br />

Nutzungsmöglichkeit<br />

DataInputStream Ermöglicht das E<strong>in</strong>lesen von InputStream<br />

primitiven Typen<br />

Enthält e<strong>in</strong> Interface für das<br />

lesen primitiver Typen<br />

BufferedInputStream Gepuffertes E<strong>in</strong>lesen InputStream mit optionale<br />

L<strong>in</strong>eNumberInputStream Verfolgt die zeilennummer im<br />

Angabe der Puffergröße<br />

InputStream<br />

E<strong>in</strong>gabestrom. Die Methode Fügt e<strong>in</strong>e Zeilennummerierung<br />

getL<strong>in</strong>eNumber() und h<strong>in</strong>zu<br />

setL<strong>in</strong>eNumber(<strong>in</strong>t)<br />

verwendet werden<br />

können<br />

PushBackInputStream Hat e<strong>in</strong>en Byte großen InputStream<br />

„Pushback“-Puffer, das letzte Braucht der <strong>Java</strong>-Compiler<br />

gelesene Zeichen kann <strong>in</strong> den<br />

strom zurückgelegt werden.<br />

Abb.: „FilterInputStream“-Typen<br />

248


Nützliche Subklassen von FilterOutputStream s<strong>in</strong>d:<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Klasse Funktion Konstruktor-Argumente<br />

Nutzungsmöglichkeit<br />

DataOutputStream Ausgabe primitiver Typen OutputStream<br />

Erlaubt das Schreiben primitiver<br />

Typen<br />

Pr<strong>in</strong>tStream Produziert formatierte Ausgabe. OutputStream<br />

BufferedOutputStream Gepufferte Ausgabe, der Puffer<br />

kann mit flush() geleert werden<br />

Abb.: „FilterOutputStream“-Typen<br />

Gepufferte Ströme<br />

249<br />

Formatierte Ausgabe<br />

OutputStream<br />

Gepufferte Ausgabe<br />

Gepufferte Ströme werden mit der Klasse BufferedInputStream für die E<strong>in</strong>gabe und<br />

BufferedOutputStream für die Ausgabe realisiert:<br />

public BufferedInputStream(InputStream e<strong>in</strong>)<br />

public BufferedInputStream(InputStream e<strong>in</strong>, <strong>in</strong>t puffergroesse)<br />

public BufferedOutputStream(OutputStream aus)<br />

public BufferedOutputStream(OutputStream aus, <strong>in</strong>t puffergroesse)<br />

Die Klasse BufferedInputStream implementiert die vollen Fähigkeiten der<br />

InputStream-Methoden, besitzt aber zusätzlich e<strong>in</strong>en gepufferten Byte-Array<br />

(Cache für weitere Leseoperationen).<br />

Die Klasse BufferedOutputStream implementiert die vollen Fähigkeiten der<br />

OutputStream-Methoden, besitzt aber zusätzlich e<strong>in</strong>en gepufferten Byte-Array.<br />

Die BufferedInputStream-Klasse versucht mit e<strong>in</strong>em e<strong>in</strong>zigen read-Aufruf soviel<br />

Daten wie möglich <strong>in</strong> ihre Puffer e<strong>in</strong>zulesen. Die BufferedOutputStream-Klasse<br />

ruft nur dann die write-Methode auf, wenn ihr Puffer voll ist oder wenn flush<br />

aufgerufen wird.<br />

Datenströme<br />

Die Filter DataInputStream und DataOutputStream s<strong>in</strong>d nützliche Filter des<br />

java.io-Pakets. Sie ermöglichen Schreiben und Lesen primitiver Typen <strong>in</strong> <strong>Java</strong> auf<br />

masch<strong>in</strong>enunabhängige Weise.<br />

DataInputStream implementiert e<strong>in</strong>e DataInput-Schnittstelle. Diese Schnittstelle<br />

def<strong>in</strong>iert Methoden zum Lesen von primitiven Datentypen <strong>in</strong> <strong>Java</strong> (sowie noch e<strong>in</strong><br />

paar weitere Methoden).<br />

DataOutputStream implementiert e<strong>in</strong>e DataOutput-Schnittstelle mit Ausgabe-<br />

Methoden, die den E<strong>in</strong>gabe-Methoden der DataInput-Schnittstelle entsprechen.<br />

Die Konstruktoren zu den DataInputStream- und DataOutputStream-Klassen<br />

s<strong>in</strong>d Stromfilter-Konstruktoren, die den zu filternden Strom als Parameter<br />

verwenden:<br />

public DataInputStream (InputStream e<strong>in</strong>)<br />

public DataOutputStream(OutputStream aus)<br />

Die Schnittstelle DataInput. Sie enthält Methoden zum Lesen primitiver Typen:


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public boolean readBoolean() throws IOException<br />

public byte readByte() throws IOException<br />

public byte readUnsignedByte() throws IOException EOFException<br />

public byte readChar() throws IOException<br />

public byte readShort() throws IOException<br />

public byte readUnsignedShort() throws IOException<br />

public <strong>in</strong>t readInt() throws IOException<br />

public long readLong() throws IOException<br />

public float readFloat() throws IOException<br />

public double readDouble() throws IOException<br />

public Str<strong>in</strong>g readUTF() throws IOException 186<br />

Ausgeworfene Ausnahmen s<strong>in</strong>d vom Typ IOException oder EOFException.<br />

EOFException wird ausgeworfen, wenn das Ende des Stroms erreicht wird. Die<br />

Ausnahme läßt sich überall e<strong>in</strong>setzen, wo bisher auf „-1“ überprüft wurde.<br />

Zum Lesen e<strong>in</strong>er durch Zeilenumschaltung (\r, \n) begrenzten Zeile aus e<strong>in</strong>er<br />

Textdateigibt es die Methode: public Str<strong>in</strong>g readL<strong>in</strong>e() throws<br />

IOException. „\r, \n, \r\n“ werden entfernt, bevor die Zeile als Zeichenkette<br />

wiedergegeben wird.<br />

Bsp.: E<strong>in</strong>lesen von der Standarde<strong>in</strong>gabe und Ausgabe<br />

Mit der Methode public <strong>in</strong>t skipBytes(<strong>in</strong>t anzahlBytes) wird e<strong>in</strong>e Anzahl<br />

Bytes übersprungen.<br />

Die Schnittstelle DataOutput. Duch diese Schnittstelle s<strong>in</strong>d folgende Methoden zur<br />

Ausgabe primitiver Typen def<strong>in</strong>iert:<br />

public void writeBoolean(boolean b) throws IOException<br />

public void writeByte(<strong>in</strong>t b) throws IOException<br />

public void writeChar(<strong>in</strong>t c) throws IOException<br />

public void writeShort(<strong>in</strong>t c) throws IOException<br />

public void writeInt(<strong>in</strong>t i) throws IOException<br />

public void writeFloat(float f) throws IOException<br />

public void writeDouble(double d) throws IOException<br />

public void writeUTF(Str<strong>in</strong>g s) throws IOException<br />

Mit den Methoden<br />

public void writeBytes(Str<strong>in</strong>g s) throws IOException<br />

public void writeChars(Str<strong>in</strong>g s) throws IOException<br />

kann e<strong>in</strong>e Zeichenkette als e<strong>in</strong>e Reihe von Bytes oder Zeichen abgelegt werden.<br />

Die Pr<strong>in</strong>tStream-Klasse<br />

Der „System.out“-Strom mit den Methoden „System.out.pr<strong>in</strong>t“ bzw.<br />

„System.out.pr<strong>in</strong>tln“ ist e<strong>in</strong>e Instanz von Pr<strong>in</strong>tStream. „System.<strong>in</strong>“ ist e<strong>in</strong><br />

InputStream.<br />

Erstellen e<strong>in</strong>es „Pr<strong>in</strong>tStream“-Objekts. Das Pr<strong>in</strong>tStream-Objekt muß <strong>in</strong> e<strong>in</strong>en<br />

existierenden Ausgabestrom angehangen werden. Über e<strong>in</strong>en optionalen Parameter<br />

kann automatisch die Methode flush() aufgerufen werden:<br />

public Pr<strong>in</strong>tStream(OutputStream aus)<br />

186 UTF (Unicode Transmission Format) ist e<strong>in</strong> spezielles Format zum Kodieren von 16-Bit-Unicode-Werten<br />

250


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public Pr<strong>in</strong>tStream(OutputStream aus, boolean autoFlush)<br />

Methode für die Ausgabe von Objekten.<br />

public void flush()<br />

public void close()<br />

public abstract void write(<strong>in</strong>t b)<br />

public void pr<strong>in</strong>t(Object o)<br />

public void pr<strong>in</strong>t(Str<strong>in</strong>g s)<br />

public void pr<strong>in</strong>t(char c)<br />

public void pr<strong>in</strong>t(char[] puffer)<br />

public void pr<strong>in</strong>t(char c)<br />

public void pr<strong>in</strong>t(<strong>in</strong>t i)<br />

public void pr<strong>in</strong>t(float f)<br />

public void pr<strong>in</strong>t(double d)<br />

public void pr<strong>in</strong>tln(Object f)<br />

public void pr<strong>in</strong>tln(Str<strong>in</strong>g s)<br />

public void pr<strong>in</strong>tln(char c)<br />

public void pr<strong>in</strong>tln(char[] puffer)<br />

public void pr<strong>in</strong>tln(char c)<br />

public void pr<strong>in</strong>tln(<strong>in</strong>t i)<br />

public void pr<strong>in</strong>tln(float f)<br />

public void pr<strong>in</strong>tln(double d)<br />

public void pr<strong>in</strong>tln()<br />

251


7.3 Die Klasse File<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

E<strong>in</strong> File-Objekt kann sich auf e<strong>in</strong>e Datei oder e<strong>in</strong> Verzeichnis beziehen und läßt<br />

sich auf verschiedene Arten erstellen.<br />

public File(Str<strong>in</strong>g pfadname)<br />

erstellt e<strong>in</strong>e File-Instanz, die <strong>in</strong> pfadname angegeben wurde.<br />

public File(Str<strong>in</strong>g pfadname, Str<strong>in</strong>g date<strong>in</strong>ame)<br />

erstellt e<strong>in</strong>e File-Instanz, die sich aus dem <strong>in</strong> date<strong>in</strong>ame angegebenen Date<strong>in</strong>amen und dem <strong>in</strong><br />

pfadnamen aungegebenen Pfad zusammensetzt.<br />

public File(File verzeichnis, Str<strong>in</strong>g date<strong>in</strong>ame)<br />

erstellt e<strong>in</strong>e File-Instanz, die sich aus dem <strong>in</strong> date<strong>in</strong>ame angegebenen Date<strong>in</strong>amen und dem <strong>in</strong><br />

verzeichnis angegebenen Verzeichnis zusammensetzt.<br />

Die Klasse File umfaßt Methoden zum Berabeiten von Dateien bzw. Verzeichnissen.<br />

Die Methoden<br />

public boolean isFile()<br />

public boolean isDirectory<br />

überprüfen, ob e<strong>in</strong>e Datei oder e<strong>in</strong> Verzeichnis vorliegt. Mit<br />

public boolean canRead()<br />

public boolean canWrite()<br />

wird Lese- bzw. Schreiberlaubnis überprüft. Die Methode<br />

public long lastModified()<br />

zeigt an, wann die Datei bzw. das Verzeichnis geändert wurde. Mit<br />

public boolean exists<br />

wird die physikalische Existenz e<strong>in</strong>er Datei oder e<strong>in</strong>es Verzeichnisses überprüft.<br />

Über<br />

public Str<strong>in</strong>g getName()<br />

wird der name e<strong>in</strong>er Datei bzw. e<strong>in</strong>es Verzeichnisses ermittelt.<br />

7.4 Die RandomAccessFile-Klasse<br />

Für den Zugriff auf Random-Access-Dateien stellt das Paket java.io die Klasse<br />

RandomAccessFile zur Verfügung. Es kann nur auf Dateien zugegriffen werden,<br />

auch das durch die „Streams“ realisierte Filter-Konzept gibt es <strong>in</strong> Random-Access-<br />

Dateien nicht.<br />

Öffnen, Neuanlegen und Schließen. Das Öffnen von Random-Access-Dateien erfolgt<br />

mit den Konstruktoren:<br />

public RandomAccessFile(File datei, Str<strong>in</strong>g mode) throws<br />

IOException<br />

Bei der Übergabe des File-Objekts wird die durch dieses Objekt spezifizierte Datei<br />

geöffnet.<br />

252


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

public RandomAccessFile(Str<strong>in</strong>g name, Str<strong>in</strong>g mode) throws<br />

IOException<br />

Bei der Übergabe des Str<strong>in</strong>g-Parametres „name“ wird die Datei mit diesem Namen<br />

geöffnet. Der zweite Parameter mode bestimmt die Art des Zugriffs:<br />

- „r“: Öffnen nur zum Lesen<br />

- „rw“: Öffnen zum Schreiben und Lesen. E<strong>in</strong> re<strong>in</strong>er Schreibmodus wird nicht<br />

unterstützt.<br />

Es gibt <strong>in</strong> der Klasse RandomAccessFile ke<strong>in</strong>e explizite Differenzierung zwischen<br />

Öffnen der Datei und Neuanlegen. Implizit gilt: E<strong>in</strong>e Datei wird neu angelegt, wenn<br />

beim Öffnen im Modus „w“ nicht vorhanden ist. Existiert die Datei bereits, wird sie<br />

unverändert geöffnet, und es gibt ke<strong>in</strong>e Möglichkeit, ihren Inhalt zu löschen oder die<br />

Dateilänge auf e<strong>in</strong>en bestimmten Wert zusetzen.<br />

Das Schliessen erfolgt durch Aufruf der parameterlosen Methode close.<br />

Positionieren des Dateizeigers. Jeder Schreib- und Lesezugriff erfolgt an der<br />

Position, die durch den aktuellen Inhalt des Satzzeigers bestimmt wird und<br />

positioniert den Zeiger um die Anzahl gelesener bzw. geschriebener Bytes weiter.<br />

Die Klasse RandomAccessFile stellt e<strong>in</strong>e Reihe von Methoden zum Zugriff auf den<br />

Satzzeiger zur Verfügung.<br />

Die Methode seek. Die RandomAccessFile-Klasse besitzt alle Methoden, die <strong>in</strong><br />

den Schnittstellen DataInput und DataOutput verfügbar s<strong>in</strong>d. Mit public void<br />

seek(long dateiPosition) throws IOException kann man an jede<br />

beliebige Position der Datei spr<strong>in</strong>gen. Mit der Methode public long<br />

getFilePo<strong>in</strong>ter() throws IOException kann die derzeitige Dateiposition 187<br />

bestimmt werden.<br />

7.5 Spezielle nützliche Ströme<br />

Die L<strong>in</strong>eInputStream-Klasse<br />

Die SequenceInputStream-Klasse<br />

Die PushBackInputStream-Klasse<br />

Die StreamTokenizer-Klasse. Sie zerlegt e<strong>in</strong>en Zeichenstrom <strong>in</strong> e<strong>in</strong>en<br />

Tokenstrom188 . Die Klasse StreamTokenizer ist nicht von den Klassen InputStream<br />

und OutputStream abgeleitet. Da die Klasse mit InputStream-Objekten arbeitet,<br />

gehört sie zum IO-Bereich. Die Klasse StreamTokenizer zerlegt e<strong>in</strong>en InputStream <strong>in</strong><br />

e<strong>in</strong>e Folge von Token (Textbereiche, die durch beliebige Zeichen eigener Wahl<br />

abgegrenzt s<strong>in</strong>d). Falls e<strong>in</strong> Token bspw. e<strong>in</strong>em Wort entsprechen soll, dann ist es<br />

begrenzt durch leerzeichen und durch Interpunktionszeichen.<br />

187 Der Dateipositionswert <strong>in</strong> den Methoden seek und getFilePo<strong>in</strong>ter ist die Anzahl der Beytes vom<br />

anfang bis zum ende der Datei.<br />

188 Token: e<strong>in</strong>zelne Wörter bzw. Satzzeichen<br />

253


7.6 <strong>Java</strong> 1.1 IO-Ströme<br />

7.6.1 Grundlagen<br />

<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Bis zur Version 1.0 des JDK gab es nur Byte-Streams <strong>in</strong> <strong>Java</strong>. Das ergab<br />

Schwierigkeiten bei der Umwandlung zwischen Bytes und 16 Bit langen Unicode-<br />

Zeichen, die <strong>in</strong>nerhalb von <strong>Java</strong> benutzt werden. Im JDK 1.1. wurden daher<br />

„Character“-Streams auf der Basis von 16 Bit langen Unicode-Zeichen e<strong>in</strong>geführt.<br />

Die Kompatibilität wurde durch Brückenklassen gewährleistet, die „Character“-<br />

Streams <strong>in</strong> „Byte“-Streams überführen (und umgekehrt).<br />

Quellen und Senken: „<strong>Java</strong> 1.0“-Klassen Korrespondierende Klassen <strong>in</strong> <strong>Java</strong> 1.1<br />

InputStream Reader<br />

Konverter: InputStreamReader<br />

OutputStream Writer<br />

Konverter: OutputStreamWriter<br />

FileInputStream FileReader<br />

FileOutputStream FileWriter<br />

Str<strong>in</strong>gBufferInputStream Str<strong>in</strong>gReader<br />

Str<strong>in</strong>gWriter<br />

ByteArrayInputStream CharArrayReader<br />

ByteArrayOutputStream CharArrayWriter<br />

PipedInputStream PipedReader<br />

PipedOutputStream PipedWriter<br />

Abb.<br />

In Filterklassen kann nur e<strong>in</strong>e etwas gröbere Zuordnung von Klassen aus <strong>Java</strong> 1.0<br />

zu <strong>Java</strong> 1.1 angegeben werden. So ist „BufferedOutputStream“ e<strong>in</strong>e Subklasse<br />

von FilterOutputStream, BufferedWriter ist dagegen ke<strong>in</strong>e Subklasse von<br />

FilterWriter.<br />

Filter: Klassen <strong>in</strong> <strong>Java</strong> 1.0 Korrespondierende Klassen <strong>in</strong> <strong>Java</strong> 1.1<br />

FilterInputStream FilterReader<br />

FilterOutputStream FilterWriter (abstrakte Klasse ohne Subklassen)<br />

BufferedInputStream BufferedReader (mit readL<strong>in</strong>e)<br />

BufferedOutputStream BufferedWriter<br />

DataInputStream DataInputStream, bei readL<strong>in</strong>e() BufferedReader<br />

verwenden<br />

Pr<strong>in</strong>tStream Pr<strong>in</strong>tWriter<br />

L<strong>in</strong>eNumberInputStream L<strong>in</strong>eNumberReader<br />

StreamTokenizer StreamTokenizer<br />

PushBackInputStream PushBackReader<br />

Abb.<br />

E<strong>in</strong>ige Klassen bleiben von der Umstellung unberührt: DataOutputStream, File,<br />

RandomAccessFile, SequenceInputStream.<br />

254


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

7.6.2 Die abstrakte Klassen Reader und ihre Ableitungen<br />

Basis aller sequentiellen E<strong>in</strong>gaben ist die abstrakte Klasse Reader, die e<strong>in</strong>e<br />

Schnittstelle für streambasierte E<strong>in</strong>gaben zur Verfügung stellt:<br />

public abstract class java.io.Reader<br />

{<br />

public Reader();<br />

publicc void close();<br />

// schliesst den E<strong>in</strong>gabestrom<br />

public void mark(<strong>in</strong>t readAheadlimit);<br />

// markiert e<strong>in</strong>e bestimmte Position <strong>in</strong>nerhalb e<strong>in</strong>es E<strong>in</strong>gabestroms<br />

public boolean markSupported();<br />

// überprüft, ob Markieren unterstützt wird<br />

public <strong>in</strong>t read()<br />

// liest das nächste Zeichen aus dem E<strong>in</strong>gabestrom und liefert es als<br />

// „<strong>in</strong>t“. Der Rückgabewert –1 kennzeichnet das Ende des E<strong>in</strong>gabestroms<br />

public <strong>in</strong>t read(char cbuf[]);<br />

// übernimmt e<strong>in</strong>e Reihe von Zeichen <strong>in</strong> den als Parameter angegebenen<br />

// Array<br />

public <strong>in</strong>t read(char cbuf[], <strong>in</strong>t off, <strong>in</strong>t len);<br />

// übernimmt e<strong>in</strong>e Reihe von zeichen <strong>in</strong> e<strong>in</strong>en Bereich des Puffers, der<br />

// durch Versatz (Offset) und die gewünschte Länge gekennzeichnet ist<br />

public long skip(long n);<br />

// überliest Zeichen im E<strong>in</strong>gabestrom<br />

public boolean ready()<br />

// liefert True, falls der nächste Aufruf von read erfolgen kann, ohne<br />

// daß die E<strong>in</strong>gabe beendet ist<br />

public void reset();<br />

// setzt den „Lesezeiger an die markierte Stelle zurück<br />

}<br />

Von der abstrakten Basisklasse Reader können ke<strong>in</strong>e Instanzen abgeleitet werden.<br />

Es gibt e<strong>in</strong>e Reihe aus „Reader“ abgeleitete Klassen, die die Verb<strong>in</strong>dung zur<br />

konkreten E<strong>in</strong>gabe bzw. zum konkreten E<strong>in</strong>gabegerät herstellen.<br />

Klasse Bedeutung<br />

InputStreamReader Abstrakte Klasse für alle Reader, die e<strong>in</strong>en Byte-<br />

Strom <strong>in</strong> e<strong>in</strong>en Character-Strom umwandeln<br />

FileReader Konkrete Ableitung von InputStreamReader zum<br />

E<strong>in</strong>lesen e<strong>in</strong>er Datei<br />

PushBackReader E<strong>in</strong>gabefilter mit der Möglichkeit zur Rückgabe<br />

von Zeichen<br />

BufferedReader Reader zur E<strong>in</strong>gabepufferung und zum Lesen<br />

kompletter Zeilen<br />

L<strong>in</strong>eNumberReader Ableitung von BufferedReader mit der Fähigkeit<br />

zum Zählen von Zeilen<br />

Str<strong>in</strong>gReader Reader zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />

Str<strong>in</strong>g<br />

CharArrayReader Reader zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />

Zeichen-Array<br />

PipedReader Reader zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />

PipedWriter<br />

Abb.: Von Reader abgeleitete Klassen<br />

InputStreamReader<br />

Die abstrakte Basisklasse konvertiert Byte- <strong>in</strong> Character-Streams.<br />

255


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

FileReader<br />

Sie ermöglicht die E<strong>in</strong>gabe e<strong>in</strong>er Datei.<br />

Konstruktoren. Mit ihnen ermöglicht FileReader das Öffnen von Dateien:<br />

public FileReader(Str<strong>in</strong>g dateiName) throws FileNotFoundException;<br />

Bei Übergabe der Zeichenkette dateiName wird die Datei mit dem angegebenen<br />

Namen zum Lesen geöffnet. Falls sie nicht vorhanden ist, kommt es zur Ausnahme<br />

des Typs FileNotFoundException<br />

public FileReader(File datei) throws FileNotFoundException;<br />

erwartet e<strong>in</strong> File-Objekt zur Spezifikation e<strong>in</strong>er zu öffnenden Datei.<br />

public FileReader(FileDescriptor fd);<br />

erwartet e<strong>in</strong> File-Deskriptor-Objekt, das e<strong>in</strong>e bereits geöffnete Datei angibt.<br />

Str<strong>in</strong>gReader<br />

Diese Klasse erlaubt das Lesen von Zeichen aus e<strong>in</strong>em Str<strong>in</strong>g.<br />

CharArrayReader<br />

Diese Klasse erlaubt das Lesen von Zeichen aus e<strong>in</strong>en „Zeichen-Array“<br />

BufferedReader<br />

Diese Klasse dient zur Pufferung von E<strong>in</strong>gaben. BufferedReader implementiert die<br />

vollen Fähigkeiten der Methoden von Reader. Diese Klasse verwendet dazu<br />

gepufferte Zeichen-Arrays.<br />

Konstruktoren: public BufferedReader(Reader e<strong>in</strong>)<br />

public BufferedReader(Reader e<strong>in</strong>, <strong>in</strong>t gr)<br />

Der erste Parameter ist e<strong>in</strong> Reader-Objekt, auf das e<strong>in</strong> BufferedReader<br />

aufgesetzt werden soll. Der optionale Parameter gr gibt die Größe des <strong>in</strong>ternen<br />

Puffer an. Fehlt er, so wird e<strong>in</strong>e für die meisten Situationen angemessene<br />

Standarde<strong>in</strong>stellung verwendet.<br />

Zeilenweises Lesen: public Str<strong>in</strong>g readL<strong>in</strong>e throws IOException.<br />

Rückgabewert ist e<strong>in</strong> Str<strong>in</strong>g mit dem Zeichen<strong>in</strong>halt (ohne Begrenzungszeichen) oder<br />

„null“, falls das Ende von „Stream“ erreicht wurde.<br />

L<strong>in</strong>eNumberReader<br />

Diese Klasse ist e<strong>in</strong>e Ableitung von BufferedReader, die zusätzlich noch die<br />

Anzahl der E<strong>in</strong>gabezeichen beim E<strong>in</strong>lesen zählen kann. Mit „public <strong>in</strong>t<br />

getL<strong>in</strong>eNumber()“ wird der aktuelle Stand des Zeilenzählers abgefragt. Mit<br />

public void setL<strong>in</strong>eNumber(<strong>in</strong>t L<strong>in</strong>eNumber) kann der aktuelle Stand des<br />

Zeilenzählers verändert werden.<br />

256


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

7.6.3 Die abstrakte Klasse Writer und ihre Ableitungen<br />

Basis aller sequentiellen E<strong>in</strong>gaben ist die Klasse Writer, die e<strong>in</strong>e Schnittstelle für<br />

„stream“-basierte Ausgaben zur Verügung stellt:<br />

public abstract class java.io.Writer<br />

{<br />

protected Writer();<br />

// Oeffnen und Vorbereiten des Ausgabestroms<br />

public void close();<br />

// Schliessen des Ausgabestroms<br />

public void flush()<br />

// Leeren der Ausgabe von e<strong>in</strong>em gepufferten Cache<br />

public void write(<strong>in</strong>t c);<br />

// Grundform mit e<strong>in</strong>em e<strong>in</strong>zigen Ausgabeparameter vom typ <strong>in</strong>t,<br />

// der als Byte <strong>in</strong> den Ausgabestrom geschrieben wird<br />

public void write(char e<strong>in</strong>Puffer[]);<br />

// Varianten von write, die e<strong>in</strong> Array von Bytes oder e<strong>in</strong> Str<strong>in</strong>g-Objekt<br />

// erwarten und dieses durch Aufruf von write() ausgeben<br />

abstact public void write(char e<strong>in</strong>Puffer[], <strong>in</strong>t off, <strong>in</strong>t len);<br />

}<br />

public void write(Str<strong>in</strong>g str);<br />

public void write(Str<strong>in</strong>g str, <strong>in</strong>t off, <strong>in</strong>t len);<br />

Von der abstrakten Basisklasse Writer können ke<strong>in</strong>e Instanzen abgeleitet werden.<br />

Es gibt e<strong>in</strong>e Reihe aus „Writer“ abgeleitete Klassen, die die Verb<strong>in</strong>dung zur<br />

konkreten Ausgabe(gerät) herstellen:<br />

Klasse Bedeutung<br />

OutputStreamWriter Abstrakte Basisklasse für alle Writer, die e<strong>in</strong>en Character-Stream <strong>in</strong><br />

e<strong>in</strong>en Byte-Stream umwandeln<br />

FileWriter Konkrete Ableitung von OutputStreamWriter zur Ausgabe e<strong>in</strong>er Datei<br />

FilterWriter Abstrakte Basisklasse für die Konstruktion von Ausgabefiltern<br />

Pr<strong>in</strong>tWriter Ausgabe aller Basistypen im Textformat<br />

BufferedWriter Writer mit Ausgabepufferung<br />

Str<strong>in</strong>gWriter Writer zur Ausgabe <strong>in</strong> e<strong>in</strong>em Str<strong>in</strong>g<br />

CharArrayWriter Writer zur Ausgabe im Zeichen-Array<br />

PipedWriter Writer zur Ausgabe <strong>in</strong> e<strong>in</strong>em PipedReader<br />

Abb.: Aus Writer abgeleitete Klassen<br />

Von den abgeleiteten Klassen wird erwartet: Überlagerung der Methoden flush(),<br />

close() und write(char e<strong>in</strong>Puffer[], <strong>in</strong>t offset, <strong>in</strong>t laenge).<br />

Zun Schachteln von Ausgabe-Streams gibt es die aus Writer abgeleiteten Klassen:<br />

BufferedWriter, Pr<strong>in</strong>tWriter und FilterWriter. Falls die "write"-Methode<br />

e<strong>in</strong>es derart geschachtelten "Writer" aufgerufen wird, gibt sie Daten nicht mehr<br />

direkt an den <strong>in</strong>ternen "Writer", sondern führt Filterfunktionen aus.<br />

OutputStreamWriter<br />

Diese Klasse übernimmt e<strong>in</strong>e Konvertzierung zwischen Character- und Byte-<br />

Streams.<br />

FileWriter<br />

257


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

ermöglicht die Ausgabe <strong>in</strong> e<strong>in</strong>e Datei. Sie implementiert die abstrakten<br />

Eigenschaften von Writer. Die Klasse FileWriter bietet 4 Konstruktoren für das<br />

Öffnen von Dateien an:<br />

public FileWriter(Str<strong>in</strong>g dateiName) throws IOException<br />

Falls dateiName e<strong>in</strong>e bereits vorhandene Datei bezeichnet, wird sie geöffnet und ihr bisheriger Inhalt<br />

gelöscht, anderenfalls wird e<strong>in</strong>e neue Datei mit diesem Namen angelegt. Sukzessive Aufrufe von write<br />

schreiben dann <strong>in</strong> diese Datei.<br />

public FileWriter(Str<strong>in</strong>g dateiName, boolean append) throws IOException<br />

Wird der Parameter append mit dem Wert true an den Konstruktor übergeben, dann werden die<br />

Ausgabezeichen an die Datei angehängt, falls sie bereits existiert.<br />

public FileWriter (File datei) throws IOException<br />

public FileWriter (FileDescriptor fd)<br />

Parameter ist hier e<strong>in</strong> File-Objekt bzw. e<strong>in</strong> FileDescriptor-Objekt<br />

Die Klasse Str<strong>in</strong>gWriter<br />

Sie besitzt zwei Konstruktoren:<br />

public Str<strong>in</strong>gWriter()<br />

bestimmt e<strong>in</strong>en Str<strong>in</strong>gWriter <strong>in</strong> der Standardgröße e<strong>in</strong>es Str<strong>in</strong>gBuffer-Objekts. Der <strong>in</strong>terne Puffer<br />

wächst automatisch, falls fortgesetzte Aufrufe von „write“ das eroderlich machen<br />

public Str<strong>in</strong>gWriter(<strong>in</strong>t <strong>in</strong>itialGroesse)<br />

Zugriffe: Die schreibenden Zugriffe auf die Puffer erfolgen mit den von Writer<br />

bekannten „write“-Methoden. Für den Zugriff auf den Inhalt des Puffers gibt es die<br />

Methoden public Str<strong>in</strong>gBuffer getBuffer() und public Str<strong>in</strong>g<br />

toStr<strong>in</strong>g().<br />

CharArrayWriter<br />

Sie schreibt Zeichen <strong>in</strong> e<strong>in</strong> Character-Array, das automatisch bei fortgesetzten<br />

Aufrufen von „write“ erweitert wird. Die Klasse besitzt zwei Konstruktoren:<br />

public CharArrayWriter()<br />

public CharArrayWriter(<strong>in</strong>t <strong>in</strong>itialGroesse)<br />

Zugriffe: Schreibende Zugriffe erfolgen mit den von „Writer“ bekannten „write“-<br />

Methoden. Für den Zugriff auf das Array gibt es die Methoden public Str<strong>in</strong>g<br />

toStr<strong>in</strong>g() und public char[] toCharArray(). Mit der Methode public<br />

void reset() wird der <strong>in</strong>terne Puffer geleert. Die Größe des Zeichen-Array wird<br />

über public <strong>in</strong>t size() ermittelt. Durch Aufruf von public void<br />

writeTo(Writer aus) throws IOException kann der Inhalt des Array an<br />

e<strong>in</strong>en anderen Writer übergeben werden und so mit e<strong>in</strong>em e<strong>in</strong>zigen<br />

Funktionsaufruf <strong>in</strong> e<strong>in</strong>e Datei geschrieben werden.<br />

BufferedWriter<br />

Die Klasse puffert „Stream“-Ausgaben über e<strong>in</strong>en <strong>in</strong>ternen Puffer, <strong>in</strong> dem die<br />

Ausgaben von write zwischengespeichert werden. Falls der Puffer gefüllt ist oder die<br />

Methode flush aufgerufen wird, werden alle gepufferten Ausgaben <strong>in</strong> den „Stream“<br />

geschrieben. Das Puffern der Ausgabe ist immer dann nützlich, wenn die Ausgabe <strong>in</strong><br />

e<strong>in</strong>e Datei geschreiben werden soll. BufferedWriter besitzt zwei Konstruktoren:<br />

public BufferdWriter(Writer aus)<br />

public BufferedWriter(Writer aus, <strong>in</strong>t groesse)<br />

In beiden Fällen wird e<strong>in</strong> existierender Writer übergeben, an den alle gepufferten<br />

Ausgaben weitergereicht werden. Ist die Größe des Puffers nicht explizit angegeben,<br />

legt BufferedWriter e<strong>in</strong>en Standardpuffer an.<br />

258


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

Die „write“-Methoden von BufferedWriter entsprechen denen der Klasse<br />

Writer. Zusätzlich gibt es e<strong>in</strong>e Methode newL<strong>in</strong>e mit der e<strong>in</strong>e Zeileumschaltung <strong>in</strong><br />

den Stream geschrieben werden kann.<br />

Pr<strong>in</strong>tWriter<br />

Diese Klasse stellt Ausgabemethoden für alle primitiven Datentypen und für<br />

Objektgruppen zur Verfügung.<br />

Konstruktoren.<br />

public Pr<strong>in</strong>tWriter(Writer aus)<br />

<strong>in</strong>stanziert e<strong>in</strong> Pr<strong>in</strong>tWriter-Objekt durch Übergabe e<strong>in</strong>es Writer-Objekts, auf das die Ausgabe<br />

umgelenkt werden soll.<br />

public Pr<strong>in</strong>tWriter(Writer aus, boolean autoflush)<br />

Mit dem Parameter autoflush wird angegeben, ob nach der Ausgabe „e<strong>in</strong>er Zeilenschaltung“<br />

automatisch die Methode flush() aufgerufen werden soll.<br />

Ausgabe primitiver Typen (und Objekttypen): Sie wird realisiert über e<strong>in</strong>e Reihe<br />

überladener Methoden mit dem Namen „pr<strong>in</strong>t“. Zusätzlich gibt es alle Methoden <strong>in</strong><br />

der Variante pr<strong>in</strong>tln, bei der automatisch an das Ende der Ausgabe e<strong>in</strong><br />

Zeilenvorschub (Zeilenumschaltung) angehängt wird. Pr<strong>in</strong>tln() existiert auch<br />

parameterlos zur Ausgabe e<strong>in</strong>er e<strong>in</strong>zelnen Zeilenumschaltung.<br />

public void pr<strong>in</strong>t(boolean b)<br />

public void pr<strong>in</strong>t(char z)<br />

public void pr<strong>in</strong>t(char s[])<br />

public void pr<strong>in</strong>t(double d)<br />

public void pr<strong>in</strong>t(float f)<br />

public void pr<strong>in</strong>t(<strong>in</strong>t i)<br />

public void pr<strong>in</strong>t(long l)<br />

public void pr<strong>in</strong>t(Object obj)<br />

public void pr<strong>in</strong>t(Str<strong>in</strong>g s)<br />

259


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

7.6.4 Demonstrationsprogramm zur E<strong>in</strong>-/ Ausgabe ab <strong>Java</strong> Version 1.1<br />

Das Demonstrationsprogramm soll folgende E<strong>in</strong>-/Ausgabe zeigen:<br />

1. Zeilenweises Lesen<br />

2. E<strong>in</strong>gabe vom Speicher<br />

3. Formatierte Speicher-E<strong>in</strong>gabe<br />

4. Zeilennummerierung und Dateiausgabe<br />

5. Speichern und Wiedergew<strong>in</strong>nen von Daten<br />

import java.io.*;<br />

public class E<strong>in</strong>AusDemo<br />

{<br />

public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />

{<br />

try<br />

{<br />

// 1. Zeilenweises Lesen<br />

BufferedReader e<strong>in</strong>1 = new BufferedReader(<br />

new FileReader(args[0]));<br />

Str<strong>in</strong>g s1, s2 = new Str<strong>in</strong>g();<br />

while ((s1 = e<strong>in</strong>1.readL<strong>in</strong>e()) != null)<br />

s2 += s1 + ’\n’;<br />

e<strong>in</strong>1.close();<br />

// Lesen Standarde<strong>in</strong>gabe<br />

BufferedReader std<strong>in</strong> = new BufferedReader(<br />

new InputStreamReader(System.<strong>in</strong>));<br />

System.out.pr<strong>in</strong>t("Gib e<strong>in</strong>e Zeile an: ");<br />

System.out.pr<strong>in</strong>tln(std<strong>in</strong>.readL<strong>in</strong>e());<br />

// 2. E<strong>in</strong>gabe vom Speicher<br />

Str<strong>in</strong>gReader e<strong>in</strong>2 = new Str<strong>in</strong>gReader(s2);<br />

<strong>in</strong>t zch;<br />

while ((zch=e<strong>in</strong>2.read()) != -1)<br />

System.out.pr<strong>in</strong>t((char) zch);<br />

// 3. Formatierte Speicher-e<strong>in</strong>gabe<br />

try<br />

{<br />

DataInputStream e<strong>in</strong>3 = new DataInputStream(<br />

new Str<strong>in</strong>gBufferInputStream(s2));<br />

while (true)<br />

System.out.pr<strong>in</strong>t((char) e<strong>in</strong>3.readByte());<br />

}<br />

catch(EOFException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Ende des Stroms");<br />

}<br />

// 4. Zeilennummerierung und Datei-Ausgabe<br />

try<br />

{<br />

L<strong>in</strong>eNumberReader zn = new L<strong>in</strong>eNumberReader(<br />

new Str<strong>in</strong>gReader(s2));<br />

// BufferedReader e<strong>in</strong>4 = new BufferedReader(zn);<br />

Pr<strong>in</strong>tWriter aus1 = new Pr<strong>in</strong>tWriter(<br />

new BufferedWriter(<br />

new FileWriter("E<strong>in</strong>AusDemo.aus")));<br />

while ((s1 = zn.readL<strong>in</strong>e()) != null)<br />

aus1.pr<strong>in</strong>tln("/* " + zn.getL<strong>in</strong>eNumber() + " */" + s1);<br />

// System.out.pr<strong>in</strong>tln("/* " + zn.getL<strong>in</strong>eNumber() + " */" + s1);<br />

aus1.close();<br />

}<br />

catch(EOFException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Ende des Stroms");<br />

}<br />

260


<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />

// 5. Speichern und Wiedergew<strong>in</strong>nen von Daten<br />

try<br />

{<br />

DataOutputStream aus2 = new DataOutputStream(<br />

new BufferedOutputStream(<br />

new FileOutputStream("Daten.txt")));<br />

aus2.writeDouble(3.14159);<br />

aus2.writeBytes("Das war Pi");<br />

aus2.close();<br />

DataInputStream e<strong>in</strong>5 = new DataInputStream(<br />

new BufferedInputStream(<br />

new FileInputStream("Daten.txt")));<br />

BufferedReader e<strong>in</strong>5br = new BufferedReader(<br />

new InputStreamReader(e<strong>in</strong>5));<br />

System.out.pr<strong>in</strong>tln(e<strong>in</strong>5.readDouble());<br />

System.out.pr<strong>in</strong>tln(e<strong>in</strong>5br.readL<strong>in</strong>e());<br />

}<br />

catch(EOFException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Ende des Stroms");<br />

}<br />

}<br />

catch(FileNotFoundException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("Datei nicht gefunden: " + args[1]);<br />

}<br />

catch(IOException e)<br />

{<br />

System.out.pr<strong>in</strong>tln("IO Exception");<br />

}<br />

}<br />

}<br />

8. Serialisierung<br />

Serialisierung 189 ist die Fähigkeit e<strong>in</strong> Objekt, das im Hauptspeicher der Anwendung<br />

existiert, <strong>in</strong> e<strong>in</strong> Format zu konvertieren, das es erlaubt, das Objekt <strong>in</strong> e<strong>in</strong>e Datei zu<br />

schreiben oder über e<strong>in</strong>e Netzwerkverb<strong>in</strong>dung zu transportieren. Auch der<br />

umgekehrte Weg gehört dazu: Rekonstruktion e<strong>in</strong>es <strong>in</strong> serialisierter Form<br />

vorliegenden Objekts <strong>in</strong> das <strong>in</strong>terne Format der laufenden <strong>Java</strong>-Masch<strong>in</strong>e.<br />

9. Netzwerkprogrammierung<br />

189 häufig auch mit dem Begriff Persistenz gleichgesetzt. Persistenz bezeichnet das dauerhafte Speichern von<br />

Daten auf e<strong>in</strong>em externen Datenträger, so daß sie auch nach dem Beenden des Programms erhalten bleiben.<br />

261

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!