Programmieren in Java
Programmieren in Java
Programmieren in Java
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