Programmieren in Java - HostFiXX.de
Programmieren in Java - HostFiXX.de
Programmieren in Java - HostFiXX.de
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<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 2004/2005<br />
1
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Inhaltsverzeichnis<br />
0. ÜBERSICHT.....................................................................................................................................11<br />
0.1 Ziel <strong>de</strong>r Vorlesung "<strong>Programmieren</strong>" ...................................................................................................... 11<br />
0.2 <strong>Java</strong>-Masch<strong>in</strong>e und Programmiersystem ................................................................................................. 11<br />
0.3 Der erste Versuch........................................................................................................................................ 13<br />
0.3.1 Das erste Programm............................................................................................................................... 13<br />
0.3.2 Bestandteile e<strong>in</strong>es Programms ............................................................................................................... 19<br />
1. EINFÜHRUNG IN DIE JAVA-PROGRAMMIERUNG......................................................................21<br />
1.1 Übersicht zur Entwicklung <strong>de</strong>r Programmiersprache <strong>Java</strong> ................................................................... 21<br />
1.2 Was ist <strong>Java</strong>?............................................................................................................................................... 22<br />
1.3 E<strong>in</strong>stieg <strong>in</strong> die <strong>Java</strong>-Programmierung ...................................................................................................... 25<br />
1.3.1 Die Software für die <strong>Java</strong>-Programmierung .......................................................................................... 25<br />
1.3.2 Applets und Anwendungen.................................................................................................................... 27<br />
1.3.2.1 Entwicklung von <strong>Java</strong>-Anwendungen ............................................................................................ 27<br />
1.3.2.2 Entwicklung von <strong>Java</strong>-Applets ....................................................................................................... 34<br />
1.3.3 Programmablaufpläne und Strukturierte Programmierung .................................................................... 43<br />
1.3.3.1 Darstellung von Algorithmen durch Programmablaufpläne ........................................................... 43<br />
1.3.3.2 Darstellung von Algorithmen mit Struktogrammen........................................................................ 46<br />
1.3.4 Datentyp und Datenstruktur................................................................................................................... 52<br />
1.4 Die Objektorientierung von <strong>Java</strong> .............................................................................................................. 55<br />
1.4.1 Grundlegen<strong>de</strong> Konzepte......................................................................................................................... 55<br />
1.4.1.1 Zustand und Verhalten von Objekten, Klassen, Instanz- und Klassen-Variable bzw. -Metho<strong>de</strong>n . 55<br />
1.4.1.1.1 Die Abbildung von Zustand bzw. Verhalten <strong>in</strong> Instanzvariable bzw. Instanzmetho<strong>de</strong>n ......... 55<br />
1.4.1.1.2 E<strong>in</strong>fache Typen, Referenztypen, Automatisches Boxen.......................................................... 59<br />
1.4.1.1.3 Konstruktoren .......................................................................................................................... 61<br />
1.4.1.1.4 Zugriffsrechte auf Klassen, Variable und Metho<strong>de</strong>n ............................................................... 62<br />
1.4.1.1.5 Klassenvariable und Klassenmetho<strong>de</strong>n.................................................................................... 64<br />
1.4.1.1.6 Lokale Variable und Konstanten.............................................................................................. 65<br />
1.4.1.1.7 Überla<strong>de</strong>n von Metho<strong>de</strong>n......................................................................................................... 66<br />
1.4.1.2 Superklassen und Subklassen, Vererbung und Klassenhierarchie.................................................. 67<br />
1.4.1.3 Referenzen, Referenztypen und Aufzählungstyp............................................................................72<br />
1.4.1.4 Konvertieren von Objekten und Primitivtypen ............................................................................... 75<br />
1.4.1.5 Manipulieren von Objekten ............................................................................................................ 76<br />
1.4.1.6 Innere (lokale) und anonyme Klassen............................................................................................. 80<br />
1.4.1.7 Schnittstellen und Pakete ................................................................................................................ 82<br />
1.4.1.7.1 Schnittstellen............................................................................................................................ 82<br />
1.4.1.7.2 Pakete....................................................................................................................................... 84<br />
1.4.1.8 Polymorphismus und B<strong>in</strong><strong>de</strong>n .......................................................................................................... 88<br />
1.4.2 Klassen <strong>de</strong>s Pakets java.lang.................................................................................................................. 90<br />
1.4.2.1 Die Klasse Object............................................................................................................................ 90<br />
1.4.2.3 Die Klasse System .......................................................................................................................... 93<br />
1.4.2.4 Multithread<strong>in</strong>g................................................................................................................................. 95<br />
1.4.2.4.1. Die Klasse Thread................................................................................................................... 95<br />
1.4.2.4.2 Das Interface Runnable ...................................................................................................... 102<br />
1.4.2.4.3. Prozesse und Threads <strong>in</strong> <strong>Java</strong>................................................................................................ 104<br />
1.4.2.4.4 Synchronisation nebenläufiger Prozesse................................................................................ 106<br />
1.4.2.5 Die Klassen Str<strong>in</strong>g und Str<strong>in</strong>gBuffer ............................................................................................ 112<br />
3
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.5.1 Die Klasse Str<strong>in</strong>g............................................................................................................... 112<br />
1.4.2.5.2 Die Klasse Str<strong>in</strong>gBuffer ......................................................................................................... 116<br />
1.4.2.6 Die Math-Klasse ........................................................................................................................... 117<br />
1.4.2.7 Object-Wrapper-Klassen............................................................................................................... 118<br />
1.4.3 Ausnahmen und Ausnahmenbehandlung............................................................................................. 121<br />
1.4.4 E<strong>in</strong>-, Ausgaben..................................................................................................................................... 128<br />
1.4.4.1 E<strong>in</strong>- und Ausgabeströme <strong>de</strong>r Klasse System................................................................................. 128<br />
1.4.4.2 Datenströme .................................................................................................................................. 129<br />
1.4.4.3 E<strong>in</strong>gabe und Ausgabe mit Dateien................................................................................................ 131<br />
1.4.4.4 Verwalten von Dateien und Verzeichnissen durch die Klasse File............................................... 137<br />
1.4.4.5 Filtern mit <strong>de</strong>n Klasse FilterRea<strong>de</strong>r und FilterWriter ................................................................... 137<br />
1.4.4.6 Der Dateiauswahl-Dialog.............................................................................................................. 141<br />
2. HAUPTBESTANDTEILE DER SPRACHE ................................................................................... 143<br />
2.1 Token.......................................................................................................................................................... 143<br />
2.1.1 Schlüsselworte ..................................................................................................................................... 144<br />
2.1.2 Bezeichner und Namenskonventionen................................................................................................. 144<br />
2.1.3 Literale ................................................................................................................................................. 145<br />
2.1.3.1 Ganzzahlige Literale ..................................................................................................................... 145<br />
2.1.3.2 Gleitpunktliterale .......................................................................................................................... 145<br />
2.1.3.3 Boolesche Literale......................................................................................................................... 146<br />
2.1.3.4 Zeichenliterale............................................................................................................................... 146<br />
2.1.3.5 Zeichenkettenliterale..................................................................................................................... 147<br />
2.1.4 Trennzeichen........................................................................................................................................ 147<br />
2.1.5 Operatoren ........................................................................................................................................... 148<br />
2.1.5.1 Arithmetische Operatoren ............................................................................................................. 148<br />
2.1.5.1.1 E<strong>in</strong>stellige arithmetische Operatoren ..................................................................................... 148<br />
2.1.5.1.2 Arithmetische Zuweisungsoperatoren.................................................................................... 148<br />
2.1.5.2 Inkrement- / Dekrement-Operatoren............................................................................................. 149<br />
2.1.5.3 Bitweise arithmetische Operatoren ............................................................................................... 149<br />
2.1.5.4 Bitweise Verschiebungsoperatoren............................................................................................... 149<br />
2.1.5.5 Bitweise Zuweisungsoperatoren ................................................................................................... 151<br />
2.1.5.6 Vergleichsoperatoren .................................................................................................................... 152<br />
2.1.5.7 Logische Vergleichsoperatoren..................................................................................................... 152<br />
2.1.6 Kommentare, e<strong>in</strong>gebettete Dokumentation.......................................................................................... 153<br />
2.2 Typen.......................................................................................................................................................... 155<br />
2.2.1 Primitive Datentypen ........................................................................................................................... 155<br />
2.2.2 Operationen mit primitiven Datentypen............................................................................................... 156<br />
2.2.2.1 Operationen mit booleschen Variablen......................................................................................... 156<br />
2.2.2.2 Operationen mit Zeichenvariablen................................................................................................ 156<br />
2.2.2.3 Operationen mit Gleitpunktzahlen ................................................................................................ 157<br />
2.2.2.4 Operationen mit ganzzahligen Variablen (bzw. ganzzahligen Ausdrücken) ................................ 158<br />
2.2.3 Datenfel<strong>de</strong>r (Arrays) ............................................................................................................................ 159<br />
2.2.3.1 Deklarieren, Erstellen von Array-Objekten .................................................................................. 159<br />
2.2.3.2 Zugriff auf Datenfeld-Elemente, Än<strong>de</strong>rn von Datenfeld-Elementen............................................ 161<br />
2.2.3.3 Anwendungen mit e<strong>in</strong>dimensionaler Datenfel<strong>de</strong>rn....................................................................... 162<br />
2.2.3.4 Mehrdimensionale Datenfel<strong>de</strong>r..................................................................................................... 164<br />
2.2.3.5 Die Klasse Arrays ......................................................................................................................... 170<br />
2.3 Ausdrücke.................................................................................................................................................. 171<br />
2.3.1 Arithmetische Ausdrücke..................................................................................................................... 171<br />
2.3.2 Bewertung von Ausdrücken................................................................................................................. 171<br />
2.3.3 Typkonvertierungen............................................................................................................................. 172<br />
2.3.4 Vergleichsoperatoren ........................................................................................................................... 175<br />
2.3.5 Logische Ausdrücke............................................................................................................................. 175<br />
2.4 Anweisungen.............................................................................................................................................. 176<br />
2.4.1 Blöcke und Anweisungen .................................................................................................................... 176<br />
4
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.4.2 Leere Anweisungen ............................................................................................................................. 176<br />
2.4.3 Benannte Anweisungen ....................................................................................................................... 176<br />
2.4.4 Deklarationen....................................................................................................................................... 176<br />
2.4.5 Ausdrucksanweisungen........................................................................................................................ 176<br />
2.4.6 Auswahlanweisungen .......................................................................................................................... 177<br />
2.4.6.1 if-Anweisungen............................................................................................................................. 177<br />
2.4.6.2 if-else-Anweisungen ..................................................................................................................... 177<br />
2.4.6.3 switch-Anweisungen..................................................................................................................... 179<br />
2.4.7 Iterationsanweisungen.......................................................................................................................... 180<br />
2.4.7.1 while-Anweisung .......................................................................................................................... 180<br />
2.4.7.2 do-Anweisung............................................................................................................................... 181<br />
2.4.7.3 for-Anweisung .............................................................................................................................. 182<br />
2.4.7.4 Die erweiterte Form <strong>de</strong>r for-Schleife <strong>in</strong> <strong>Java</strong> 1.5.......................................................................... 183<br />
2.4.8 Sprung-Anweisungen........................................................................................................................... 184<br />
2.4.8.1 break-Anweisung .......................................................................................................................... 184<br />
2.4.8.2 cont<strong>in</strong>ue-Anweisung ..................................................................................................................... 184<br />
2.4.8.3 Marken (labels) ............................................................................................................................. 185<br />
2.4.8.4 return-Anweisung ......................................................................................................................... 187<br />
2.4.8.5 throw-Anweisung.......................................................................................................................... 187<br />
2.4.9 Synchronisationsanweisungen ............................................................................................................. 187<br />
2.4.10 Schutzanweisungen............................................................................................................................ 188<br />
2.4.11 Unerreichbare Anweisungen.............................................................................................................. 188<br />
2.5 Klassen ....................................................................................................................................................... 188<br />
2.5.1 Deklaration........................................................................................................................................... 188<br />
2.5.2 Generische Klassen und generische Schnittstellen .............................................................................. 189<br />
2.5.2.1 Generische Typen ......................................................................................................................... 189<br />
2.5.2.1.1 Typvariable ............................................................................................................................ 189<br />
2.5.2.1.2 Vererbung .............................................................................................................................. 192<br />
2.5.2.1.3 E<strong>in</strong>schränkung <strong>de</strong>r Typvariablen ........................................................................................... 193<br />
2.5.2.2 Generische Schnittstellen.............................................................................................................. 194<br />
2.6 Metho<strong>de</strong>n ................................................................................................................................................... 196<br />
2.6.1 Die Deklaration.................................................................................................................................... 196<br />
2.6.2 Die Zugriffsspezifizierung ................................................................................................................... 196<br />
2.6.3 Die Metho<strong>de</strong>nmodifizierer................................................................................................................... 197<br />
2.6.4 Rückgabewerte von Metho<strong>de</strong>n............................................................................................................. 197<br />
2.6.5 Metho<strong>de</strong>nname und Parameterliste ...................................................................................................... 197<br />
2.6.6 Variable Parameteranzahl .................................................................................................................... 198<br />
2.6.7 Rekursion ............................................................................................................................................. 198<br />
2.6.7.1 Rekursive Funktionen ................................................................................................................... 198<br />
2.6.7.2 Rekursion und Iteration................................................................................................................. 199<br />
3. GRAFISCHE BENUTZEROBERFLÄCHEN UND APPLETS ...................................................... 201<br />
3.1 Ereignisse <strong>in</strong> grafischen Benutzeroberflächen ....................................................................................... 201<br />
3.1.1 Gestaltung von GUI mit Hilfe <strong>de</strong>r AWT-Klassen................................................................................ 201<br />
3.1.2 Ereignisbehandlung unter grafischen Benutzeroberflächen................................................................. 205<br />
3.1.3 Anwendung lokaler Klassen für die Ereignisbehandlung.................................................................... 208<br />
3.1.5 Low-Level-Events................................................................................................................................ 213<br />
3.1.5.1 Component-Events........................................................................................................................ 213<br />
3.1.5.2 W<strong>in</strong>dow-Events............................................................................................................................. 213<br />
3.1.5.3 Mouse-Events ............................................................................................................................... 214<br />
3.1.5.4 MouseMotion-Events.................................................................................................................... 215<br />
3.1.5.5 Fokus-Events................................................................................................................................. 215<br />
3.1.5.6 Key-Events.................................................................................................................................... 216<br />
3.1.6 Der Weg e<strong>in</strong>es Ereignisses................................................................................................................... 219<br />
3.2 Kommunikation Anwen<strong>de</strong>r – Programm über Dialoge bzw. Menüs................................................... 221<br />
3.2.1 Dialoge................................................................................................................................................. 221<br />
5
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.2.2 Menüs................................................................................................................................................... 228<br />
3.2.3 Popup-Menüs ....................................................................................................................................... 230<br />
3.3 Grundlagen <strong>de</strong>r Applet-Erstellung.......................................................................................................... 232<br />
3.3.1 HTML-Grundlagen.............................................................................................................................. 232<br />
3.3.2 Die <strong>in</strong>terne Arbeitsweise e<strong>in</strong>es Applets ............................................................................................... 234<br />
3.3.3 „Multithread<strong>in</strong>g“-fähige Applets ......................................................................................................... 240<br />
3.3.4 Animation <strong>in</strong> Applets........................................................................................................................... 243<br />
3.3.5 Das La<strong>de</strong>n und Anzeigen von Bil<strong>de</strong>rn ................................................................................................. 248<br />
3.3.7 Die Klasse JApplet............................................................................................................................... 250<br />
3.3.8 Das Interface AppletContext................................................................................................................ 251<br />
3.4 Grafische Benutzeroberfläche mit Observable-Observer ..................................................................... 252<br />
3.5 Sw<strong>in</strong>g .......................................................................................................................................................... 255<br />
3.6 <strong>Java</strong> Beans ................................................................................................................................................. 256<br />
3.6.1 Wie<strong>de</strong>rverwendbare Softwarekomponenten ........................................................................................ 256<br />
3.6.3 Enterprise <strong>Java</strong> Beans .......................................................................................................................... 258<br />
4. GRAFIK UND BILDVERARBEITUNG ......................................................................................... 259<br />
4.1 Allgeme<strong>in</strong>e Zeichenvorgänge ................................................................................................................... 260<br />
4.1.1 Punkte, L<strong>in</strong>ien, Kreise, Bögen, Polygone ............................................................................................ 260<br />
4.1.2 Farbangaben......................................................................................................................................... 266<br />
4.1.3 Textausgabe über <strong>de</strong>n Zeichen-Modus ................................................................................................ 267<br />
4.1.4 Grössenangaben ................................................................................................................................... 270<br />
4.1.5 Clipp<strong>in</strong>g-Operationen .......................................................................................................................... 271<br />
4.2 Bildverarbeitung ....................................................................................................................................... 271<br />
4.2.1 Klassen zur Bildverarbeitung............................................................................................................... 272<br />
4.2.2 Bildproduzenten und Bildkonsumenten............................................................................................... 276<br />
4.2.3 Bildfilter............................................................................................................................................... 277<br />
4.2.4 Kopieren von Speicher <strong>in</strong> e<strong>in</strong> Bild bzw. von Bil<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>en Speicher.............................................. 281<br />
4.2.4.1 Kopieren von Speicher <strong>in</strong> e<strong>in</strong> Bild................................................................................................ 281<br />
4.2.4.2 Kopieren von Bil<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>en Speicher ....................................................................................... 282<br />
4.3 <strong>Java</strong> 2D....................................................................................................................................................... 284<br />
4.3.1 Das Zeichnen unter <strong>Java</strong>2D API.......................................................................................................... 285<br />
4.3.3 Koord<strong>in</strong>atensysteme und Transformation ............................................................................................ 295<br />
4.3.4 <strong>Java</strong>2D-Pipel<strong>in</strong>e ................................................................................................................................... 300<br />
4.3.5 Farbmanagement unter <strong>Java</strong> 2D........................................................................................................... 301<br />
4.3.6 Text und Fonts unter <strong>Java</strong>2D ............................................................................................................... 307<br />
4.3.7 2D Bildverarbeitung............................................................................................................................. 309<br />
4.3.8 Animationen mit <strong>Java</strong>2D ..................................................................................................................... 310<br />
5. AWT............................................................................................................................................... 311<br />
5.1 Bestandteile <strong>de</strong>s AWT............................................................................................................................... 311<br />
5.2 Die AWT-Komponenten........................................................................................................................... 311<br />
5.2.1 Schaltflächen (Buttons)........................................................................................................................ 312<br />
5.2.2 Labels................................................................................................................................................... 315<br />
5.2.3 Kontrollkästchen und Optionsfel<strong>de</strong>r .................................................................................................... 315<br />
5.2.4 Auswahlmenüs..................................................................................................................................... 319<br />
5.2.5 Listenfel<strong>de</strong>r .......................................................................................................................................... 320<br />
5.2.6 Textbereiche und Textfel<strong>de</strong>r ................................................................................................................ 321<br />
5.2.7 Schieber und Bildlaufleisten ................................................................................................................ 324<br />
5.2.8 ScrollPane ............................................................................................................................................ 327<br />
6
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.2.9 Zeichenbereiche ................................................................................................................................... 328<br />
5.3 Conta<strong>in</strong>er ................................................................................................................................................... 331<br />
5.3.1 Panels ................................................................................................................................................... 331<br />
5.3.2 Frames.................................................................................................................................................. 331<br />
5.3.3 Menüs................................................................................................................................................... 332<br />
5.3.4 Dialoge................................................................................................................................................. 336<br />
5.4 Die Layout-Manager................................................................................................................................. 338<br />
5.4.1 Layout-Regeln...................................................................................................................................... 338<br />
5.4.2 Die e<strong>in</strong>zelnen Layout-Manager............................................................................................................ 339<br />
5.5 Die Event-Mo<strong>de</strong>lle 1.0 und 1.1 ................................................................................................................. 347<br />
5.5.1 Der AWT-Handler 1.0 ......................................................................................................................... 347<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.................................................................................... 349<br />
5.6 Benutzerschnittstellen mit Sw<strong>in</strong>g............................................................................................................. 355<br />
6. UTILITIES...................................................................................................................................... 421<br />
6.1 Kollektionen (Collections) ........................................................................................................................ 421<br />
6.1.1 Durchwan<strong>de</strong>rn von Datenstrukturen mit Iteratoren ............................................................................. 421<br />
6.1.2 Die Klasse Vector ................................................................................................................................ 422<br />
6.1.3 Die Klasse Stack .................................................................................................................................. 424<br />
6.1.4 Die Klasse Bitset für Bitmengen.......................................................................................................... 427<br />
6.1.5 Die Klasse Hashtable und assoziative Speicher................................................................................... 428<br />
6.1.6 Die abstrakte Klasse Dictionary........................................................................................................... 432<br />
6.1.7 Die Klasse Properties........................................................................................................................... 433<br />
6.2 Collection API ........................................................................................................................................... 434<br />
6.2.1 Die Schnittstellen Collection, Iterator, Comparator............................................................................. 434<br />
6.2.2 Die Behälterklassen und Schnittstellen <strong>de</strong>s Typs List ......................................................................... 436<br />
6.2.3 Behälterklassen <strong>de</strong>s Typs Set............................................................................................................... 440<br />
6.2.4 Behälterklassen <strong>de</strong>s Typs Map............................................................................................................. 443<br />
6.2.5 Algorithmen ......................................................................................................................................... 445<br />
6.2.5.1 Datenmanipulation ........................................................................................................................ 445<br />
6.2.5.2 Größter und kle<strong>in</strong>ster Wert e<strong>in</strong>er Collection................................................................................. 446<br />
6.2.5.3 Sortieren........................................................................................................................................ 446<br />
6.2.5.4 Suchen von Elementen.................................................................................................................. 448<br />
6.2.6 Generics ............................................................................................................................................... 449<br />
6.2.6.1 Sammlungsklassen ........................................................................................................................ 449<br />
6.2.6.2 Generische Metho<strong>de</strong>n ................................................................................................................... 450<br />
6.2.6.3 Iteration......................................................................................................................................... 452<br />
6.3 Die Klasse Str<strong>in</strong>gTokenizer...................................................................................................................... 455<br />
6.4 Die Klasse Random................................................................................................................................... 456<br />
6.5 Datumsberechnungen ............................................................................................................................... 457<br />
6.5.1 Die Klassen Date, Calendar, GregorianCalendar................................................................................. 457<br />
6.5.2 Formatieren <strong>de</strong>r Datumsangaben ......................................................................................................... 461<br />
6.6 Formatieren mit Format-Objekten ......................................................................................................... 463<br />
6.6.1 Die Klasse Numberformat für die Ausgabe von Prozenten, Zahlen, Währungen ............................... 464<br />
6.6.2 Ausgabe formatieren mit MessageFormat ........................................................................................... 464<br />
6.6.3 Dezimalzahlenformatierung mit DecimalFormat................................................................................. 464<br />
6.6.4 Formatieren mit format()...................................................................................................................... 465<br />
7. EIN- UND AUSGABE ................................................................................................................... 467<br />
7
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.1 Die abstrakten Klassen InputStream und OutputStream..................................................................... 469<br />
7.1.1 InputStream.......................................................................................................................................... 469<br />
7.1.2 OutputStream ....................................................................................................................................... 471<br />
7.2 Gefilterte Ströme....................................................................................................................................... 472<br />
7.3 Die Klasse File ........................................................................................................................................... 475<br />
7.4 Die RandomAccessFile-Klasse................................................................................................................. 477<br />
7.5 Die Klasse StreamTokenizer .................................................................................................................... 479<br />
7.6 Klassen für spezielle nützliche Ströme.................................................................................................... 482<br />
7.7 <strong>Java</strong> 1.1 IO-Ströme ................................................................................................................................... 483<br />
7.7.1 Grundlagen........................................................................................................................................... 483<br />
7.7.2 Die abstrakte Klassen Rea<strong>de</strong>r und ihre Ableitungen............................................................................ 484<br />
7.7.3 Die abstrakte Klasse Writer und ihre Ableitungen .............................................................................. 486<br />
7.7.4 Demonstrationsprogramm zur E<strong>in</strong>-/ Ausgabe ab <strong>Java</strong> Version 1.1 ..................................................... 489<br />
8. SERIALISIERUNG........................................................................................................................ 491<br />
8.1 Grundlagen................................................................................................................................................ 491<br />
8.1.1 Das Interface Serializable .................................................................................................................... 491<br />
8.1.2 Die Klasse ObjectOutputStream .......................................................................................................... 492<br />
8.1.3 Die Klasse ObjectInputStream............................................................................................................. 494<br />
8.2 Tiefe Objektkopien ................................................................................................................................... 496<br />
9. NETZWERKPROGRAMMIERUNG .............................................................................................. 497<br />
9.1 Adressen, Ressourcen und URLs............................................................................................................. 497<br />
9.1.1 Die Klasse InetAddress........................................................................................................................ 497<br />
9.1.2 Die Klasse URL ................................................................................................................................... 498<br />
9.1.3 Die Klasse URLConnection und abgeleitete Klassen.......................................................................... 502<br />
9.2 Kommunikation <strong>in</strong> Netzwerken............................................................................................................... 503<br />
8
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Literaturverzeichnis<br />
Alexan<strong>de</strong>r Newman u.a.: JAVA, Referenz und Anwendungen, 1996, Haar bei München : Que<br />
Ralph Steyer: JAVA 1.2, Kompendium, 1998, Markt & Technik, Haar bei München<br />
Laura Lemay u. Roger Ca<strong>de</strong>nhead; JAVA 2 <strong>in</strong> 21 Tagen, 1999, Markt & Technik, Haar bei<br />
München<br />
Gui<strong>de</strong> 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 />
Florian Hawlitzek: <strong>Java</strong> 2, 2000, Addison-Wesley, München ...<br />
Christian Ullenboom: <strong>Java</strong> ist auch e<strong>in</strong>e Insel, GalileoPress, Bonn 2002<br />
9
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
0. Übersicht<br />
0.1 Ziel <strong>de</strong>r Vorlesung "<strong>Programmieren</strong>"<br />
„Vermittlung grundlegen<strong>de</strong>r 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 „irgen<strong>de</strong><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 Son<strong>de</strong>rzeichen besitzen (Tastatur)<br />
- programmierbar se<strong>in</strong><br />
- e<strong>in</strong>e Ausgabemöglichkeit haben (Bildschirm)<br />
Zum Erwerb grundlegen<strong>de</strong>r Kenntnisse für das Lösen von Problemen auf e<strong>in</strong>em<br />
Universalrechner ist<br />
- zu zeigen, wie man von <strong>de</strong>r Problemstellung zum Lösungsverfahren (Algorithmus) kommt. Alle<br />
Probleme, für die e<strong>in</strong> Lösungweg genügend präzise formuliert wer<strong>de</strong>n kann, s<strong>in</strong>d über <strong>de</strong>n Rechner<br />
lösbar.<br />
- zu üben: Der Umgang mit <strong>de</strong>n Algorithmen. Dazu wird die Programmiersprache <strong>Java</strong> benutzt, <strong>in</strong> <strong>de</strong>r<br />
die Algorithmen formuliert wer<strong>de</strong>n. Der <strong>in</strong> <strong>Java</strong> formulierte Lösungsweg (Algorithmus) ist das <strong>Java</strong>-<br />
Programm (Anwendung, Applet), <strong>de</strong>r Rechner auf <strong>de</strong>m 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> wur<strong>de</strong> 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 <strong>de</strong>s Universalrechners.<br />
Die E<strong>in</strong>gabemöglichkeit dient zum E<strong>in</strong>schreiben von Daten und Programmen <strong>in</strong> <strong>de</strong>n<br />
Speicher <strong>de</strong>r 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 <strong>de</strong>n Anweisungen <strong>de</strong>s e<strong>in</strong>gelesenen<br />
Programms, das zur Ausführung <strong>in</strong> b<strong>in</strong>äre Form gebracht wur<strong>de</strong>. Das Steuerwerk<br />
überwacht die Ausführung <strong>de</strong>s Programms (Entschlüsseluung <strong>de</strong>r b<strong>in</strong>är dargestellten<br />
Anweisungen). Das eigentliche Abarbeiten <strong>de</strong>r Programmanweisungen<br />
(arithmetische, logische Operatoren) <strong>in</strong> <strong>de</strong>r gegebenen Reihenfolge übernimmt das<br />
Rechenwerk. Daten, Programme, die im Hauptspeicher ke<strong>in</strong>en Platz f<strong>in</strong><strong>de</strong>n, 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 />
Operationsco<strong>de</strong>s (Masch<strong>in</strong>enanweisungen) <strong>in</strong>terpretieren kann. Es wur<strong>de</strong>n bzw. wer<strong>de</strong>m 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 <strong>de</strong>r jeweiligen Zielplattform.<br />
11
<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 (z.B.<br />
<strong>Java</strong>-Masch<strong>in</strong>e) gewünscht wird, gibt <strong>de</strong>r Benutzer durch Systemkommandos<br />
bekannt. Diese Kommandos wer<strong>de</strong>n von Systemprogrammen entschlüsselt und<br />
anschließend <strong>in</strong>terpretiert. E<strong>in</strong>es dieser Kommandos verwan<strong>de</strong>lt, falls die dazu<br />
nötigen Programme vorhan<strong>de</strong>n s<strong>in</strong>d, <strong>de</strong>n 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 <strong>de</strong>s Benutzers die Quelle<br />
aller Erkenntnisse.<br />
Quellprogramme wer<strong>de</strong>n über die Tastatur e<strong>in</strong>gegeben und auf externen Speicher<br />
abgelegt. Zur E<strong>in</strong>gabe, Korrektur und Än<strong>de</strong>rung stellt das System e<strong>in</strong> Programm mit<br />
<strong>de</strong>m Namen „Editor" zur Verfügung. Das Speichern <strong>de</strong>r e<strong>in</strong>gegebenen bzw.<br />
geän<strong>de</strong>rten Programme auf Externspeicher übernimmt das Systemprogramm<br />
„Dateiverwaltung“.<br />
<strong>Java</strong>-Programm<br />
Daten<br />
E<strong>in</strong>gabe (Tastatur)<br />
Externer Speicher<br />
Externer Speicher<br />
<strong>Java</strong>-Compiler<br />
System,<br />
<strong>Java</strong>-Quellpro-<br />
System- <strong>Java</strong>-Masch<strong>in</strong>e gramme<br />
programme<br />
<strong>Java</strong>-Laufzeitsystem<br />
<strong>Java</strong>-Byteco<strong>de</strong>-<br />
Dateien<br />
Ausgabe (Bildschirm)<br />
12
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
0.3 Der erste Versuch<br />
0.3.1 Das erste Programm<br />
Quelltext:<br />
import java.lang.*;<br />
/* ErstesProgramm ist e<strong>in</strong>e Applikation, die <strong>de</strong>n e<strong>in</strong>fachen<br />
Gebrauch von Zeichenketten aufzeigt */<br />
public class ErstesProgramm extends Object<br />
{<br />
// Beg<strong>in</strong>n <strong>de</strong>r 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 <strong>de</strong>r Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.");<br />
}<br />
}<br />
Das Programm umfaßt zwei Teile: e<strong>in</strong>e Klassen<strong>de</strong>f<strong>in</strong>ition und e<strong>in</strong>en<br />
Programmabschnittt, <strong>de</strong>r durch die Metho<strong>de</strong> ma<strong>in</strong>() bestimmt ist.<br />
Je<strong>de</strong> <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>()-Metho<strong>de</strong> benutzen:<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]) { ... }.<br />
Es be<strong>de</strong>uten:<br />
public ... Die Metho<strong>de</strong> ist für an<strong>de</strong>re Klassen und Objekte verfügbar<br />
static ... Es han<strong>de</strong>lt sich um e<strong>in</strong>e Klassenmetho<strong>de</strong><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 wer<strong>de</strong>n, wer<strong>de</strong>n 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 <strong>de</strong>s Programms, die ausgeführt wird.<br />
Durch die „import“-Anweisung können Entwickler Klassen verwen<strong>de</strong>n, die <strong>in</strong><br />
an<strong>de</strong>ren Dateien <strong>de</strong>f<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“, <strong>de</strong>nn hier ist die Klasse Object enthalten, von <strong>de</strong>r alle <strong>Java</strong>-<br />
Klassen abgeleitet s<strong>in</strong>d. Das Paket „java.lang“, die unmittelbare Ableitung von <strong>de</strong>r<br />
Klasse Object wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> per <strong>de</strong>fault bereitgestellt. Die diesbezüglichen<br />
Angaben im Programm können entfallen, <strong>de</strong>r Quelltext kann <strong>de</strong>shalb auch folgen<strong>de</strong><br />
Gestalt annehmen:<br />
/* ErstesProgramm ist e<strong>in</strong>e Applikation, die <strong>de</strong>n e<strong>in</strong>fachen<br />
Gebrauch von Zeichenketten aufzeigt */<br />
public class ErstesProgramm<br />
{<br />
// Beg<strong>in</strong>n <strong>de</strong>r 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 <strong>de</strong>r Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>.");<br />
}<br />
}<br />
13
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Token<br />
Die Ausdrucksformen <strong>de</strong>r Sprache <strong>Java</strong> wer<strong>de</strong>n Token genannt. In <strong>de</strong>rartige für die<br />
Sprache <strong>Java</strong> s<strong>in</strong>nvolle E<strong>in</strong>heiten muß sich <strong>de</strong>r 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 o<strong>de</strong>r I<strong>de</strong>ntifizierer,<br />
Schlüsselworte, Literale, Operatoren, Trennzeichen.<br />
Bezeichner, I<strong>de</strong>ntifizierer: Darunter versteht man die Benennungen (Namen) für<br />
Klassen, Objekte, Variable, Metho<strong>de</strong>n. Namen s<strong>in</strong>d zusammengesetzt aus Unico<strong>de</strong>-<br />
Zeichen. <strong>Java</strong> benutzt <strong>de</strong>n 16-Bit-Unico<strong>de</strong>-Zeichensatz, <strong>de</strong>ssen erste 256 Zeichen<br />
<strong>de</strong>m normalen ASCII-Zeichensatz entsprechen (Byte 1 ist immer auf 0 gesetzt). Im<br />
vorliegen<strong>de</strong>n Programm s<strong>in</strong>d z.B. Bezeichner: ErstesProgramm, ma<strong>in</strong>, System.<br />
<strong>Java</strong> unterschei<strong>de</strong>t Groß-/ Kle<strong>in</strong>schreibung. Namen bestehen <strong>in</strong> <strong>de</strong>r Regel aus<br />
alphabetischen Zeichen und Dezimalziffern. An <strong>de</strong>r 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 <strong>de</strong>r <strong>Java</strong>-<br />
Sprach<strong>de</strong>f<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 wer<strong>de</strong>n. 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 <strong>de</strong>r 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 Angabe e<strong>in</strong>er<br />
auszuführen<strong>de</strong>n Operation mit e<strong>in</strong>er o<strong>de</strong>r mehreren Variablen o<strong>de</strong>r Konstanten<br />
(Operan<strong>de</strong>n), z.B. + - / >.<br />
Variable s<strong>in</strong>d Arbeitsspeicherstellen, an <strong>de</strong>nen Informationen gespeichert wer<strong>de</strong>n<br />
können. Zur Deklaration erhält e<strong>in</strong>e Variable Namen (Bezeichner) und Typ<br />
zugeordnet. Der Typ kennzeichnet die Art <strong>de</strong>r 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> unterschei<strong>de</strong>t man: elementare (primitive Typen) und benutzer<strong>de</strong>f<strong>in</strong>ierte<br />
Typen (e<strong>in</strong>schl. <strong>de</strong>r 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), Gleitpunktzahlen (float, double), Zeichen (char) und booleschen Werten<br />
(boolean).<br />
Sobald die Variable <strong>de</strong>klariert wur<strong>de</strong>, kann ihr über <strong>de</strong>n Zuweisungsoperator („=“) e<strong>in</strong><br />
Wert zugewiesen wer<strong>de</strong>n, z.B. <strong>in</strong>nerhalb <strong>de</strong>r ma<strong>in</strong>()-Metho<strong>de</strong><br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g s; // Deklaration <strong>de</strong>r Variablen s zur Aufnahme von Zeichenketten<br />
// Zuweisung<br />
s = "Das erste Programm <strong>de</strong>r Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>."<br />
// Aufruf <strong>de</strong>r Metho<strong>de</strong> pr<strong>in</strong>tln() <strong>de</strong>r Klasse System, die sich im Paket<br />
// java.lang bef<strong>in</strong><strong>de</strong>t<br />
System.out.pr<strong>in</strong>tln(s);<br />
}<br />
14
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Vorrang Operator Operan<strong>de</strong>ntyp Assoziation Operation<br />
1 ++<br />
--<br />
+, -<br />
~<br />
!<br />
(type)<br />
Arithmetisch<br />
Arithmetisch<br />
Arithmetisch<br />
Integral<br />
boolean<br />
irgen<strong>de</strong><strong>in</strong><br />
R<br />
R<br />
R<br />
R<br />
R<br />
R<br />
Pre- o<strong>de</strong>r Post-Inkrement<br />
(unär)<br />
Pre- o<strong>de</strong>r Post-<br />
Dekrement (unär)<br />
Unäres Plus, unäres<br />
M<strong>in</strong>us<br />
Bitweises Komplement<br />
(unär)<br />
Logisches Komplement<br />
(unär)<br />
cast<br />
2 *, /, % arithmetisch L Multiplikation, Division,<br />
Rest<br />
3 +, -<br />
+<br />
Arithmetisch<br />
Str<strong>in</strong>g<br />
L<br />
L<br />
Addition, Subtraktion<br />
Verkettung<br />
4 ><br />
>>><br />
Integral<br />
Integral<br />
Integral<br />
L<br />
L<br />
L<br />
L<strong>in</strong>ks-Shift<br />
Rechts-Shift mit<br />
Vorzeichen<br />
Rechts-Shift mit Nullen-<br />
5 =<br />
<strong>in</strong>stanceof<br />
6 ==<br />
!=<br />
==<br />
!=<br />
7 &<br />
&<br />
8 ^<br />
^<br />
Arithmetisch<br />
Arithmetisch<br />
Objekt, Typ<br />
Primitiver Typ<br />
Primitiver Typ<br />
Objekt<br />
Objekt<br />
Integral<br />
boolean<br />
Integral<br />
boolean<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
L<br />
Nachziehen<br />
Kle<strong>in</strong>er als, kle<strong>in</strong>er als<br />
o<strong>de</strong>r gleich<br />
Größer als, größer als<br />
o<strong>de</strong>r gleich<br />
Objekt?, Instanz?<br />
Gleich (i<strong>de</strong>ntische Werte)<br />
Ungleich (verschie<strong>de</strong>ne<br />
Werte)<br />
Gleich (Referenz auf das<br />
gleiche Objekt)<br />
Ungleich (Referenz auf<br />
verschie<strong>de</strong>ne Objekte)<br />
Bitweises Und<br />
Logisches Und<br />
Bitweises O<strong>de</strong>r<br />
Logisches O<strong>de</strong>r<br />
(exklusiv)<br />
9 |<br />
|<br />
Integral<br />
boolean<br />
L<br />
L<br />
Bitweises O<strong>de</strong>r<br />
Logisches O<strong>de</strong>r (<strong>in</strong>klusiv)<br />
10 && boolean L Konditionelles Und<br />
11 || boolean L Konditionelles O<strong>de</strong>r<br />
12 ?= boolean,<br />
irgen<strong>de</strong><strong>in</strong>,<br />
irgen<strong>de</strong><strong>in</strong><br />
R<br />
Konditioneller (ternärer)<br />
Operator<br />
13 =<br />
*=, /=,<br />
+=, -=<br />
=,<br />
>>>=,<br />
&=, ^=,<br />
|=<br />
Abb. 0.3-1: <strong>Java</strong>-Operatoren<br />
Variable, irgen<strong>de</strong><strong>in</strong><br />
Variable, irgen<strong>de</strong><strong>in</strong><br />
R<br />
R<br />
Zuweisung<br />
Zuweisung mit Operation<br />
15
<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. Je<strong>de</strong> 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 <strong>de</strong>r Fall ist. Derartige Anweisungen<br />
wer<strong>de</strong>n 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 an<strong>de</strong>ren Anweisung verwen<strong>de</strong>t o<strong>de</strong>r überhaupt nicht beachtet wer<strong>de</strong>n.<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 Quellco<strong>de</strong>: ( ) {<br />
} [ ] ; . , .<br />
„(“: wird sowohl zum Öffnen e<strong>in</strong>er Parameterliste für e<strong>in</strong>e Metho<strong>de</strong> als auch zur<br />
Festlegung <strong>de</strong>r 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 Metho<strong>de</strong> als auch zur<br />
Festlegung <strong>de</strong>r 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 o<strong>de</strong>r e<strong>in</strong>er Initialisierungsliste<br />
gesetzt.<br />
„}“:wird an das En<strong>de</strong> e<strong>in</strong>es Blocks mit Anweisungen o<strong>de</strong>r e<strong>in</strong>er Initialisierungsliste<br />
gesetzt.<br />
Bsp.: Metho<strong>de</strong>n wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> durch e<strong>in</strong>en Anweisungsblock bestimmt. E<strong>in</strong> Anweisungsblock<br />
besteht <strong>in</strong> <strong>de</strong>r Regel aus e<strong>in</strong>er Reihe von Anweisungen, die von geschweiften Klammern umschlossen<br />
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 <strong>de</strong>r 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, <strong>de</strong>r als In<strong>de</strong>x für e<strong>in</strong> Datenfeld (Array) steht.<br />
„]“: folgt e<strong>in</strong>em Ausdruck, <strong>de</strong>r als In<strong>de</strong>x für e<strong>in</strong> Datenfeld steht.<br />
Bsp.: Str<strong>in</strong>g args[] = {"Juergen", "Hubert", "Josef", "Liesel", "Christian"};<br />
<strong>de</strong>f<strong>in</strong>iert e<strong>in</strong>en Array mit 5 Komponenten, die alle <strong>de</strong>n gleichen Typ besitzen.<br />
Datenfel<strong>de</strong>r (Arrays) dienen zum Speichern von Elementen, die alle <strong>de</strong>nselben Typ aufweisen.<br />
Je<strong>de</strong>m Element wird <strong>in</strong>nerhalb <strong>de</strong>s Datenfelds e<strong>in</strong> eigener Speicherplatz zugewiesen. Dieser<br />
Speicherplatz ist für <strong>de</strong>n leichten Zugriff durchnumeriert.<br />
[0] "Juergen"<br />
[1] "Hubert"<br />
[2] "Josef"<br />
[3] "Liesel"<br />
[4] "Christian"<br />
Auf <strong>de</strong>n Wert e<strong>in</strong>er Komponenten kann über <strong>de</strong>n Array-Namen (z.B. args), gefolgt von e<strong>in</strong>em In<strong>de</strong>x <strong>in</strong><br />
eckigen Klammern (z.B. [0]) zugegriffen wer<strong>de</strong>n. Mit<br />
args[0] = "Roland";<br />
kann <strong>de</strong>m ersten Element <strong>de</strong>s Array args e<strong>in</strong> neuer Wert zugewiesen wer<strong>de</strong>n.<br />
„;“: dient zum Been<strong>de</strong>n 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 o<strong>de</strong>r Variablennamen benutzt (z.B. System.out.pr<strong>in</strong>tln(s);).<br />
16
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Standardmäßig haben Klassen Zugriff auf die Klassen im Paket „java.lang“. Zur<br />
Bezugnahme auf e<strong>in</strong>e Klasse, die sich nicht <strong>in</strong> java.lang bef<strong>in</strong><strong>de</strong>t, s<strong>in</strong>d alle Pakete,<br />
<strong>in</strong> <strong>de</strong>nen sich die Klasse bef<strong>in</strong><strong>de</strong>t, 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><strong>de</strong>t.<br />
Leerraumzeichen: Sie können <strong>in</strong> beliebiger Anzahl und an je<strong>de</strong>m Ort zwischen Token<br />
(die e<strong>in</strong>e Funktion besitzen) zur übersichtlichen Gestaltung <strong>de</strong>s Quellco<strong>de</strong>s plaziert<br />
wer<strong>de</strong>n. Solche Zeichen s<strong>in</strong>d bspw.: Space, Tab, Zeilenen<strong>de</strong>, Formularvorschub<br />
Kommentar: Er wird vom Compiler ignoriert. Man unterschei<strong>de</strong>t <strong>de</strong>n Kommentar bis<br />
zum Zeilenen<strong>de</strong> „//“ und <strong>de</strong>n e<strong>in</strong>gebetteten Kommentar „/* ... */“, z.B.:<br />
/* ErstesProgramm ist e<strong>in</strong>e Applikation, die <strong>de</strong>n e<strong>in</strong>fachen<br />
Gebrauch von Zeichenketten aufzeigt */<br />
Übersetzung und Ausführung.<br />
Bef<strong>in</strong><strong>de</strong>t sich <strong>de</strong>r Quelltext zum Programm <strong>in</strong> e<strong>in</strong>er Datei mit <strong>de</strong>m Namen<br />
ErstesProgramm.java, dann kann dieses Programm durch Aufruf <strong>de</strong>s <strong>Java</strong>-<br />
Compilers javac <strong>in</strong> ablauffähigen Byteco<strong>de</strong> übersetzt wer<strong>de</strong>n. Das geschieht über<br />
das folgen<strong>de</strong> Systemkommando:<br />
javac ErstesProgramm.java<br />
Den Byte-Co<strong>de</strong>, <strong>de</strong>n <strong>de</strong>r <strong>Java</strong>-Compiler <strong>in</strong> <strong>de</strong>r Datei ErstesProgramm.class<br />
h<strong>in</strong>terlegt hat, kann über das Kommando<br />
java ErstesProgramm<br />
zur Ausführung gebracht wer<strong>de</strong>n.<br />
17
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Konsole: Arbeitsspeicher: Externspeicher<br />
javac ErstesProgramm.java<br />
ErstesProgramm.java<br />
ErstesProgramm.class<br />
java ErstesProgramm<br />
ErstesProgramm.class<br />
<strong>Java</strong> (-Interpreter)<br />
"Das erste Programm <strong>de</strong>r Vorlesung <strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong>"<br />
Abb. 0.3-2: Ablaufplan ErstesProgramm<br />
18
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
0.3.2 Bestandteile e<strong>in</strong>es Programms<br />
Wesentliche Programmelemente <strong>in</strong> <strong>Java</strong> s<strong>in</strong>d:<br />
- Anweisungen<br />
Anweisungen 3 gehören zu <strong>de</strong>n 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 o<strong>de</strong>r <strong>de</strong>n 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>an<strong>de</strong>r ausgeführt wer<strong>de</strong>n. E<strong>in</strong><br />
Block kann eigene Variable <strong>de</strong>f<strong>in</strong>ieren, die nur <strong>in</strong>nerhalb <strong>de</strong>s Blocks sichtbar s<strong>in</strong>d. Sie wer<strong>de</strong>n beim<br />
Aufruf <strong>de</strong>s Blocks angelegt und beim Verlassen <strong>de</strong>s Blocks zerstört. Innerhalb e<strong>in</strong>es Blocks s<strong>in</strong>d nur<br />
die lokalen Variablen <strong>de</strong>s Blocks und die lokalen Variablen <strong>de</strong>s umgeben<strong>de</strong>n Blocks bzw. <strong>de</strong>r<br />
umgeben<strong>de</strong>n Metho<strong>de</strong> sichtbar. Nach außen stellt sich <strong>de</strong>r Block als e<strong>in</strong>e e<strong>in</strong>zige Anweisung dar.<br />
- Metho<strong>de</strong>n<br />
Metho<strong>de</strong>n 7 unterschei<strong>de</strong>n sich von Blöcken folgen<strong>de</strong>rmaßen:<br />
-- Sie haben e<strong>in</strong>en Namen und können von verschie<strong>de</strong>nen Stellen <strong>de</strong>s Programms aufgerufen<br />
wer<strong>de</strong>n.<br />
-- Sie s<strong>in</strong>d parametrisierbar<br />
-- Sie können e<strong>in</strong>en Rückgabewert besitzen.<br />
Metho<strong>de</strong>n wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> immer lokal zu e<strong>in</strong>er Klasse <strong>de</strong>f<strong>in</strong>iert.<br />
- Klassen<br />
Sie 8 enthalten Variablen zur Beschreibung <strong>de</strong>s Zustands von Objekten und Metho<strong>de</strong>n zur<br />
Beschreibung <strong>de</strong>s Verhaltens von Objekten.<br />
- Schnittstellen<br />
E<strong>in</strong>e Schnittstelle (Interface) ist e<strong>in</strong>e Sammlung von Metho<strong>de</strong>n, die e<strong>in</strong>en Namen besitzen, aber<br />
nicht implementiert s<strong>in</strong>d. E<strong>in</strong> Klasse kann beliebig viele Schnittstellen implementieren. Dadurch wird<br />
die Klasse zur Implementierung <strong>de</strong>r Metho<strong>de</strong> gezwungen, <strong>de</strong>ren Namen von <strong>de</strong>r Schnittstelle<br />
<strong>de</strong>f<strong>in</strong>iert wur<strong>de</strong>n. Falls zwei unterschiedliche Klassen, dieselbe Schnittstelle implementieren, können<br />
bei<strong>de</strong> auf Aufrufe <strong>de</strong>r Metho<strong>de</strong>, die <strong>in</strong> <strong>de</strong>r Schnittstelle <strong>de</strong>f<strong>in</strong>iert s<strong>in</strong>d, reagieren. Allerd<strong>in</strong>gs kann die<br />
Reaktion auf diese Metho<strong>de</strong>naufrufe 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. Je<strong>de</strong> Klasse <strong>in</strong> <strong>Java</strong> gehört zu e<strong>in</strong>em Paket. Pakete<br />
ermöglichen, daß Sammlungen von Klassen bei Bedarf verfügbar s<strong>in</strong>d. Die Klassenbibliotheken<br />
bef<strong>in</strong><strong>de</strong>n sich <strong>in</strong> e<strong>in</strong>em Paket mit <strong>de</strong>m Namen „java“. Dieses Paket be<strong>in</strong>haltet Pakete, die spezielle<br />
Bestandteile <strong>de</strong>r Sprache <strong>Java</strong>, z.B. Dateie<strong>in</strong>gabe und Datenausgabe, Multimedia, etc. <strong>de</strong>f<strong>in</strong>ieren.<br />
Standardmäßig haben Klassen <strong>de</strong>r Anwen<strong>de</strong>r nur Zugrifff auf Klassen im Paket „java.lang“<br />
(Standard-Feature). Klassen irgen<strong>de</strong><strong>in</strong>es an<strong>de</strong>ren Pakets müssen importiert wer<strong>de</strong>n.<br />
- Applikationen (Anwendungen)<br />
Anwendungen (Applikationen) bil<strong>de</strong>n die eigenständigen Programme. Sie benötigen zur Ausführung<br />
ke<strong>in</strong>en Browser, son<strong>de</strong>rn nur <strong>de</strong>n <strong>Java</strong>-Interpreter und die .class-Dateien <strong>de</strong>r verwen<strong>de</strong>ten<br />
Klassen.<br />
- Applets<br />
Applets s<strong>in</strong>d ebenfalls lauffähige <strong>Java</strong>-Programme. Sie wer<strong>de</strong>n aus e<strong>in</strong>er HTML-Seite aufgerufen<br />
und benötigen zur Ausführung e<strong>in</strong>en Web-Browser (o<strong>de</strong>r e<strong>in</strong> Werkzeug wie <strong>de</strong>n Appletviewer).<br />
Applets müssen von <strong>de</strong>r Klasse Applet abgeleitet und nach <strong>de</strong>n Regeln dieser Klasse aufgebaut<br />
se<strong>in</strong>. Zum Starten <strong>de</strong>s Programms erzeugt <strong>de</strong>r Browser e<strong>in</strong>e Instanz <strong>de</strong>r abgeleiteten Klasse und<br />
ruft e<strong>in</strong>e Reihe vor<strong>de</strong>f<strong>in</strong>ierter Callback-Metho<strong>de</strong>n 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-Metho<strong>de</strong>n s<strong>in</strong>d von <strong>de</strong>r abgeleiteteten Klasse zur Verfügung gestellte Metho<strong>de</strong>n, die vom Browser<br />
bzw. Appletviewer aufgerufen wer<strong>de</strong>n<br />
19
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
20
<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 <strong>de</strong>r Programmiersprache <strong>Java</strong><br />
<strong>Java</strong> ist <strong>in</strong> <strong>de</strong>n Entwicklungslaboren <strong>de</strong>r amerikanischen Firma Sun Microsystems 10<br />
entstan<strong>de</strong>n. 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 vorliegen<strong>de</strong>n Programmiersprachen zu große Schwächen zeigten.<br />
Der erste Versuch war nur bed<strong>in</strong>gt erfolgreich. Lediglich <strong>de</strong>r damals im Internet<br />
verbreitete Mosaic-Browser 12 wur<strong>de</strong> zu e<strong>in</strong>er Zielplattform <strong>de</strong>r neuen<br />
Programmiersprache 13 , die En<strong>de</strong> 1994 für das Internet umgearbeitet wur<strong>de</strong> und über<br />
das Netz frei und umsonst verteilt wur<strong>de</strong>.<br />
1995 wur<strong>de</strong> die neue Programmiersprache mit <strong>de</strong>m Namen <strong>Java</strong> 14 <strong>de</strong>r 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, <strong>de</strong>r erste<br />
<strong>Java</strong>-fähige Browser und damit die Präsentationsform für die ersten <strong>Java</strong>-Applets.<br />
Außer<strong>de</strong>m war dieser Browser e<strong>in</strong>e wesentliche Ergänzung <strong>de</strong>s ersten <strong>Java</strong>-<br />
Entwicklungstools von Sun – das <strong>Java</strong> Develelopment Kit (JDK 1.0). E<strong>in</strong><br />
kommerzielles Produkt, <strong>de</strong>r <strong>Java</strong> Workshop 15 , wur<strong>de</strong> kurz nach <strong>de</strong>r Präsentation von<br />
JDK 1.0 bereitgestellt.<br />
Natürlich gab es im JDK noch diverse K<strong>in</strong><strong>de</strong>rkrankheiten. Im zweiten Quartal 1997<br />
folgte <strong>de</strong>shalb nach e<strong>in</strong>igen Zwischenversionen die Version 1.1 <strong>de</strong>s JDK. Parallel zur<br />
10 Sun ist e<strong>in</strong>e <strong>de</strong>r führen<strong>de</strong>n Hersteller von Workstations<br />
11 Entwicklung e<strong>in</strong>es vollkommen neuen, plattformunabhängigen Betriebssystems für <strong>de</strong>n „Consumerbereich<br />
<strong>de</strong>r allgeme<strong>in</strong>en Elektronik (Telefone, Vi<strong>de</strong>orecor<strong>de</strong>r, Waschmasch<strong>in</strong>en, Kaffemasch<strong>in</strong>en; eigentlich alle<br />
elektrischen Masch<strong>in</strong>en, die Daten benötigen)<br />
12 <strong>de</strong>r erste WWW-Browser mit e<strong>in</strong>er grafischen Benutzeroberfläche. WWW steht für World Wi<strong>de</strong> 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 <strong>de</strong>r Sprache HTML entwickelt wur<strong>de</strong>n und wer<strong>de</strong>n. E<strong>in</strong> Hypertext ist im wesentlichen e<strong>in</strong> ASCII-Text,<br />
<strong>de</strong>r durch maskierte 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 an<strong>de</strong>re Texte. Der Verweis auf <strong>de</strong>n weiterführen<strong>de</strong>n Text kann aktiviert wer<strong>de</strong>n (z.B. durch<br />
Mausklick), und es wird zu <strong>de</strong>m gewünschten Text verzweigt.<br />
Das Hypertext Transfer Protocol (HTTP) dient zur Übertragung von Informationen aus <strong>de</strong>m 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, wer<strong>de</strong>n (<strong>in</strong> <strong>de</strong>r Regel) als Web-Browser,<br />
Server-Programme als Web-Server bezeichnet. Der Browser schickt an <strong>de</strong>n Server die Auffor<strong>de</strong>rung e<strong>in</strong>e<br />
bestimmte HTML-Seite zu übertragen. Falls er <strong>in</strong> dieser Seite weitere Verweise (z.B. auf Bil<strong>de</strong>r) ent<strong>de</strong>ckt,<br />
schickt er weitere Übertragungswünsche h<strong>in</strong>terher. Das Besorgen <strong>de</strong>r gewünschten Dokumente erfolgt über e<strong>in</strong><br />
e<strong>in</strong>heitliches Adressierungsschema, <strong>de</strong>m Uniform Resource Locater (URL), durch <strong>de</strong>n Internet-Standort und die<br />
Art <strong>de</strong>r zu übertragen<strong>de</strong>n Information i<strong>de</strong>ntifiziert wer<strong>de</strong>n.<br />
13 Dem WWW mit <strong>de</strong>m bis zu diesem Zeitpunkt realisierten Stand <strong>de</strong>r HTML fehlten: dreidimensionale<br />
Darstellung <strong>de</strong>r Objekte, e<strong>in</strong>e bewegte Animation und e<strong>in</strong>e Möglichkeit zur vernünftigen Interaktion mit <strong>de</strong>m<br />
Anwen<strong>de</strong>r. Deshalb waren hier die Multimedia- und Interaktionseigenschaften <strong>de</strong>r neuen Programmiersprache<br />
beson<strong>de</strong>rs 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 <strong>de</strong>r Informationen f<strong>in</strong><strong>de</strong>t man<br />
bereits auf <strong>de</strong>r E<strong>in</strong>stiegseite von Sun (http://java.sun.com), an<strong>de</strong>re Informationen bekommt man von <strong>de</strong>r<br />
Neuigkeitenseite (http://java.sun.com/nav/new/<strong>in</strong><strong>de</strong>x.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 <strong>de</strong>r Version 2.0 <strong>in</strong>zwischen <strong>in</strong> e<strong>in</strong>e neue Phase zur Unterstützung <strong>de</strong>s neuen <strong>Java</strong>.<br />
21
<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 <strong>de</strong>r<br />
neuen 1.1-API-Funktionen.<br />
<strong>Java</strong> 1.2 ist die neueste Version. In Verb<strong>in</strong>dung mit <strong>de</strong>m JDK 1.2 wur<strong>de</strong> <strong>de</strong>r 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> verschie<strong>de</strong>nen Ausgaben (Editionen) erhältlich. Sun hat<br />
drei verschie<strong>de</strong>ne Editionen mit unterschiedlicher Ausrichtung <strong>de</strong>f<strong>in</strong>iert:<br />
1. Standard-Edition für <strong>de</strong>n Desktop Client o<strong>de</strong>r 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 <strong>de</strong>m JDK gibt es zahlreiche kommerzielle Entwicklungstools für <strong>Java</strong>-<br />
Programmierer, z. B.: Symantec Visual Café, Borland JBuil<strong>de</strong>r, SuperCa<strong>de</strong>, 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, <strong>de</strong>zentrale, <strong>in</strong>terpretierte, stabil laufen<strong>de</strong>,<br />
sichere, architekturneutrale, portierbare und dynamische Sprache, die<br />
Hochleistungsgeschw<strong>in</strong>digkeitsanwendungen und Multithread<strong>in</strong>g unterstützt.<br />
- <strong>Java</strong> ist e<strong>in</strong>fach, obwohl es sehr nahe an <strong>de</strong>r ziemlich komplizierten C/C++-Syntax entworfen wur<strong>de</strong>.<br />
Die komplexen Teile von C/C++ wur<strong>de</strong>n 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 <strong>de</strong>nen 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 <strong>de</strong>r ursprünglichen Ziele von <strong>Java</strong> war die Erleichterung <strong>de</strong>r 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 <strong>de</strong>f<strong>in</strong>ieren<br />
und Metho<strong>de</strong>n zur Bearbeitung dieser Objekte verwen<strong>de</strong>n. Das objektorientierte Konzept von <strong>Java</strong><br />
hat viel von C++ geerbt, aber auch Konzepte an<strong>de</strong>rer objektorientierter Sprachen wur<strong>de</strong>n<br />
übernommen. Wie die meisten objektorientierten Sprachen umfaßt <strong>Java</strong> e<strong>in</strong>e umfangreiche<br />
Klassenbibliothek, die grundlegen<strong>de</strong> Datentypen, Systeme<strong>in</strong>- und Systemausgabe und an<strong>de</strong>re<br />
Hilfsmittel (utilities) bietet. Die grundlegen<strong>de</strong>n Klassen s<strong>in</strong>d Teil <strong>de</strong>s JDK, das darüber h<strong>in</strong>aus noch<br />
Klassen besitzt, die Funktionen 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 <strong>de</strong>zentral und erfüllt e<strong>in</strong>e wesentliche Eigenschaft von Client/Server-Anwendungen. Die<br />
Fähigkeit <strong>de</strong>r Verteilung von Informationen für die Berechnung <strong>de</strong>r Daten. „Dezentral“ beschreibt die<br />
Beziehung von Systemobjekten: Es ist gleichgültig, ob die Objekte sich auf lokalen o<strong>de</strong>r 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 />
22
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Systemen bef<strong>in</strong><strong>de</strong>n. Objekte können mit <strong>Java</strong>-Programmen über URLs 20 vom gesamten Web<br />
genauso wie auf <strong>de</strong>m lokalen Rechner geöffnet und bearbeitet wer<strong>de</strong>n. Wichtige Teile <strong>de</strong>r<br />
Anwendung bzw. <strong>de</strong>r Daten können lokal vorhan<strong>de</strong>n se<strong>in</strong>, an<strong>de</strong>re wer<strong>de</strong>n bei Bedarf gela<strong>de</strong>n.<br />
- <strong>Java</strong> ist <strong>in</strong>terpretiert. E<strong>in</strong> gewisser Teil <strong>de</strong>s <strong>Java</strong>-Co<strong>de</strong>s (ca. 20 %) wer<strong>de</strong>n vom Conta<strong>in</strong>er, <strong>de</strong>m<br />
Browser <strong>in</strong>terpretiert. Der <strong>Java</strong>-Quellco<strong>de</strong> wird mit <strong>de</strong>m <strong>Java</strong>-Compiler <strong>in</strong> Byteco<strong>de</strong><br />
(architekturneutrales Object-Co<strong>de</strong>-Format) kompiliert. Byteco<strong>de</strong> ist nicht lauffähig, bis er von <strong>de</strong>r<br />
<strong>Java</strong>-Laufzeitumgebung 21 <strong>in</strong>terpretiert wird.<br />
<strong>Java</strong>-Compiler (Pentium)<br />
<strong>Java</strong>-Interpreter (Pentium)<br />
<strong>Java</strong>-Co<strong>de</strong><br />
<strong>Java</strong>-Compiler (SPARC)<br />
<strong>Java</strong>-Interpreter (SPARC)<br />
Abb. 1.2-1:<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 <strong>de</strong>r Kompilierungsphase <strong>de</strong>r gößte Teil <strong>de</strong>r Datenüberprüfung ausgeführt wer<strong>de</strong>n kann.<br />
<strong>Java</strong> ist stark typisiert. Damit können Fehler früh gefun<strong>de</strong>n wer<strong>de</strong>n. E<strong>in</strong> weiteres Stabilitätskriterium<br />
von <strong>Java</strong>-Programmen ist die e<strong>in</strong>gebaute Begrenzung <strong>de</strong>r Zugriffsmöglichkeiten auf <strong>de</strong>n<br />
Speicherbereich <strong>de</strong>s Rechners 22 . H<strong>in</strong>zu kommt auch noch die anschließen<strong>de</strong><br />
Sicherheitsüberprüfung durch <strong>de</strong>n „L<strong>in</strong>ker“. Der L<strong>in</strong>ker ist e<strong>in</strong> Teil <strong>de</strong>r Laufzeitumgebung, das die im<br />
System e<strong>in</strong>gehen<strong>de</strong>n 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><strong>de</strong>utig<br />
adressiert. Innerhalb <strong>de</strong>s 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 Adressanfragen 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“ <strong>de</strong>shalb, weil mit e<strong>in</strong>er URL sowohl die verschie<strong>de</strong>nen Dienste (WWW,<br />
FTP, Gopher usw.) als auch Rechner o<strong>de</strong>r Dokumente beschrieben wer<strong>de</strong>n können. Der Begriff „Objekt“ steht<br />
bspw. für Datei, Text, Vi<strong>de</strong>os, Sounds usw., also für ziemlich alles, was sich im Netz bef<strong>in</strong><strong>de</strong>t. Die exakte<br />
Schreibweise e<strong>in</strong>er URL ist je nach Dienstprotokoll etwas unterschiedlich, sieht jedoch <strong>in</strong> <strong>de</strong>r 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<br />
zwei Slashes (Ausnahme: mailto).<br />
Mit hosts.doma<strong>in</strong> wird e<strong>in</strong> Rechner im Internet adressiert. Dabei kann die IP-Nummer <strong>de</strong>s Rechner angegeben<br />
wer<strong>de</strong>n (unüblich). Häufiger nimmt man dafür <strong>de</strong>n DNS-Namen (<strong>in</strong> <strong>de</strong>r 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 verschie<strong>de</strong>nen Diensten parallel<br />
betrieben wer<strong>de</strong>n (z.B. FTP-Server, HTTP-Server). Zum Erreichen <strong>de</strong>s gewünschten Dienstes auf <strong>de</strong>m<br />
ausgewählten Rechner benötigt man <strong>de</strong>n sog. Port. Ports s<strong>in</strong>d numerische Werte (zwischen 0 und 1023). In <strong>de</strong>r<br />
Regel hat je<strong>de</strong>r Internet-Dienst e<strong>in</strong>en Default-Wert, <strong>de</strong>r immer verwen<strong>de</strong>t 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 <strong>de</strong>n Port „21“.<br />
Das genaue Objekt verbirgt sich h<strong>in</strong>ter <strong>de</strong>r Angabe /pfad/datei.<br />
21 Normalerweise durch e<strong>in</strong>en <strong>Java</strong>-Browser<br />
22 Ungeprüfte Zugriffe auf Speicherbereiche <strong>de</strong>s Rechners ermöglicht C/C++ (Zeigerarithmetik, implizite<br />
Deklaration)<br />
23
<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 verschie<strong>de</strong>n Systemen mit unterschiedlichen Prozessoren und Betriebssystemarchitekturen<br />
lauffähig (architekturneutral). Der komplette <strong>Java</strong>-Byteco<strong>de</strong> kann auf je<strong>de</strong>m Prozessor<br />
ausgeführt wer<strong>de</strong>n, <strong>de</strong>r 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>ärco<strong>de</strong> wird allerd<strong>in</strong>gs nicht erzeugt, son<strong>de</strong>rn <strong>Java</strong>-Byteco<strong>de</strong><br />
wird während <strong>de</strong>r Laufzeit <strong>in</strong> systemeigenen Masch<strong>in</strong>enco<strong>de</strong> übertragen (<strong>in</strong>terpretiert).<br />
- <strong>Java</strong> unterstützt „Multithread<strong>in</strong>g“. „Multthread<strong>in</strong>g be<strong>de</strong>utet: Mehrere Aufgaben o<strong>de</strong>r Prozesse können<br />
gleichzeitig ausgeführt wer<strong>de</strong>n. Nicht die quasi gleichzeitige Ausführung mehrerer Programme<br />
(Multitask<strong>in</strong>g), son<strong>de</strong>rn die gleichzeitige, parallele Ausführung von e<strong>in</strong>zelnen Programmschritten<br />
(o<strong>de</strong>r zusammenhängen<strong>de</strong>n Prozessen) ist „Multithread<strong>in</strong>g“. Das kann be<strong>de</strong>uten: Innerhalb e<strong>in</strong>es<br />
Programms können mehrere D<strong>in</strong>ge gleichzeitig geschehen, mehrere Fa<strong>de</strong>n / Threads e<strong>in</strong>es<br />
Programms können gleichzeitig verfolgt und abgearbeitet wer<strong>de</strong>n.<br />
23 Verschie<strong>de</strong>ne Sicherheitslücken wur<strong>de</strong>n aufge<strong>de</strong>ckt und wur<strong>de</strong>n <strong>in</strong>zwischen beseitigt.<br />
24 Die virtuelle Masch<strong>in</strong>e wird auch als <strong>Java</strong> Interpreter o<strong>de</strong>r <strong>Java</strong> Environment (<strong>Java</strong>-Laufzeitumgebung)<br />
bezeichnet<br />
24
<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 Schreiben<br />
von <strong>Java</strong> Programmen. Das JDK ist für Sun-SPARC-Systeme mit Solaris 2.2 (o<strong>de</strong>r<br />
höher) sowie für W<strong>in</strong>dows NT und W<strong>in</strong>dows 95 über das Internet 25 erhältlich.<br />
Nach <strong>de</strong>r Installation hat das <strong>Java</strong>-Verzeichnis 26 folgen<strong>de</strong>n Inhalt 27 :<br />
Abb. 1.3-1: Inhalt <strong>de</strong>s <strong>Java</strong>-Verzeichnisses<br />
Innerhalb <strong>de</strong>s <strong>Java</strong>-Verzeichnisses bef<strong>in</strong><strong>de</strong>n sich Unterverzeichnisse 28 mit folgen<strong>de</strong>m<br />
Inhalt:<br />
Verzeichnis<br />
\b<strong>in</strong><br />
\lib<br />
\<strong>in</strong>clu<strong>de</strong><br />
\<strong>de</strong>mo<br />
\src<br />
Inhalt<br />
In diesem Verzeichnis bef<strong>in</strong><strong>de</strong>n sich die JDK-Programme<br />
In diesem Verzeichnis bef<strong>in</strong><strong>de</strong>n sich <strong>de</strong>faultmäßig die Standard-<strong>Java</strong>-Klassen<br />
<strong>de</strong>s JDK 29<br />
In diesem Verzeichnis bef<strong>in</strong><strong>de</strong>n sich diverse Hea<strong>de</strong>r-Dateien für die geme<strong>in</strong>same<br />
Verwendung von <strong>Java</strong> und C/C++<br />
Das Demo-Verzeichnis e<strong>in</strong>thält Beispielprogramme<br />
Falls „<strong>Java</strong>-Source“ im InstallShield ausgewählt wur<strong>de</strong>, wird dieses Verzeichnis<br />
mit angelegt. Dar<strong>in</strong> bef<strong>in</strong><strong>de</strong>n sich die entkomprimierten <strong>Java</strong>-Dateien, die sonst<br />
nur im gepackten Zustand (Datei SRC.ZIP) vorhan<strong>de</strong>n s<strong>in</strong>d.<br />
Es ist s<strong>in</strong>nvoll, die <strong>in</strong> <strong>de</strong>r 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 />
25 Das jeweils aktuelle JDK (aber auch ältere Versionen) können von <strong>de</strong>n Sun-Microsystem-Webseiten bzw. <strong>de</strong>r<br />
<strong>Java</strong>Soft-Homepage gela<strong>de</strong>n wer<strong>de</strong>n (http://www.sun.com bzw. http://www.javasoft.com/ ). Genutzt wer<strong>de</strong>n<br />
kann auch die <strong>Java</strong>Soft-WWW-Download-Seite für das jeweilige JDK (http://java.sun.com.products/jdk/x.x ,<br />
die Angabe x.x ist durch die gewünschte Versionsnummer zu ersetzen). Auch e<strong>in</strong>e FTP-Download, z.B. vom<br />
Sun-FTP-Server (ftp.javasoft.com) ist möglich.<br />
26 Erzeugt von <strong>de</strong>r Entpackungsrout<strong>in</strong>e <strong>de</strong>s JDK<br />
27 Das Verzeichnis „me<strong>in</strong>epr“ dient zur Aufnahme von Projekten und zählt nicht standardmäßig zum Inhalt<br />
e<strong>in</strong>es <strong>Java</strong>-Verzeichnisses<br />
28 unter W<strong>in</strong>dows<br />
29 Im wesentlichen ist das die Datei classes.zip<br />
25
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Anwen<strong>de</strong>r wird das Verzeichnis mit <strong>de</strong>n Werkzeugen <strong>in</strong> <strong>de</strong>r Pfadangabe <strong>de</strong>r Datei<br />
„autoexec.bat“ e<strong>in</strong>getragen, z.B.:<br />
PATH c:\;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>clu<strong>de</strong>;<br />
Die CLASSPATH-Umgebungsvariable 30 sollte unter W<strong>in</strong>dows <strong>in</strong> <strong>de</strong>r 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 verwen<strong>de</strong>t.<br />
Nach <strong>de</strong>r Installation <strong>de</strong>s JDK 1.2 bzw. JDK 1.3 muß das Verzeichnis<br />
\jdk1.3\b<strong>in</strong> <strong>in</strong> <strong>de</strong>n Suchpfad ausführbarer Dateien e<strong>in</strong>getragen wer<strong>de</strong>n. Das kann<br />
direkt <strong>in</strong> <strong>de</strong>r autoexec.bat durch Modifikation <strong>de</strong>r PATH-Anweisung, mit Hilfe e<strong>in</strong>er<br />
Batch-Datei o<strong>de</strong>r direkt erledigt wer<strong>de</strong>n, 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 <strong>de</strong>nen die Hot<strong>Java</strong>- und <strong>Java</strong>-Interpreter-Umgebungen <strong>de</strong>s<br />
Systems spezifiziert wer<strong>de</strong>n. Sie wer<strong>de</strong>n z.B. unter W<strong>in</strong>dows im allg. auf Befehlszeilenebene o<strong>de</strong>r <strong>in</strong> <strong>de</strong>r<br />
„autoexec.bat“ mit <strong>de</strong>r Anweisung „SET [Umgebungsvariable]= ....“ gesetzt.<br />
CLASSPATH ist die wichtigste <strong>de</strong>r Umgebungsvariablen von <strong>Java</strong>. Mit dieser Umgebungsvariablen wird<br />
bestimmt, woher die Systemklassen importiert wer<strong>de</strong>n.<br />
26
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.3.2 Applets und Anwendungen<br />
<strong>Java</strong> Programme wer<strong>de</strong>n <strong>in</strong> zwei Hauptanwendungs-Gruppen geglie<strong>de</strong>rt: Applets<br />
und Anwendungen.<br />
Applets s<strong>in</strong>d <strong>Java</strong>-Programme, die über das WWW heruntergela<strong>de</strong>n und von e<strong>in</strong>em<br />
Web-Browser auf <strong>de</strong>m Rechner <strong>de</strong>s Anwen<strong>de</strong>rs ausgeführt wer<strong>de</strong>n. Applets können<br />
nur auf e<strong>in</strong>em javafähigen Browser ausgeführt wer<strong>de</strong>n bzw. mit e<strong>in</strong>em Tool <strong>de</strong>s JDK,<br />
<strong>de</strong>m Appletviewer, gesichtet wer<strong>de</strong>n.<br />
<strong>Java</strong>-Anwendungen s<strong>in</strong>d allgeme<strong>in</strong>e, <strong>in</strong> <strong>de</strong>r <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 <strong>de</strong>n Text „Willkommen <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-<br />
Welt“ ausgibt.<br />
Lösungsschritte:<br />
1) Erstelle die folgen<strong>de</strong> Datei mit <strong>de</strong>m 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> <strong>de</strong>r <strong>Java</strong>-Welt!");<br />
}<br />
}<br />
Das Programm umfaßt zwei Teile: e<strong>in</strong>e Klassen<strong>de</strong>f<strong>in</strong>ition und e<strong>in</strong><br />
Programmabschnitt, <strong>de</strong>r unter ma<strong>in</strong>() angegeben ist.<br />
2) Speichern <strong>de</strong>r Datei mit <strong>de</strong>m Namen „Willkommen.java“ unter e<strong>in</strong>em beliebigen<br />
Verzeichnis 31 .<br />
3) Aufruf <strong>de</strong>s <strong>Java</strong>-Übersetzers über die folgen<strong>de</strong> Befehlszeilene<strong>in</strong>gabe:<br />
javac [optionen] date<strong>in</strong>ame.<br />
optionen .... bestimmen das Verhalten vom Compiler<br />
date<strong>in</strong>ame ... Name <strong>de</strong>r Datei mit <strong>de</strong>m <strong>Java</strong>-Quellco<strong>de</strong>. "javac" for<strong>de</strong>rt, daß<br />
<strong>de</strong>r Quelltext <strong>in</strong> Dateien steht, <strong>de</strong>ren Date<strong>in</strong>ame die Extension ".java"<br />
besitzt.<br />
„javac“ kompiliert <strong>de</strong>n Quellco<strong>de</strong> <strong>in</strong> <strong>Java</strong>-Byteco<strong>de</strong> und speichert se<strong>in</strong>e Ausgabe <strong>in</strong><br />
e<strong>in</strong>er Datei mit <strong>de</strong>m Namen „date<strong>in</strong>ame.class“. Standardmäßig wer<strong>de</strong>n .class-<br />
Dateien im gleichen Verzeichnis wie die .java-Quelldatei erzeugt 32 . Im vorliegen<strong>de</strong>n<br />
Fall ist <strong>de</strong>r Aufruf: javac Willkommen.java.<br />
4) Ausführen <strong>de</strong>r Byteco<strong>de</strong>-Datei „Willkommen.class“ mit <strong>de</strong>m <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> <strong>de</strong>r letzten (Ausgabe-) Zeile: Willkommen <strong>in</strong><br />
<strong>de</strong>r <strong>Java</strong>-Welt!.<br />
31 Vgl. pr13210<br />
32 Mit <strong>de</strong>r Option "-d" im javac-Aufruf kann die .class-Datei an e<strong>in</strong>em an<strong>de</strong>ren Ort gespeichert wer<strong>de</strong>n.<br />
27
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2. Aufgabe: Erstelle e<strong>in</strong>e Anwendung, die <strong>de</strong>n Text „Herzlich Willkommen<br />
Juergen Hubert Josef Liesel“ ausgibt. Die angebenen Namen<br />
sollen auf Befehlszeilenebene als Parameter e<strong>in</strong>geben wer<strong>de</strong>n.<br />
Lösungsschritte:<br />
1) Erstellen e<strong>in</strong>er Quelle (Datei), die folgen<strong>de</strong>n Quellco<strong>de</strong> 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 <strong>de</strong>r Datei, Übersetzen und Aufruf <strong>de</strong>s Programm mit <strong>de</strong>m Parameter<br />
Juergen führt zu: „Herzlich Willkommen Juergen“.<br />
Argumente auf Befehlszeilenebene wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>n Zeichenketten-Array „Str<strong>in</strong>g<br />
args[]“ aufgenommen. „args“ ist <strong>de</strong>r Name <strong>de</strong>s Zeichenketten-Arrays, das die<br />
Argumentenliste enthält und <strong>de</strong>m Programm immer zur Verfügung steht. Hier wur<strong>de</strong><br />
nur das erste Argument <strong>de</strong>r Liste (args[0])ausgegeben. Sollen alle Argumente, die<br />
auf <strong>de</strong>r Befehlszeilenebene e<strong>in</strong>gegeben wur<strong>de</strong>n, ausgegeben wer<strong>de</strong>n, 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, <strong>de</strong>r <strong>de</strong>n Beg<strong>in</strong>n <strong>de</strong>r Zählschleife e<strong>in</strong>leitet, z.B.<br />
Initialisierung e<strong>in</strong>es Schleifen<strong>in</strong><strong>de</strong>x (z.B. <strong>in</strong>t i = 0;). Die Variablen, die <strong>in</strong> diesem<br />
Teil <strong>de</strong>r Schleife <strong>de</strong>klariert wer<strong>de</strong>n, s<strong>in</strong>d lokal (<strong>in</strong> Bezug auf die Schleife). Das<br />
be<strong>de</strong>utet: Sie gehören zur Schleife und existieren nicht mehr nach <strong>de</strong>r vollständigen<br />
Ausführung <strong>de</strong>r 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 Ausdrücke, z.B.<br />
<strong>in</strong>t i = 0, <strong>in</strong>t j = 10).<br />
Test ist e<strong>in</strong> Ausdruck, <strong>de</strong>r nach je<strong>de</strong>r Iteration <strong>de</strong>r Schleife ausgeführt wird. Der Test<br />
muß e<strong>in</strong> boolescher Ausdruck o<strong>de</strong>r e<strong>in</strong>e Funktion se<strong>in</strong>, die e<strong>in</strong>en booleschen Wert<br />
zurückgibt (true o<strong>de</strong>r false). Ergibt <strong>de</strong>r 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 o<strong>de</strong>r Funktionsaufruf. Üblicherweise wird er<br />
verwen<strong>de</strong>t, um <strong>de</strong>n Wert <strong>de</strong>s Schleifen<strong>in</strong><strong>de</strong>x näher an <strong>de</strong>n Endwert zu br<strong>in</strong>gen und<br />
damit für Beendigung <strong>de</strong>r 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>an<strong>de</strong>r getrennt s<strong>in</strong>d.<br />
Auf <strong>de</strong>n Wert e<strong>in</strong>es Elements <strong>in</strong> e<strong>in</strong>em Array wird über <strong>de</strong>n Namen <strong>de</strong>s Array, gefolgt<br />
von e<strong>in</strong>em In<strong>de</strong>x <strong>in</strong> eckigen Klammern zugegriffen (z.B. args[i]). Array-Indizes<br />
beg<strong>in</strong>nen mit 0. Alle Array-Indizes wer<strong>de</strong>n geprüft, um sicher zu stellen, daß sie sich<br />
<strong>in</strong>nerhalb <strong>de</strong>r Grenzen <strong>de</strong>s Array bef<strong>in</strong><strong>de</strong>n, wie sie bei <strong>de</strong>r Erzeugung <strong>de</strong>s Arrays<br />
festgelegt wur<strong>de</strong>n. Die Länge <strong>de</strong>s Array kann im Programm mit <strong>de</strong>r Instanzvariablen<br />
length getestet wer<strong>de</strong>n (z.B. args.length).<br />
33 Vgl. pr13210<br />
28
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3) Erweitern <strong>de</strong>r Quellco<strong>de</strong>-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 <strong>de</strong>r Argumentenliste.<br />
4) Speichern <strong>de</strong>r Datei, Übersetzen und Aufruf <strong>de</strong>s Programm mit Parametern führt<br />
zu: „Herzlich Willkommen Juergen Liesel Vera Christian Hubert“.<br />
Auffällig ist: i spielt hier eigentlich gar ke<strong>in</strong>e große Rolle, es hat lediglich als In<strong>de</strong>x<br />
se<strong>in</strong>e Berechtigung. Nur damit lässt sich das Element an e<strong>in</strong>er bestimmten Stelle im<br />
Array ansprechen. Da dieses Durchlaufen von Arrays häufig ist , haben die<br />
Entwickler von Sun seit <strong>Java</strong> 1.5 e<strong>in</strong>e Abkürzung für soche Iterationen <strong>in</strong> die Sprache<br />
e<strong>in</strong>geführt:<br />
for (Typ bezeichner : Feld)<br />
...<br />
Diese erweiterte for-Schleife löst sich vom In<strong>de</strong>x und erfragt je<strong>de</strong>s Elemment <strong>de</strong>s<br />
Fel<strong>de</strong>s. "WillkommensGruss" lässt sich dann so formulieren:<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 />
for (Str<strong>in</strong>g arg : args)<br />
{<br />
System.out.pr<strong>in</strong>t(arg + " ");<br />
}<br />
System.out.pr<strong>in</strong>tln();<br />
}<br />
}<br />
Die "for"-Schleife ist folgen<strong>de</strong>rmaßen zu lesen: "Für je<strong>de</strong>s Element arg vom Typ<br />
Str<strong>in</strong>g <strong>in</strong> args tue ... ". E<strong>in</strong> Variablenname wie i für <strong>de</strong>n Scheifen<strong>in</strong><strong>de</strong>x ist nicht mehr<br />
nötig, <strong>de</strong>nn <strong>de</strong>r In<strong>de</strong>x ist nicht sichtbar. Intern setzt <strong>de</strong>r Compiler diese erweiterte<br />
for-Schleife ganz klassisch um, sodass <strong>de</strong>r Byteco<strong>de</strong> unter bei<strong>de</strong>n Varianten gleich<br />
ist.<br />
3. Aufgabe: Die auf Befehlszeilenebene e<strong>in</strong>gegebenen Namen sollen sortiert<br />
wer<strong>de</strong>n. So soll die E<strong>in</strong>gabe <strong>de</strong>r Befehlszeile „java<br />
WillkommensGruss Juergen Hubert Josef Liesel<br />
Christian“ zu folgen<strong>de</strong>r Ausgabe führen: „Herzlich Willkommen<br />
Christian Hubert Josef Juergen Liesel“.<br />
Lösungsschritte:<br />
1) Gesucht ist e<strong>in</strong> Algorithmus, <strong>de</strong>r die über die Befehlszeile e<strong>in</strong>gegebenen Namen<br />
sortiert. E<strong>in</strong> e<strong>in</strong>facher Sortieralgorithmus ist unter <strong>de</strong>m Namen „Bubble-Sort“<br />
29
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
bekannt. Man vergleicht dabei zunächst <strong>de</strong>n 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 folgen<strong>de</strong> 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 <strong>de</strong>r Name an <strong>de</strong>r 2. Position ([1]) mit <strong>de</strong>n übrigen Namen <strong>de</strong>s<br />
Datenfelds verglichen wer<strong>de</strong>n. Nach 3 Vergleichen zeigt sich folgen<strong>de</strong>s Bild:<br />
args<br />
[0] "Christian"<br />
[1] "Hubert"<br />
[2] "Juergen"<br />
[3] "Liesel"<br />
[4] "Josef"<br />
„Christian“ und „Hubert“ s<strong>in</strong>d jetzt richtig e<strong>in</strong>geordnet. Nun muß <strong>de</strong>r Name an <strong>de</strong>r<br />
dritten Position mit allen noch verbliebenen Namen auf Position 4 und 5 noch<br />
verglichen wer<strong>de</strong>n. Das Resultat <strong>de</strong>r 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 beschriebene Sortieralgorithmus muß <strong>in</strong> <strong>Java</strong>-Programmco<strong>de</strong><br />
abgebil<strong>de</strong>t wer<strong>de</strong>n. 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 />
30
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 wer<strong>de</strong>n über die Metho<strong>de</strong> „compareTo“ <strong>de</strong>r 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 verwen<strong>de</strong>t e<strong>in</strong>en boolschen Ausdruck für die Entscheidung, ob<br />
e<strong>in</strong>e Anweisung ausgeführt wer<strong>de</strong>n soll. Die Anweisung wird ausgeführt, wenn <strong>de</strong>r<br />
Ausdruck <strong>de</strong>n Wert true zurückliefert. Falls gewünscht wird, daß e<strong>in</strong>e bestimmte<br />
Anweisung bzw. Anweisungen ausgeführt wer<strong>de</strong>n, wenn <strong>de</strong>r boolsche 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 folgen<strong>de</strong>n 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 <strong>de</strong>r Datei, Übersetzen und Aufruf <strong>de</strong>s Programms mit Parametern führt<br />
zu: „Herzlich Willkommen Christian Hubert Josef Juergen Liesel“.<br />
4. Aufgabe: Die Argumentenliste args soll auf folgen<strong>de</strong> Weise angezeigt wer<strong>de</strong>n:<br />
31
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r Klammern. Sollen, wie hier gewünscht, mehrere Variablen,<br />
vom Typ Str<strong>in</strong>g o<strong>de</strong>r Zeichenkettenliterale, Argument für pr<strong>in</strong>tln() se<strong>in</strong>, dann<br />
können diese Elemente mit <strong>de</strong>m Verkettungsoperator „+“ zu e<strong>in</strong>em e<strong>in</strong>zigen Str<strong>in</strong>g<br />
o<strong>de</strong>r Zeichenkettenliteral verknüpft wer<strong>de</strong>n. Der Umgang mit <strong>de</strong>m<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 behan<strong>de</strong>lt. Sobald e<strong>in</strong> Teil e<strong>in</strong>er Verkettung e<strong>in</strong> Str<strong>in</strong>g o<strong>de</strong>r e<strong>in</strong> Str<strong>in</strong>g-<br />
Literal ist, wer<strong>de</strong>n alle Operatoren wie Str<strong>in</strong>gs behan<strong>de</strong>lt, z.B.:<br />
System.out.pr<strong>in</strong>tln("1 + 2 = " + 3);.<br />
2) Die Ausgabe kann über die folgen<strong>de</strong> 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 wer<strong>de</strong>n. Die<br />
bei<strong>de</strong>n Anführungszeichen, die das Literal umschliessen, müssen <strong>in</strong> <strong>de</strong>rselben Zeile<br />
<strong>de</strong>s Quellco<strong>de</strong>s 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 wer<strong>de</strong>n.<br />
5. Aufgabe: Zwei Gleitpunktzahlen sollen über die Befehlszeile e<strong>in</strong>gelesen wer<strong>de</strong>n.<br />
Anschließend sollen mit diesen bei<strong>de</strong>n Zahlen alle zugelassenen,<br />
b<strong>in</strong>ären arithmetischen Operationen für Gleitpunktzahlen (<strong>de</strong>s primitiven<br />
Datentyps float) und unäre Inkrement- bzw. Dekrement-Operationen<br />
ausgeführt wer<strong>de</strong>n.<br />
Lösungsschritte:<br />
1) Die Übergabe <strong>de</strong>r bei<strong>de</strong>n Zahlen über die Befehlsargumentenliste erfor<strong>de</strong>rt die<br />
Konvertierung <strong>de</strong>s Typs Str<strong>in</strong>g <strong>in</strong> e<strong>in</strong>en Typ <strong>de</strong>r Klasse Float. Das konvertierte<br />
Datum kann anschließend e<strong>in</strong>er Variablen <strong>de</strong>s primitiven Typs float zugewiesen<br />
wer<strong>de</strong>n.<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 (/) <strong>de</strong>f<strong>in</strong>iert. Es gibt außer<strong>de</strong>m für unäre<br />
Arithmetik noch Inkrement- und Dekrementoperatoren zur Manipulation <strong>de</strong>s Werts<br />
von Variablen.<br />
3) Der Quelltext zur Programmlösung 34 ist dann:<br />
public class FloatDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
34 FloatDemo.java aus pr13210<br />
32
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
// Konvertieren<br />
float x = Float.valueOf(args[0]).floatValue();<br />
float y = Float.valueOf(args[1]).floatValue();<br />
// Ausgabe <strong>de</strong>r 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 <strong>de</strong>n 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 />
4) Der Aufruf java FloatDemo 17 4 führt dann zu folgen<strong>de</strong>n Ausgabe:<br />
x = 17.0<br />
y = 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 = 18.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 = 24.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 />
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> <strong>de</strong>n Typ<br />
float konvertiert wer<strong>de</strong>n.<br />
33
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Anwendung zeigt außer<strong>de</strong>m die Anwendungsweise <strong>de</strong>r Inkrement- und<br />
Dekrementoperatoren <strong>in</strong> Präfix- und Postfix-Schreibweise. Steht <strong>de</strong>r Operator vor <strong>de</strong>r<br />
Variablen (z.B. ++x), dann wird er angewen<strong>de</strong>t, bevor <strong>de</strong>r Wert <strong>de</strong>r 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 <strong>de</strong>r 5. Aufgabe führt <strong>de</strong>r Aufruf java FloatDemo zu e<strong>in</strong>em Fehler.<br />
Dieser Fehler soll aufgefangen wer<strong>de</strong>n.<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) <strong>de</strong>n „try-catch“-Block. Im<br />
„try“-Block wird <strong>de</strong>r normale Ablauf behan<strong>de</strong>lt. Im „catch“-Block erfolgt die<br />
Behandlung <strong>de</strong>r Ausnahmen. Die Verzweigung <strong>in</strong> <strong>de</strong>n „catch“-Block erfolgt beim<br />
Auftreten e<strong>in</strong>er Ausnahme automatisch, <strong>de</strong>r „try“-Block bleibt dabei unberührt.<br />
2) Der Quelltext nimmt nach <strong>de</strong>m E<strong>in</strong>fügen e<strong>in</strong>es „try-catch“-Blocks folgen<strong>de</strong><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 <strong>de</strong>r E<strong>in</strong>gabe: java FloatDemo a b");<br />
System.out.pr<strong>in</strong>tln(e.getMessage());<br />
}<br />
}<br />
}<br />
1.3.2.2 Entwicklung von <strong>Java</strong>-Applets<br />
Die Entwicklung e<strong>in</strong>es Applets unterschei<strong>de</strong>t 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 an<strong>de</strong>ren Seitenelementen zusammen ausgeführt<br />
wer<strong>de</strong>n. Zur Ausführung e<strong>in</strong>es Applets ist es nötig, das Applet <strong>in</strong> e<strong>in</strong>em HTML-<br />
Dokument 35 e<strong>in</strong>zubetten. In diesem HTML-Dokument wer<strong>de</strong>n <strong>de</strong>m javafähigen<br />
Browser die Informationen mitgeteilt, die er zur Ausführung <strong>de</strong>s Applets benötigt. Der<br />
Browser lädt die Klassendatei und führt das Applet automatisch aus.<br />
Aus <strong>de</strong>r Sicht <strong>de</strong>s Programmierers ist das Applet e<strong>in</strong>e Klasse, die von <strong>de</strong>r Applet-<br />
Klasse abgeleitet wird.<br />
1. Aufgabe: Erstelle e<strong>in</strong> Applet, das <strong>in</strong> e<strong>in</strong>em Fenster <strong>de</strong>n Text „Herzlich<br />
Willkommen <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Welt“ ausgibt<br />
Lösungsschritte:<br />
1) Erstelle die folgen<strong>de</strong> Datei mit <strong>de</strong>m Namen „WillkommenApplet.java“ mit Hilfe<br />
e<strong>in</strong>es Dateiaufbereiters (Editor):<br />
35 e<strong>in</strong>e entsprechen<strong>de</strong> Referenz <strong>in</strong>nerhalb e<strong>in</strong>er HTML-Seite mit e<strong>in</strong>em speziellen Tag, <strong>de</strong>m -Tag<br />
erledigt die E<strong>in</strong>bettung <strong>in</strong> <strong>de</strong>n Browser<br />
34
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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> <strong>de</strong>r <strong>Java</strong> Welt!",5,25);<br />
}<br />
}<br />
Durch die „import“-Anweisung können Entwickler Klassen verwen<strong>de</strong>n, die <strong>in</strong><br />
an<strong>de</strong>ren Dateien <strong>de</strong>f<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“, <strong>de</strong>nn hier ist die Klasse Object enthalten, von <strong>de</strong>r<br />
alle <strong>Java</strong>-Klassen abgeleitet s<strong>in</strong>d. Die Graphics-Klasse enthält Metho<strong>de</strong>n zum<br />
Zeichnen von Textzeichen und Zeichenketten. Mit <strong>de</strong>r „drawstr<strong>in</strong>g“-Metho<strong>de</strong> <strong>de</strong>r<br />
Graphics-Klasse können Textzeichen auf <strong>de</strong>n Bildschirm gemalt wer<strong>de</strong>n.<br />
Die folgen<strong>de</strong> Abbildung zeigt die Mo<strong>de</strong>llierung 36 <strong>de</strong>s vorliegen<strong>de</strong>n Quellco<strong>de</strong>s:<br />
WillkommenApplet<br />
pa<strong>in</strong>t()<br />
g.drawStr<strong>in</strong>g<br />
(“Herzlich Willkommen <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Welt!“,5,25)<br />
Abb. 1.3-2: Klassendiagramm zu WillkommenApplet<br />
Die Klasse WillkommenApplet läßt sich grafisch als rechteckiges Symbol<br />
darstellen. Die pa<strong>in</strong>t()-Metho<strong>de</strong> 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> <strong>de</strong>r „extends“-Klausel<br />
angegeben. „extends java.applet.Applet“ bestimmt das die angegebene<br />
Applet-Klasse von <strong>de</strong>r Applet-Klasse <strong>de</strong>s Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit (AWT)<br />
abgeleitet ist. Der an<strong>de</strong>re Teil <strong>de</strong>r Klassen<strong>de</strong>f<strong>in</strong>ition enthält das Schlüsselwort<br />
„public“ mit <strong>de</strong>r Be<strong>de</strong>utung: Die Klasse ist nach <strong>de</strong>m La<strong>de</strong>n für das gesamte <strong>Java</strong>-<br />
System verfügbar. Applets müssen „public“ <strong>de</strong>klariert wer<strong>de</strong>n.<br />
Die folgen<strong>de</strong> Abbildung zeigt die Beziehungen <strong>de</strong>r Klasse WillkommenApplet zu<br />
ihren unmittelbaren Nachbarn:<br />
Applet<br />
WillkommenApplet<br />
pa<strong>in</strong>t()<br />
Graphics<br />
36 Die Mo<strong>de</strong>llierung erfolgt nach <strong>de</strong>n Regeln <strong>de</strong>r Unified Mo<strong>de</strong>ll<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 />
35
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb. 1.3-3: Die unmittelbare Umgebung von WillkommenApplet<br />
Die gerichtete L<strong>in</strong>ie mit <strong>de</strong>r 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 verwen<strong>de</strong>t Graphics.<br />
E<strong>in</strong> eigenes, vom Benutzer erstelltes Applet überschreibt gewöhnlich Metho<strong>de</strong>n, die<br />
<strong>in</strong> <strong>de</strong>r Superklasse Applet <strong>de</strong>f<strong>in</strong>iert s<strong>in</strong>d. Diese Metho<strong>de</strong>n übernehmen Aufgaben zur<br />
Initialisierung <strong>de</strong>s Applet vor <strong>de</strong>r Ausführung (public void start()), zur<br />
Reaktion auf Mause<strong>in</strong>gaben, zum Anhalten <strong>de</strong>s Applet (public void stop())<br />
und zu Aufräumungsarbeiten (public void <strong>de</strong>stroy()), wenn das Applet<br />
been<strong>de</strong>t wird. E<strong>in</strong>e dieser Metho<strong>de</strong>n ist pa<strong>in</strong>t(), die sich um die Anzeige <strong>de</strong>s<br />
Applet <strong>in</strong> e<strong>in</strong>er Webseite kümmert. Die pa<strong>in</strong>t()-Metho<strong>de</strong> besitzt e<strong>in</strong> e<strong>in</strong>ziges<br />
Argument, e<strong>in</strong>e Instanz <strong>de</strong>r Klasse Graphics. Die Klasse Graphics stellt<br />
Verhaltensweisen zur Darstellung von Schriften, Farben, zum Zeichnen von L<strong>in</strong>ien 37 ,<br />
von Ellipsen bzw. Kreisen 38 , von Rechtecken 39 und an<strong>de</strong>ren Formen zur Verfügung.<br />
In <strong>de</strong>r pa<strong>in</strong>t()-Metho<strong>de</strong> wur<strong>de</strong> hier <strong>de</strong>r Str<strong>in</strong>g "Herzlich Willkommen <strong>in</strong> <strong>de</strong>r<br />
<strong>Java</strong> Welt!" bei <strong>de</strong>n (x,y)-Koord<strong>in</strong>aten (5,25) ausgegeben. Der Ursprung <strong>de</strong>s<br />
Koord<strong>in</strong>atensystems liegt <strong>in</strong> <strong>de</strong>r l<strong>in</strong>ken oberen Ecke <strong>de</strong>s Darstellungsbereichs. Der<br />
Str<strong>in</strong>g wird <strong>in</strong> e<strong>in</strong>er <strong>de</strong>faultmäßig festgelegten Schrift und Farbe angezeigt.<br />
Die Untersuchung <strong>de</strong>r <strong>Java</strong>-Bibliotheken zu Applet und Graphics zeigt: Die bei<strong>de</strong>n<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 folgen<strong>de</strong> Klassendiagramm<br />
erhalten:<br />
Object<br />
ImageObserver<br />
Component<br />
Conta<strong>in</strong>er<br />
Panel<br />
Applet<br />
WillkommenApplet<br />
37 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 <strong>de</strong>n<br />
Anfangspunkt, (x2,y2) bestimmt <strong>de</strong>n Endpunkt <strong>de</strong>r L<strong>in</strong>ie.<br />
38 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 <strong>de</strong>r oberen l<strong>in</strong>ken Ecke <strong>de</strong>s die Ellipse umschreiben<strong>de</strong>n Rechtecks mit <strong>de</strong>r Höhe height und <strong>de</strong>r<br />
Breite width am<br />
39 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 <strong>de</strong>s Rechtecks, (width, height) legen Breite und Höhe <strong>de</strong>s Rechtecks fest.<br />
36
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb. 1.3-4: Vererbungshierarchie 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 <strong>de</strong>n Klassen Applet und Graphics unmittelbar<br />
zusammen. Diese bei<strong>de</strong>n Klassen bil<strong>de</strong>n lediglich e<strong>in</strong>en kle<strong>in</strong>en Ausschnitt aus <strong>de</strong>r<br />
Bibliothek mit vor<strong>de</strong>f<strong>in</strong>ierten <strong>Java</strong>-Klassen. Die Verwaltung dieser Klassen und<br />
Schnittstellen organisiert <strong>Java</strong> <strong>in</strong> mehreren verschie<strong>de</strong>nen Paketen. Das Wurzelpaket<br />
<strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Umgebung heißt java. In dieses Paket s<strong>in</strong>d mehrere weitere Pakete<br />
geschachtelt, die wie<strong>de</strong>rum an<strong>de</strong>re Pakete, Schnittstellen und Klassen enthalten.<br />
Object existiert im Paket lang, Panel, Conta<strong>in</strong>er, Component existieren im<br />
Paket awt, und die Klasse Applet im Paket applet. Die Schnittstelle<br />
ImageObserver existiert im Paket image, das liegt wie<strong>de</strong>rum im Paket awt<br />
(qualifizierter Name: java.awt.ImageObeserver). Die Paketstruktur 40 kann <strong>in</strong><br />
e<strong>in</strong>em Klassendiagramm visualisiert wer<strong>de</strong>n:<br />
java<br />
WillkommenApplet<br />
applet<br />
awt<br />
lang<br />
Abb. 1.3-5: Paketstruktur im WillkommenApplet<br />
2) Speichern <strong>de</strong>r Datei mit <strong>de</strong>m Namen „WillkommenApplet.java“ unter e<strong>in</strong>em<br />
beliebigen Verzeichnis.<br />
3) Aufruf <strong>de</strong>s <strong>Java</strong>-Übersetzers über die folgen<strong>de</strong> 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 <strong>de</strong>r folgen<strong>de</strong>n HTML-Datei „WillkommenApplet.html“, anschließend<br />
Speichern dieser Datei.<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 <strong>de</strong>m -Tag. Das<br />
Co<strong>de</strong>-Attribut dient zur Angabe von <strong>de</strong>m Namen <strong>de</strong>r Klasse, die das Applet enthält.<br />
40 Pakete wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r UML als Akten mit Reitern dargestellt. Die gestrichelten Pfeile repräsentieren die<br />
Abhängigkeiten zwischen <strong>de</strong>n Paketen.<br />
37
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Attribute WIDTH und HEIGHT dienen zum Bestimmen <strong>de</strong>r Größe <strong>de</strong>s Applets.<br />
Der Browser benutzt diese Werte zur Zuteilung <strong>de</strong>s Raums, <strong>de</strong>r für das Applet auf<br />
<strong>de</strong>r Seite freigehalten wer<strong>de</strong>n muß. Hier wur<strong>de</strong> e<strong>in</strong>e Box mit e<strong>in</strong>er Breite von 200 und<br />
e<strong>in</strong>er Höhe von 50 Pixeln <strong>de</strong>f<strong>in</strong>iert.<br />
WillkommenApplet ist als Applet implementiert. Es kann nie isoliert stehen, son<strong>de</strong>rn<br />
ist normalerweise Teil e<strong>in</strong>er Webseite.<br />
WillkommenApplet.java<br />
WillkommenApplet.html<br />
WillkommenApplet.class<br />
Abb. 1.3-6: Die Komponenten von WillkommenApplet<br />
5) Ausführung <strong>de</strong>s Applet mit e<strong>in</strong>em javafähigen Web-Browser bzw. <strong>de</strong>m<br />
Appletviewer, z.B. mit <strong>de</strong>m Aufruf „appletviewer WillkommenApplet.html“. Das<br />
Resultat müßte so aussehen:<br />
Abb. 1.3-7: Darstellung <strong>de</strong>s Fensters mit <strong>de</strong>m Appletviewer<br />
In e<strong>in</strong>em Browser wür<strong>de</strong> zusätzlich <strong>de</strong>r Text rund um das Applet („Me<strong>in</strong> <strong>Java</strong><br />
Applet sagt:“) gezeigt wer<strong>de</strong>n.<br />
2. Aufgabe: Verän<strong>de</strong>rn von Schrift und Farbe für <strong>de</strong>n Text „Herzlich Willkommen<br />
<strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Welt“.<br />
Lösungsschritte:<br />
1) Erweitere die Datei mit <strong>de</strong>m Namen „WillkommenApplet.java“ mit Hilfe e<strong>in</strong>es<br />
Dateiaufbereites (Editor).<br />
Die erste Erweiterung soll die Schrift verän<strong>de</strong>rn, <strong>in</strong> <strong>de</strong>r <strong>de</strong>r Text ausgegeben wird. Es<br />
wird e<strong>in</strong> Objekt <strong>de</strong>r Klasse java.awt.Font über folgen<strong>de</strong> Anweisung erzeugt: Font f<br />
= new Font("TimesRoman",Font.BOLD,12);<br />
Objekte <strong>de</strong>r Klasse Font dienen zum Bereitstellen verschie<strong>de</strong>ner Schriftarten für die<br />
Metho<strong>de</strong> drawStr<strong>in</strong>g() und repräsentieren <strong>de</strong>n Namen, <strong>de</strong>n Stil und die Größe<br />
e<strong>in</strong>er Schrift. Mit e<strong>in</strong>em spezifischen Objekt <strong>de</strong>r Klasse Font kann man e<strong>in</strong>e Schrift<br />
aufrufen, die sich von <strong>de</strong>r standardmäßig <strong>in</strong> Applets benutzten Schrift unterschei<strong>de</strong>t.<br />
Dem Font-Objekt wird hier die Schrift „TimesRoman“, fett <strong>in</strong> „12-Punkt“ Größe<br />
38
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
zugewiesen. Das neue Objekt wird anschließend <strong>de</strong>r Instanzvariablen f zugewiesen<br />
und ist so <strong>de</strong>r Metho<strong>de</strong> pa<strong>in</strong>t() zugänglich:<br />
public void pa<strong>in</strong>t (Graphics g)<br />
{<br />
// Mitteilung: Die Schrift zur Anzeige von Text bef<strong>in</strong><strong>de</strong>t sich <strong>in</strong> <strong>de</strong>r<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 <strong>de</strong>n Text, <strong>de</strong>r<br />
// aus e<strong>in</strong>em Rechteck mit abgerun<strong>de</strong>ten 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 <strong>de</strong>r Klasse Color fuer die Farbe rot<br />
g.setColor(Color.red);<br />
// Mitteilung: Text wird <strong>in</strong> festgelegter Schrift und Farbe bei <strong>de</strong>n<br />
// (x,y)-Koord<strong>in</strong>aten (5,25) ausgegeben.<br />
g.drawStr<strong>in</strong>g("Herzlich Willkommen <strong>in</strong> <strong>de</strong>r <strong>Java</strong> Welt!",5,25);<br />
}<br />
Die Klassen Font und Color wer<strong>de</strong>n über die folgen<strong>de</strong>n 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 <strong>de</strong>s Applet, z.B. über <strong>de</strong>n Aufruf appletviewer<br />
WillkommenApplet.html.<br />
3. Aufgabe: Erweitere das Applet <strong>de</strong>r 1. Aufgabe um e<strong>in</strong>en Dokumentationskommentar<br />
<strong>Java</strong> kennt verschie<strong>de</strong>ne Kommentarzeichen<br />
- für die <strong>in</strong>terne Dokumentation: // und die Komb<strong>in</strong>ation /* ... */<br />
- für die externe Dokumentation: //** ... */<br />
Grundsätzlich steht <strong>de</strong>r Dokumentationskommentar vor Klassen, (Interfaces,<br />
Konstruktoren,) Metho<strong>de</strong>n, z.B. 42 :<br />
/* Das erste <strong>Java</strong> Applet */<br />
import java.awt.Graphics;<br />
/** Dieses Applet <strong>de</strong>monstriert <strong>de</strong>n Grundaufbau von Applets.<br />
*** @author Juergen Sauer<br />
*** @version WS 2001/2002<br />
*** @see WillkommenApplet01<br />
*/<br />
public class WillkommenApplet01 extends java.applet.Applet<br />
{<br />
/** Die Metho<strong>de</strong> pa<strong>in</strong>t ist von Component geerbt<br />
*** Sie wird aufgerufen, wenn das Applet neu gezeichnet wer<strong>de</strong>n muss;.<br />
41 Diese Anweisung stellt alle Klassen <strong>de</strong>s Pakets java.awt zur Verfügung<br />
42 pr13210<br />
39
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
*** @param g E<strong>in</strong>e Referenz e<strong>in</strong>es Grafikobjekts<br />
*/<br />
public void pa<strong>in</strong>t (Graphics g)<br />
{<br />
g.drawStr<strong>in</strong>g("Herzlich Willkommen <strong>in</strong> <strong>de</strong>r <strong>Java</strong> Welt!",5,25);<br />
}<br />
}<br />
Das Programm, das e<strong>in</strong>en <strong>de</strong>rartigen Quellco<strong>de</strong> zu e<strong>in</strong>er HTML-Dokumentation<br />
verarbeitet, heißt javadoc.exe und ist im <strong>Java</strong>-SDK von Sun 43 enthalten.<br />
Aufrufsyntax: javadoc [flags] [klasse|package]<br />
Für „flags“ kann * o<strong>de</strong>r folgen<strong>de</strong> Schalter angegeben wer<strong>de</strong>n:<br />
-version<br />
-author<br />
-sourcepath<br />
-classpath<br />
-doctype<br />
-no<strong>in</strong><strong>de</strong>x<br />
-notree<br />
@version berücksichtigen<br />
@author berücksichtigen<br />
Suchpfad für Klassen<br />
Synonym für sourcepath<br />
Ausgabetyp (Standard: html)<br />
Ke<strong>in</strong> Verzeichnis aller Konstruktoren und Metho<strong>de</strong>n erzeugen<br />
Ke<strong>in</strong>e <strong>Java</strong>-Klassenhierarchie erzeugen<br />
Falls das vorliegen<strong>de</strong> Beispiel mit javadoc –author –version –notree –<br />
no<strong>in</strong><strong>de</strong>x WillkommenApplet01.java aufgerufen wird, erzeugt das Programm<br />
e<strong>in</strong>e Datei WillkommenApplet01.html, die Auswertungen <strong>de</strong>r <strong>Java</strong>-API zeigt und<br />
<strong>de</strong>n Kommentar, z. B.:<br />
43 siehe auch: http://java.sun.com/javadoc/<br />
40
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb. 1.3-8: Ausschnitt zum über javadoc erzeugten Dokument<br />
4. Aufgabe: Überwachen <strong>de</strong>s 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, son<strong>de</strong>rn empfängt<br />
Ereignisse vom System und liefert Ergebnisse zurück. Beim Start e<strong>in</strong>es Applet ruft<br />
<strong>de</strong>r Webbrowser die Metho<strong>de</strong> <strong>in</strong>it() <strong>de</strong>s Appletobjekts auf. Beim Been<strong>de</strong>n e<strong>in</strong>es<br />
Applets wird die Metho<strong>de</strong> <strong>de</strong>stroy() aufgerufen. <strong>in</strong>it() und <strong>de</strong>stroy() wer<strong>de</strong>n im<br />
Lebenszyklus e<strong>in</strong>es Applet genau e<strong>in</strong>mal ausgeführt, nämlich beim Erzeugen bzw.<br />
beim Been<strong>de</strong>n e<strong>in</strong>es Objekts. Zusätzlich s<strong>in</strong>d zwei weitere Metho<strong>de</strong>n start() und<br />
stop() vorgesehen, die an verschie<strong>de</strong>nen Stellen zur Aktivierung aufgerufen wer<strong>de</strong>n<br />
können. Wählt e<strong>in</strong> Anwen<strong>de</strong>r bei gestartetem Applet z.B. im Browser e<strong>in</strong>e an<strong>de</strong>re<br />
Internetseite an, so ruft <strong>de</strong>r Browser die stop()-Rout<strong>in</strong>e auf und hält das Applet an,<br />
bis <strong>de</strong>r Anwen<strong>de</strong>r wie<strong>de</strong>r auf die Appletseite zurückkehrt. Dann ruft <strong>de</strong>r Browser die<br />
start()-Rout<strong>in</strong>e zum ordnungsgemäßen Fortsetzen <strong>de</strong>s Applet auf.<br />
import java.awt.*;<br />
import java.applet.*;<br />
41
<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 />
// Metho<strong>de</strong>n<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 />
// <strong>de</strong>s Applet wird <strong>de</strong>r Str<strong>in</strong>g s mit Hilfe <strong>de</strong>s Opertors + aus<br />
// Teilstr<strong>in</strong>gs zusammengesetzt. Ganze Zahlen wer<strong>de</strong>n 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<br />
verlässt<br />
Browser<br />
schliesst<br />
Browser<br />
<br />
<strong>in</strong>it()<br />
start()<br />
pa<strong>in</strong>t()<br />
stop()<br />
<strong>de</strong>stroy()<br />
:Applet<br />
Abb.: Lebenszyklus e<strong>in</strong>es Applets<br />
5. Aufgabe: Entwickle aus <strong>de</strong>r vorliegen<strong>de</strong>n 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 folgen<strong>de</strong> Gerüst beschreibt e<strong>in</strong> Muster für alle Applets:<br />
// Name <strong>de</strong>r Klasse:<br />
// Beschreibung:<br />
// Import <strong>de</strong>r Pakete<br />
// import java.lang.*;<br />
// import java.applet.*;<br />
// import java.awt.*;<br />
// Top-Level-Klassen-Deklaration bzw. Def<strong>in</strong>ition <strong>de</strong>s Applets<br />
public Klassenname extends java.applet.Applet<br />
42
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
// Variablen-Deklarationen bzw. Def<strong>in</strong>itionen<br />
// ...<br />
// Eigene Metho<strong>de</strong>n<br />
// ...<br />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<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 <strong>de</strong>stroy()<br />
{<br />
// ...<br />
}<br />
// Optional: die Ausgabemetho<strong>de</strong><br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
// ..<br />
}<br />
}<br />
E<strong>in</strong> Applet erbt Metho<strong>de</strong>n und Variablen <strong>de</strong>r Applet-Klasse. Die Applet-Klasse erbt<br />
wie<strong>de</strong>rum von e<strong>in</strong>er Reihe an<strong>de</strong>rer Klassen. E<strong>in</strong>e Klasse, die<br />
java.applet.Applet erweitert, kann Variablen und Metho<strong>de</strong>n aus<br />
java.lang.Object, java.awt.Component, java.awt.Conta<strong>in</strong>er sowie<br />
java.awt.Panel verwen<strong>de</strong>n.<br />
1.3.3 Programmablaufpläne und Strukturierte Programmierung<br />
1.3.3.1 Darstellung von Algorithmen durch Programmablaufpläne<br />
Komposition<br />
Aus e<strong>in</strong>er Anweisungsfolge 44 (mit n ∈ N ) „anweisung 1 anweisung 2 ... anweisung n “<br />
konstuiert man durch Klammerung mit { und } e<strong>in</strong>e Anweisung, die Komposition <strong>de</strong>r<br />
Anweisungen <strong>de</strong>r Folge<br />
{ anweisung 1 anweisung 2 ... anweisung n }<br />
Die Anweisungen wer<strong>de</strong>n nache<strong>in</strong>an<strong>de</strong>r <strong>in</strong> <strong>de</strong>r angegebenen Reihenfolge ausgeführt.<br />
Die Klammern umschließen e<strong>in</strong>en Block, <strong>in</strong> <strong>de</strong>m Variablen neu bzw. lokal vere<strong>in</strong>bart<br />
wer<strong>de</strong>n können.<br />
44 vgl. 2.4.1<br />
43
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
In Programmabläufplänen wer<strong>de</strong>n Anweisungen <strong>in</strong> Anweisungsknoten (Symbol:<br />
Kästchen) dargestellt.<br />
Abb.: Anweisungsknoten<br />
Neben Anweisungsknoten gibt es <strong>in</strong> Prgrammablaufplänen Testknoten. Sie wer<strong>de</strong>n<br />
mit e<strong>in</strong>em Rhombus symbolisiert. Testknoten enthalten Tests. Ist die Bed<strong>in</strong>gung<br />
erfüllt bestimmt <strong>de</strong>r mit „true“ bewertete Pfeil <strong>de</strong>n nächsten Knoten. An<strong>de</strong>renfalls <strong>de</strong>r<br />
mit „false“ bewertete.<br />
Abb.: Testknoten<br />
Daneben gibt es noch <strong>in</strong>itale und f<strong>in</strong>ale Knoten:<br />
Abb.: Initialer bzw. f<strong>in</strong>aler Knoten<br />
Bed<strong>in</strong>gte Anweisung 45<br />
<strong>Java</strong>-Notation: if (bed<strong>in</strong>gung) anweisung<br />
Programmablaufplan:<br />
true<br />
false<br />
Abb.: Bed<strong>in</strong>gte Anweisung<br />
Verzweigungsanweisung<br />
<strong>Java</strong>-Notation: if (bed<strong>in</strong>gung) anweisung1 else anweisung2<br />
45 vgl. 2.4.6<br />
44
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Programmablaufplan:<br />
true<br />
false<br />
Abb.: Verzweigungsannweisung<br />
Endgeprüfte Schleife 46<br />
<strong>Java</strong>-Notation: // Vorbed<strong>in</strong>gung<br />
do<br />
anweisung<br />
// Invariante<br />
while (bed<strong>in</strong>gung)<br />
// Nachbed<strong>in</strong>gung<br />
Programmablaufplan:<br />
true<br />
false<br />
Abb.: Endgeprüfte Schleife<br />
Anfangsgeprüfte Schleife 47<br />
<strong>Java</strong>-Notation: // Vorbed<strong>in</strong>gung<br />
while (bed<strong>in</strong>gung)<br />
// Invariante<br />
anweisung<br />
// Nachbed<strong>in</strong>gung<br />
46 vgl. 2.4.7<br />
47 vgl. 2.4.7<br />
45
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Programmablaufplan:<br />
false<br />
true<br />
Abb.: Anfangsgeprüfte Schleife<br />
Bsp.: Flussdiagramm zur Berechnung <strong>de</strong>s größten geme<strong>in</strong>samen Teilers von m und<br />
n.<br />
Start<br />
x = m<br />
y = n<br />
T<br />
x == y<br />
F<br />
z = x<br />
x > y<br />
En<strong>de</strong> x = x – y y = y - x<br />
1.3.3.2 Darstellung von Algorithmen mit Struktogrammen<br />
Je<strong>de</strong>s Programm kann mit drei Grundstrukturen realisiert wer<strong>de</strong>n:<br />
- Sequenz (Komposition)<br />
Bei e<strong>in</strong>er Sequenz wer<strong>de</strong>n die Anweisungen nache<strong>in</strong>an<strong>de</strong>r, <strong>de</strong>r Reihe nach, durchgeführt.<br />
- Fallunterscheidung<br />
Hier wird aufgrund e<strong>in</strong>er Bed<strong>in</strong>gung e<strong>in</strong>er von 2 Fällen ausgewertet.<br />
- Schleife<br />
46
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bei e<strong>in</strong>er Schleife wird e<strong>in</strong>e Verarbeitung wie<strong>de</strong>rholt durchgeführt, solange e<strong>in</strong>e Bed<strong>in</strong>gung erfüllt ist.<br />
Programme, die aus diesen Grundstrukturen aufgebaut s<strong>in</strong>d, nennt man strukturierte<br />
Programme 48 . Zum Programmentwurf nach <strong>de</strong>r Metho<strong>de</strong> <strong>de</strong>r "strukturierten<br />
Programmierung" gehört das Pr<strong>in</strong>zip <strong>de</strong>r schrittweisen Verfe<strong>in</strong>erung (stepwise<br />
ref<strong>in</strong>ement). Man beg<strong>in</strong>nt mit e<strong>in</strong>em Grobansatz und verfe<strong>in</strong>ert schrittweise 49 . Dabei<br />
wird die Gesamtaufgabe <strong>in</strong> Teilaufgaben aufgeteilt, die unabhängig vone<strong>in</strong>an<strong>de</strong>r<br />
entwickelt wer<strong>de</strong>n können (Modularisierung).<br />
1. Die Sequenz (Komposition)<br />
Aus e<strong>in</strong>er Anweisungsfolge 50 (mit n ∈ N ) „anweisung 1 anweisung 2 ... anweisung n “<br />
konstuiert man durch Klammerung mit { und } e<strong>in</strong>e Anweisung, die Komposition <strong>de</strong>r<br />
Anweisungen <strong>de</strong>r Folge<br />
{ anweisung 1 anweisung 2 ... anweisung n }<br />
Die Anweisungen wer<strong>de</strong>n nache<strong>in</strong>an<strong>de</strong>r <strong>in</strong> <strong>de</strong>r angegebenen Reihenfolge ausgeführt.<br />
Die Klammern umschließen e<strong>in</strong>en Block, <strong>in</strong> <strong>de</strong>m Variablen neu bzw. lokal vere<strong>in</strong>bart<br />
wer<strong>de</strong>n können.<br />
In Programmabläufplänen wer<strong>de</strong>n Anweisungen <strong>in</strong> Anweisungsknoten (Symbol:<br />
Kästchen) dargestellt.<br />
Abb.: Anweisungsknoten<br />
2. Die Selektion (Fallunterscheidung)<br />
Bei e<strong>in</strong>er Sektion wird aufgrund e<strong>in</strong>er Bed<strong>in</strong>gung entschie<strong>de</strong>n 51 , welches <strong>de</strong>r bei<strong>de</strong>n<br />
Anweisungen durchgeführt wird, z.B.:<br />
if (n > 0)<br />
System.out.pr<strong>in</strong>tln("positiv");<br />
else<br />
System.out.pr<strong>in</strong>tln("kle<strong>in</strong>er o<strong>de</strong>r gleich 0");<br />
48 Entschei<strong>de</strong>n<strong>de</strong>r Punkt: Verbannung <strong>de</strong>s Sprungbefehls "goto" aus <strong>de</strong>n Programmen (zentrale Ursache für<br />
undurchsichtige Programme).<br />
49 Top Down Pr<strong>in</strong>zip<br />
50 vgl. 2.4.1<br />
51 vgl. 2.4.6<br />
47
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Allgeme<strong>in</strong>es Format<br />
if (bed<strong>in</strong>gung)<br />
true false statementA;<br />
else<br />
statemebtB;<br />
statementA<br />
statementB<br />
Abb.: Graf. Darstellung e<strong>in</strong>es Struktugramms für e<strong>in</strong>e Selektion<br />
In e<strong>in</strong>em if-Statement, kann <strong>de</strong>r else-Teil wegfallen. Falls <strong>in</strong> if- o<strong>de</strong>r im else-<br />
Zweig mehrere Anweisungen durchzuführen s<strong>in</strong>d, müssen diese mit geschweiften<br />
Klammern als zusammengesetztes Statement geschrieben wer<strong>de</strong>n.<br />
Aufbau von Bed<strong>in</strong>gungen (Boolesche Ausdrücke) 52 : Die <strong>in</strong> Fallunterscheidungen<br />
auftreten<strong>de</strong> Bed<strong>in</strong>gung ist e<strong>in</strong> Boolescher Ausdruck, d.h. e<strong>in</strong> Ausdruck mit <strong>de</strong>n<br />
möglichen Werten true o<strong>de</strong>r false. Boolesche Ausdrücke s<strong>in</strong>d aufgebaut aus:<br />
- Vergleichsoperatoren<br />
< kle<strong>in</strong>er<br />
groesser<br />
>= groesser o<strong>de</strong>r gleich<br />
== gleich<br />
!= ungleich<br />
- logischen Verknüpfungen<br />
&& Und-Verknüpfung<br />
|| O<strong>de</strong>r-Verknüpfung<br />
! Negation<br />
- Klammern ()<br />
Typen-Konversionen bei Vergleichen: Bei Vergleichen wer<strong>de</strong>n (wie <strong>in</strong> algebraischen<br />
Ausdrücken) automatisch erfor<strong>de</strong>rliche Typen-Konversionen durchgeführt, sodass<br />
"<strong>in</strong>t" mit "float" usw. mite<strong>in</strong>an<strong>de</strong>r verglichen wer<strong>de</strong>n kann.<br />
Verschachtelte if-Statements: In verschachtelten if-Anweisungen bezieht sich e<strong>in</strong><br />
"else" immer auf das nächste "if".<br />
true n > 0 false <strong>in</strong>t n;<br />
if ( n > 0)<br />
n == 0<br />
System.out.pr<strong>in</strong>tln("positiv");<br />
true false else<br />
"positiv" if (n == 0)<br />
System.out.pr<strong>in</strong>tln("null");<br />
"null" "negativ" else<br />
System.out.pr<strong>in</strong>tln("negativ");<br />
Das switch-Statement: Für Mehrfach-Fallunterscheidungen, welche aufgrund e<strong>in</strong>es<br />
ganzzahligen Werts erfolgen, stellt <strong>Java</strong> e<strong>in</strong> übersichtliches Statement zur<br />
Verfügung, das switch-Statement 53 , z.B.:<br />
52 vgl. 2.3.5<br />
53 vgl. 2.4.6<br />
48
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
<strong>in</strong>t wochentag;<br />
switch (wochentag)<br />
{<br />
case 0: System.out.pr<strong>in</strong>tln("Sonntag");<br />
break;<br />
case 1: System.out.pr<strong>in</strong>tln("Montag");<br />
break;<br />
case 2: System.out.pr<strong>in</strong>tln("Dienstag"),<br />
break;<br />
…<br />
case 6: System.out.pr<strong>in</strong>tln("Samstag");<br />
break;;<br />
<strong>de</strong>fault: System.out.pr<strong>in</strong>tln("ungueltiger Tag");<br />
}<br />
3. Schleifen<br />
Man unterschei<strong>de</strong>t drei Arten von Schleifen.<br />
- "while"-Schleife 54<br />
Bei e<strong>in</strong>er while-Schleife wird die Aktion wie<strong>de</strong>rholt durchgeführt, solange e<strong>in</strong>e bestimmte Bed<strong>in</strong>gung<br />
erfüllt ist (Fortsetzungsbed<strong>in</strong>gung). Die Bed<strong>in</strong>gung wird bei je<strong>de</strong>m Durchgang vor <strong>de</strong>r Durchführung<br />
<strong>de</strong>r Aktion geprüft.<br />
- Zählschleifen ("for"-Schleifen)<br />
Bei e<strong>in</strong>er Zählschleife wird e<strong>in</strong> Zähler (die sog. Laufvariable) verwen<strong>de</strong>t. Die Aktion <strong>de</strong>r Schleife wird<br />
für je<strong>de</strong>n Wert <strong>de</strong>r Laufvariablen von e<strong>in</strong>em Anfangswert bis (<strong>in</strong>klusive) e<strong>in</strong>em Endwert durchgeführt.<br />
- "do-while"-Schleifen<br />
Diese Schleifen funktionieren wie die "while"-Schleifen mit <strong>de</strong>m Unterschied, dass die<br />
Fortsetzungsbed<strong>in</strong>gung bei je<strong>de</strong>m Durchgang nach <strong>de</strong>r Aktion geprüft wird.<br />
1. while-Schleifen (Anfangsgeprüfte Schleifen)<br />
solange bed<strong>in</strong>gung erfuellt<br />
while (bed<strong>in</strong>gung)<br />
{<br />
statement;<br />
statement<br />
…<br />
.... …<br />
statement<br />
statement;<br />
.... ….<br />
statement<br />
…<br />
}<br />
2. for-Schleifen 55 , z.B.:<br />
<strong>in</strong>t i;<br />
for (i = 0; i < 100; i++)<br />
{<br />
54 vgl. 2.4.7<br />
55 vgl. 2.4.7<br />
49
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
System.out.pr<strong>in</strong>t("Durchlauf: ");<br />
System.out.pr<strong>in</strong>tln(i);<br />
}<br />
Lokale Laufvariablen: Im Initialisierungs-Statement e<strong>in</strong>er for-Anweisung kann e<strong>in</strong>e<br />
Laufvariable direkt durch e<strong>in</strong>e vorangestellte Typangabe <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n.<br />
Bsp.: Berechnung <strong>de</strong>r ersten 100000 Glie<strong>de</strong>r <strong>de</strong>r Harmonischen Reihe<br />
double summe = 0;<br />
for (<strong>in</strong>t i = 0; i < 100000; i++)<br />
summe += 1.0 / i;<br />
System.out.pr<strong>in</strong>tln("Summe: " + summe);<br />
3. do-while-Schleifen 56 (Endgeprüfte Scheifen)<br />
do<br />
statement; {<br />
…<br />
statement;<br />
… ....<br />
statement;<br />
statement;<br />
} while (bed<strong>in</strong>gung)<br />
solange bed<strong>in</strong>gung erfuellt<br />
Bei e<strong>in</strong>er do-while-Anweisung wer<strong>de</strong>n die Anweisungen <strong>de</strong>r Schleife m<strong>in</strong><strong>de</strong>stens<br />
e<strong>in</strong>mal durchgeführt.<br />
Bsp.: Ausgabe <strong>de</strong>r Ziffern e<strong>in</strong>er nicht negativen, ganzen Zahl<br />
do<br />
{<br />
System.out.pr<strong>in</strong>tln(n % 10);<br />
n = n / 10;<br />
} while (n > 0);<br />
4. Been<strong>de</strong>n e<strong>in</strong>es Programms<br />
Mit <strong>de</strong>m Statement System.exit(0) kann e<strong>in</strong> Programm an e<strong>in</strong>er beliebigen Stelle<br />
been<strong>de</strong>t wer<strong>de</strong>n. Dabei wird e<strong>in</strong> Return-Co<strong>de</strong> ausgegeben (0 für normale En<strong>de</strong>).<br />
Dieser Co<strong>de</strong> kann bei Bedarf auf Betriebssystem-Ebene verwertet wer<strong>de</strong>n.<br />
5. Bsp.:<br />
1. BubbleSort<br />
56 vgl. 2.4.7<br />
50
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
swapped = false<br />
swapped = false<br />
Schleife über Arrayposition i von 0 bis Arraylänge - 1<br />
swap(a,i,i+1)<br />
array[i] > array[i+1]<br />
swapped?<br />
swapped = true<br />
2. Suche nach <strong>de</strong>m ersten Vorkommen von Musterzeichenfolge pattern[0..m-1]<br />
<strong>in</strong> Textzeichenfolge text[0..n-1]<br />
Ansatz: Ab je<strong>de</strong>r Position i prügfen, ob <strong>de</strong>r Test text[i..i + (m – 1)] mit <strong>de</strong>m<br />
Muster pattern übere<strong>in</strong>stimmt.<br />
letztes-bearbeitungswürdiges-Zeichen = textLaenge - musterLaenge<br />
Schleife über alle bearbeitungswürdigen Zeichenpositionen i im Text<br />
Str<strong>in</strong>g substr = Substr<strong>in</strong>g im Text von Postion i bis i + Musterlänge<br />
substr stimmt mit Muster übere<strong>in</strong><br />
return: i<br />
return: -1<br />
Implementierung:<br />
public static <strong>in</strong>t search(Str<strong>in</strong>g text, Str<strong>in</strong>g pattern)<br />
{<br />
f<strong>in</strong>al <strong>in</strong>t last = text.length() - pattern.length();<br />
for (<strong>in</strong>t i = 0; i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.3.4 Datentyp und Datenstruktur<br />
Zum Umgang e<strong>in</strong>es Programms mit Werten benötigt man Variable. E<strong>in</strong>e Variable ist<br />
e<strong>in</strong> Bezeichnung, unter <strong>de</strong>r Daten im Speicher gehalten wer<strong>de</strong>n. Variable müssen vor<br />
<strong>de</strong>r ersten Verwendung vere<strong>in</strong>bart (<strong>de</strong>klariert) wer<strong>de</strong>n und e<strong>in</strong>en bestimmten<br />
Datentyp besitzen, z.B.:<br />
double a = 2.7;<br />
double b = 3.5;<br />
"a" und "b" tragen jeweils ihren eigenen Wert <strong>in</strong> sich und s<strong>in</strong>d Variable von e<strong>in</strong>em primitiven<br />
(elementaren, skalaren) Datentyp.<br />
Werte von e<strong>in</strong>em primitiven Typ<br />
- wer<strong>de</strong>n bereits bei <strong>de</strong>r Variablen<strong>de</strong>f<strong>in</strong>tion angelegt<br />
- haben e<strong>in</strong>e Literaldarstellung<br />
- können Parameter- und Rückgabewert bei Metho<strong>de</strong>n se<strong>in</strong><br />
- können mit Operatoren verknüpft wer<strong>de</strong>n.<br />
<strong>Java</strong> besitzt acht primitive Datentypen 57 :<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 Unico<strong>de</strong> 0 Unico<strong>de</strong> 2 16 -1 Character<br />
byte 8-Bit -128 +128 Byte<br />
short 16-Bit -2 15 +2 15 -1 Short<br />
<strong>in</strong>t 32-Bit -2 31 +2 31 -1 Integer<br />
long 64-Bit -2 63 +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 />
Abb.:<br />
Datentyp<br />
ist bestimmt durch<br />
- e<strong>in</strong>e Menge von Daten (Werte)<br />
- e<strong>in</strong>e Menge von Operationen auf diesen Daten<br />
Datenstruktur<br />
ist e<strong>in</strong> Datentyp mit folgen<strong>de</strong>n Eigenschaften<br />
1. Die besteht aus mehreren Datenelementen. Diese können<br />
57 vgl. 2.2.1<br />
52
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- atomare Datentypen o<strong>de</strong>r<br />
- selbst Datenstrukturen se<strong>in</strong><br />
2. Sie setzt die Elemente durch e<strong>in</strong>e Menge von Regeln (e<strong>in</strong>e Struktur) <strong>in</strong> e<strong>in</strong>e Beziehung (Relation).<br />
Exemplare (Instanzen, Objekte) von e<strong>in</strong>em Referenzdatentyp müssen (fast immer)<br />
explizit mit new und e<strong>in</strong>em Konstruktor angefor<strong>de</strong>rt wer<strong>de</strong>n.<br />
Elementare Strukturrelationen:<br />
Menge<br />
l<strong>in</strong>eare Struktur (gerichtete 1:1-Relation)<br />
Baum (hierarchisch)<br />
(gerichtete 1 : n – Relation)<br />
Graph (Netzwerk)<br />
( n : m Relation)<br />
Datenstrukturen dienen zur Organisation von Daten, um bestimmte Operationen<br />
(effizient) zu unterstützen. E<strong>in</strong>fache Datenstrukturen, die von Programmiersprachen<br />
unterstützt wer<strong>de</strong>n, s<strong>in</strong>d vor allem: Arrays (Fel<strong>de</strong>r), Records (Datensätze), Sets, Files<br />
(Dateien). In <strong>Java</strong> s<strong>in</strong>d es: Array und File.<br />
Array: E<strong>in</strong> Array (Reihung) ist e<strong>in</strong>e Datenstruktur fester Größe, die aus Elementen<br />
gleichen Typs aufgebaut ist. Diese s<strong>in</strong>d über Indizes zugreifbar. Indizes stehen <strong>in</strong><br />
e<strong>in</strong>er 1:1 Relation zu <strong>de</strong>n Elementen: Je<strong>de</strong>r In<strong>de</strong>xwert i<strong>de</strong>ntifiziert genau e<strong>in</strong>e<br />
Komponente.<br />
Für Arrays <strong>in</strong> <strong>Java</strong> 58 gilt bzgl.<br />
- Deklaration von Referenzvariablen auf Arrays, z.B.: <strong>in</strong>t e<strong>in</strong>Feld[]; <strong>in</strong>t[]<br />
auche<strong>in</strong>Feld;<br />
- Speicheranfor<strong>de</strong>rung. Es gibt mehrere Möglichkeiten<br />
- mit new, z.B. <strong>in</strong>t [] feld = new <strong>in</strong>t[20]<br />
- Initialisierung mit Literalen, z.B.: <strong>in</strong>t [] feld = {5,23,2};<br />
- Zuweisung (ohne erneutes Bereitstellen von Speicher), z.B. <strong>in</strong>t [] e<strong>in</strong>An<strong>de</strong>resFeld = feld;<br />
- Zugriff auf Fel<strong>de</strong>lement, z.B feld[<strong>in</strong><strong>de</strong>x]<br />
Files (Dateien): E<strong>in</strong>e Datei ist e<strong>in</strong>e geordnete endliche Folge e<strong>in</strong>es gegebenen<br />
Datentyps, wobei auf alle Elemente sequentiell zugegriffen wer<strong>de</strong>n kann:<br />
- alle Elemente s<strong>in</strong>d vom gleichen Typ<br />
58 vgl. 2.2.3<br />
53
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- Struktur zwischen <strong>de</strong>n Elementenm ist l<strong>in</strong>ear<br />
Das Lesen aus e<strong>in</strong>er Datei und Schreiben <strong>in</strong> e<strong>in</strong>e Datei erfolgt <strong>in</strong> <strong>Java</strong> 59 mit <strong>de</strong>n<br />
Klassen FileRea<strong>de</strong>r bzw. FileWriter. FileRea<strong>de</strong>r ist e<strong>in</strong> Datei-Strom und e<strong>in</strong>e<br />
Subklasse von InputStreamRea<strong>de</strong>r. Die Angabe von Dateien kann über Objekte<br />
<strong>de</strong>r Klasse File 60 o<strong>de</strong>r (plattformspezifische) Date<strong>in</strong>amen als Str<strong>in</strong>gs erfolgen.<br />
Bsp. 61 :<br />
import java.io.*;<br />
public class Kopie<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args) throws IOException<br />
{<br />
File e<strong>in</strong>gabeDatei = new File(".","Kopie.java");<br />
File ausgabeDatei = new File("Kopie.txt");<br />
FileRea<strong>de</strong>r e<strong>in</strong> = new FileRea<strong>de</strong>r(e<strong>in</strong>gabeDatei);<br />
FileWriter aus = new FileWriter(ausgabeDatei);<br />
<strong>in</strong>t c;<br />
while ((c = e<strong>in</strong>.read()) != -1) aus.write(c);<br />
e<strong>in</strong>.close(); aus.close();<br />
}<br />
}<br />
Beliebige Rea<strong>de</strong>r-Objekte können <strong>in</strong> e<strong>in</strong>en BufferedRea<strong>de</strong>r gesteckt wer<strong>de</strong>n,<br />
z.B. auch FileRea<strong>de</strong>r-Objekte. (anolog gilt das für Writer bzw. Byte-Ströme):<br />
Bsp. 62 :<br />
import java.io.*;<br />
public class BufferedDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args) throws IOException<br />
{<br />
File e<strong>in</strong>gabeDatei = new File(".","BufferedDEmo.java");<br />
File ausgabeDatei = new File("BufferedDemo.txt");<br />
BufferedRea<strong>de</strong>r e<strong>in</strong> =<br />
new BufferedRea<strong>de</strong>r(new FileRea<strong>de</strong>r(e<strong>in</strong>gabeDatei));<br />
BufferedWriter aus =<br />
new BufferedWriter(new FileWriter(ausgabeDatei));<br />
Str<strong>in</strong>g s;<br />
while ((s = e<strong>in</strong>.readL<strong>in</strong>e()) != null)<br />
{<br />
aus.write(s);<br />
aus.write('\n');<br />
}<br />
e<strong>in</strong>.close(); aus.close();<br />
}<br />
}<br />
Strukturierte zusammengesetze Datentypen s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> fast ausschließlich<br />
Referenzdatentypen (Klassen, Interfaces, Fel<strong>de</strong>r (Array <strong>in</strong> <strong>Java</strong>)). Objekte von e<strong>in</strong>em<br />
Referenzdatentyp<br />
- müssen (fast immer) explizit mit new angefor<strong>de</strong>rt wer<strong>de</strong>n<br />
- können Parameter- und Rückgabewert bei Metho<strong>de</strong>n se<strong>in</strong><br />
- können „Trägerobjekt“ e<strong>in</strong>es Methodcenaufrufs se<strong>in</strong><br />
59 vgl. 7.7 bzw. 1.4.4.3<br />
60 vgl. 1.4.4.4<br />
61 pr13400<br />
62 pr13400<br />
54
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Wird e<strong>in</strong> Objekt e<strong>in</strong>es Referenzdatentyps als Metho<strong>de</strong>nparameter verwen<strong>de</strong>t, wird<br />
e<strong>in</strong>e Kopie <strong>de</strong>r Referenz übergeben. In <strong>de</strong>r Metho<strong>de</strong> kann das Objekt im Gegendatz<br />
zu primitiven Datentypen 63 ) geän<strong>de</strong>rt wer<strong>de</strong>n, diese Än<strong>de</strong>rung wirkt auch nach<br />
außen.<br />
Basis-Datenstrukturen <strong>in</strong> <strong>Java</strong>: <strong>Java</strong> bietet mit <strong>de</strong>m <strong>Java</strong> Collection Framework 64<br />
e<strong>in</strong>e Bibliothek mit <strong>in</strong> <strong>de</strong>r Praxis häufig verwen<strong>de</strong>ten Basis-Datenstrukturen an.<br />
1.4 Die Objektorientierung von <strong>Java</strong><br />
1.4.1 Grundlegen<strong>de</strong> Konzepte<br />
1.4.1.1 Zustand und Verhalten von Objekten, Klassen, Instanz- und Klassen-Variable<br />
bzw. -Metho<strong>de</strong>n<br />
1.4.1.1.1 Die Abbildung von Zustand bzw. Verhalten <strong>in</strong> Instanzvariable bzw.<br />
Instanzmetho<strong>de</strong>n<br />
Objekte s<strong>in</strong>d die Schlüssel zum Verständnis <strong>de</strong>r objektorientierten Technologie.<br />
Objekte s<strong>in</strong>d Gegenstän<strong>de</strong> <strong>de</strong>s täglichen Lebens: <strong>de</strong>r Schreibtisch, das Skript, die<br />
Vorlesung. All diese Objekte <strong>de</strong>r 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 <strong>de</strong>r Objekte beschreiben Metho<strong>de</strong>n. Die Variablen<br />
bil<strong>de</strong>n <strong>de</strong>n Kern <strong>de</strong>r Objekte. Metho<strong>de</strong>n schirmen <strong>de</strong>n Objektkern von an<strong>de</strong>ren<br />
Objekten <strong>de</strong>s Programms ab (Kapselung). Software-Objekte kommunizieren und<br />
verkehren über Nachrichen (Botschaften) mite<strong>in</strong>an<strong>de</strong>r. Das sen<strong>de</strong>n<strong>de</strong> Objekt schickt<br />
<strong>de</strong>m Zielobjekt e<strong>in</strong>e Auffor<strong>de</strong>rung, e<strong>in</strong>e bestimmte Metho<strong>de</strong> auszuführen. Das<br />
Zielobjekt versteht (hoffentlich) die Auffor<strong>de</strong>rung und reagiert mit <strong>de</strong>r zugehörigen<br />
Metho<strong>de</strong>. Die genaue formale Schreibweise solcher Botschaften <strong>in</strong> objektorientierten<br />
Sprachen ist im Detail verschie<strong>de</strong>n, jedoch wird meistens folgen<strong>de</strong> Form verwen<strong>de</strong>t:<br />
Empfänger.Metho<strong>de</strong>nname(Argument). „Argument“ ist <strong>in</strong> <strong>de</strong>m<br />
Botschaftsausdruck e<strong>in</strong> Übergabeparameter für die Metho<strong>de</strong>.<br />
In <strong>de</strong>r realen Welt existieren häufig Objekte <strong>de</strong>r gleichen Art. Sie wer<strong>de</strong>n über e<strong>in</strong>en<br />
Prototyp, e<strong>in</strong>e Klasse, zusammengefaßt. E<strong>in</strong>e Klassen<strong>de</strong>f<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 />
Metho<strong>de</strong>n<strong>de</strong>f<strong>in</strong>itionen. Zum Anlegen e<strong>in</strong>es Objekts e<strong>in</strong>er Klasse (Instanziierung 65 )<br />
muß e<strong>in</strong>e Variable vom Typ <strong>de</strong>r Klasse <strong>de</strong>klariert und mit Hilfe <strong>de</strong>s new-Operators<br />
e<strong>in</strong> neu erzeugtes Objekt zugewiesen wer<strong>de</strong>n. 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 />
63 Wird <strong>in</strong> <strong>de</strong>r Metho<strong>de</strong> <strong>de</strong>r Wert <strong>de</strong>s Parameters mit primitivem Datentyp geän<strong>de</strong>rt, dann dr<strong>in</strong>gt dies nicht nach<br />
außen<br />
64 vgl. 6.2<br />
65 E<strong>in</strong>e Instanz e<strong>in</strong>er Klasse ist e<strong>in</strong> (tatsächliches) Objekt (konkrete Darstellung)<br />
55
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Aufruf <strong>de</strong>s new-Operators erfor<strong>de</strong>rt 66 , erfolgt die Rückgabe von nicht mehr<br />
benötigtem Speicher automatisch 67 .<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 />
grundlegen<strong>de</strong> Programmieraufgaben bereit.<br />
Zustand, Aussehen und an<strong>de</strong>re Qualitäten e<strong>in</strong>es Objekts (Attribute) wer<strong>de</strong>n durch<br />
Variable <strong>de</strong>f<strong>in</strong>iert. Da je<strong>de</strong> Instanz e<strong>in</strong>er Klasse verschie<strong>de</strong>ne 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 wer<strong>de</strong>n direkt <strong>in</strong> <strong>de</strong>r Klasse gespeichert. Der Zustand wird <strong>in</strong><br />
Variablen festgehalten und zeigt <strong>de</strong>n momentanen Stand <strong>de</strong>r Objektstruktur an, d.h.<br />
die <strong>in</strong> <strong>de</strong>n e<strong>in</strong>zelnen Bestandteilen <strong>de</strong>s Objekts enthaltenen Informationen und<br />
Daten. Abhängig vom Detaillierungsgrad kann die Notation für e<strong>in</strong>e Variable <strong>de</strong>n<br />
Namen, <strong>de</strong>n Datentyp und <strong>de</strong>n vore<strong>in</strong>gestellten Wert zeigen:<br />
Sichtbarkeit Typ Name = vore<strong>in</strong>gestellter_Wert;<br />
Sichtbarkeit: öffentlich (public), geschützt (protected) o<strong>de</strong>r privat (private)<br />
Typ: Datentyp<br />
Name: e<strong>in</strong>e nach bestimmten Regeln 68 gebil<strong>de</strong>te Zeichenkette<br />
Nach <strong>de</strong>r Initialisierung haben alle Variablen <strong>de</strong>s Objekts zunächst Standardwerte<br />
(vore<strong>in</strong>gestellte Werte). Der Zugriff auf sie erfolgt mit Hilfe <strong>de</strong>r Punktnotation:<br />
Objekt.Variable.<br />
Zur Bezugnahme auf das aktuelle Objekt dient das Schlüsselwort this. Es kann an<br />
je<strong>de</strong>r beliebigen Stelle angegeben wer<strong>de</strong>n, an <strong>de</strong>r das Objekt ersche<strong>in</strong>en kann, z.B.<br />
<strong>in</strong> e<strong>in</strong>er Punktnotation zum Verweis auf Instanzvariablen <strong>de</strong>s Objekts o<strong>de</strong>r als<br />
Argument für e<strong>in</strong>e Metho<strong>de</strong> o<strong>de</strong>r als Ausgabewert <strong>de</strong>r aktuellen Metho<strong>de</strong>n. 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 <strong>de</strong>s Verhaltens von Objekten dienen Metho<strong>de</strong>n. Metho<strong>de</strong>n s<strong>in</strong>d<br />
Funktionen, die <strong>in</strong>nerhalb von Klassen <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n und auf Klassen<strong>in</strong>stanzen<br />
angewandt wer<strong>de</strong>n. Metho<strong>de</strong>n wirken sich aber nicht nur auf e<strong>in</strong> Objekt aus. Objekte<br />
kommunizieren auch mite<strong>in</strong>an<strong>de</strong>r durch Metho<strong>de</strong>n. E<strong>in</strong>e Klasse o<strong>de</strong>r e<strong>in</strong> Objekt kann<br />
Metho<strong>de</strong>n e<strong>in</strong>er an<strong>de</strong>ren Klasse o<strong>de</strong>r e<strong>in</strong>es an<strong>de</strong>ren Objekts aufrufen, um<br />
Än<strong>de</strong>rungen <strong>in</strong> <strong>de</strong>r Umgebung mitzuteilen o<strong>de</strong>r e<strong>in</strong> Objekt aufzufor<strong>de</strong>rn, se<strong>in</strong>en<br />
Zustand zu än<strong>de</strong>rn. Instanzmetho<strong>de</strong>n (Operationen, Services) wer<strong>de</strong>n auf e<strong>in</strong>e<br />
Instanz angewandt, Klassenmetho<strong>de</strong>n beziehen sich auf e<strong>in</strong>e Klasse.<br />
Klassenmetho<strong>de</strong>n können nur mit Klassenvariablen arbeiten.<br />
Die Beschreibung <strong>de</strong>r Operationen (Nachrichten, Metho<strong>de</strong>n) erfolgt nach <strong>de</strong>m<br />
folgen<strong>de</strong>n Schema:<br />
Sichbarkeit Rückgabetypausdruck Name(Parameterliste)<br />
Sichtbarkeit: öffentlich (public), geschützt (protected), privat (private) 69<br />
Rückgabetypausdruck: Je<strong>de</strong> Metho<strong>de</strong> ist typisiert. Der Typ e<strong>in</strong>er Metho<strong>de</strong> bestimt <strong>de</strong>n Typ <strong>de</strong>s<br />
Rückgabewerts. Dieser kann von e<strong>in</strong>em beliebigen primitiven Typ 70 , e<strong>in</strong>em Objekttyp o<strong>de</strong>r vom Typ<br />
void se<strong>in</strong>. Metho<strong>de</strong>n vom Typ void haben ke<strong>in</strong>en Rückgabewert und dürfen nicht <strong>in</strong> Ausdrücken<br />
66 Ausnahmen: Str<strong>in</strong>g-, Array-Literale<br />
67 E<strong>in</strong> Garbage-Collector (niedrigpriorisierte H<strong>in</strong>tergrundprozeß) sucht <strong>in</strong> regelmäßigen Abstän<strong>de</strong>n nach nicht<br />
mehr referenzierten Objekten und gibt <strong>de</strong>n durch sie belegten Speicher an das Laufzeitsystem zurück<br />
68 vgl. 2.1.2 Bezeichner und Namenskonventionen<br />
69 vgl. 2.6.2<br />
70 vgl. 2.2<br />
56
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
verwen<strong>de</strong>t wer<strong>de</strong>n. Hat e<strong>in</strong>e Metho<strong>de</strong> e<strong>in</strong>en Rückgabewert, dann kann sie mit <strong>de</strong>r „return“-<br />
Anweisung 71 e<strong>in</strong>en Wert an <strong>de</strong>n Aufrufer zurückgeben.<br />
Parameterliste enthält optional Argumente und hat folgen<strong>de</strong> Struktur: Datentyp<br />
variablenname, ..... Die Anzahl <strong>de</strong>r Parameter ist beliebig und kann Null se<strong>in</strong>.<br />
In <strong>Java</strong> wird je<strong>de</strong> selbst<strong>de</strong>f<strong>in</strong>ierte Klasse mit Hilfe <strong>de</strong>s Operators new <strong>in</strong>stanziert. Mit<br />
Ausnahme von Zeichenketten (Str<strong>in</strong>gs) und Datenfel<strong>de</strong>rn (Arrays), bei <strong>de</strong>nen <strong>de</strong>r<br />
Compiler auch Literale zur Objekterzeugung bereitstellt, gilt dies für alle<br />
vor<strong>de</strong>f<strong>in</strong>ierten Klassen <strong>de</strong>r <strong>Java</strong>-Bibliothek.<br />
Der Aufruf e<strong>in</strong>er Metho<strong>de</strong> erfolgt ähnlich <strong>de</strong>r 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 wer<strong>de</strong>n, selbst wenn die Parameter-Liste leer<br />
ist.<br />
E<strong>in</strong> praktisches Beispiel:<br />
1. Erstellen <strong>de</strong>r Klasse Rechentafel zum Rechnen mit ganzen Zahlen<br />
Die grundlegen<strong>de</strong> Klassen<strong>de</strong>f<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><strong>de</strong>n kann, müssen Zustand und Verhalten<br />
diverser Rechentafel-Objekte festgehalten wer<strong>de</strong>n können.<br />
Der Zustand wird <strong>in</strong> Variablen gespeichert. In Rechentafel-Objekten gibt es zwei<br />
Operan<strong>de</strong>n zur Aufnahme ganzzahliger Werte für die Berechnung und e<strong>in</strong>e Variable<br />
zur Aufnahme <strong>de</strong>s Resultats nach <strong>de</strong>r Berechnung. Operan<strong>de</strong>n und Resultat s<strong>in</strong>d <strong>in</strong><br />
<strong>de</strong>r Klasse Rechentafel Instanzvariable, da je<strong>de</strong>s Rechentafel-Objekt dafür<br />
verschie<strong>de</strong>ne Werte haben kann. Folgen<strong>de</strong> Instanzvariable (mit Datentyp <strong>in</strong>t)<br />
wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>n 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 <strong>de</strong>s Klassenverzeichnisses gebil<strong>de</strong>t<br />
wer<strong>de</strong>n.<br />
Rechentafel-Objekte sollten „Rechnen“ können. Dieses Verhalten be<strong>de</strong>utet: Die<br />
vorliegen<strong>de</strong>n Instanzvariablen s<strong>in</strong>d durch Instanzmetho<strong>de</strong>n 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 />
71 vgl. 2.6.4<br />
57
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
Die Klasse ist damit für Rechentafel-Objekte vollständig bereitgestellt. Allerd<strong>in</strong>gs wird<br />
erst nach <strong>de</strong>m H<strong>in</strong>zufügen <strong>de</strong>r ma<strong>in</strong>()-Metho<strong>de</strong> aus dieser Klasse e<strong>in</strong>e <strong>Java</strong>-<br />
Anwendung 1 :<br />
2. Die Klasse Rechentafeltest zum Überprüfen <strong>de</strong>r Klasse Rechentafel<br />
Die Klasse Rechentafeltest ist durch die Anwendung <strong>de</strong>r Klasse Rechentafel<br />
bestimmt. Sie enthält die ma<strong>in</strong>()-Metho<strong>de</strong>. Im Mittelpunkt <strong>de</strong>r Anwendung steht die<br />
Anweisung:<br />
Rechentafel e<strong>in</strong>Rechenobjekt = new Rechentafel();<br />
Sie erzeugt e<strong>in</strong>e Instanz <strong>de</strong>r Klasse Rechentafel und speichert e<strong>in</strong>e Referenz<br />
darauf <strong>in</strong> <strong>de</strong>r Variablen „e<strong>in</strong>Rechenobjekt“. In je<strong>de</strong>r objektorientierten<br />
Programmiersprache lassen sich spezielle Metho<strong>de</strong>n <strong>de</strong>f<strong>in</strong>ieren, die bei <strong>de</strong>r<br />
Initialisierung e<strong>in</strong>es Objekts aufgerufen wer<strong>de</strong>n. In <strong>Java</strong> wer<strong>de</strong>n Konstruktoren als<br />
Metho<strong>de</strong>n ohne Rückgabewert <strong>de</strong>f<strong>in</strong>iert, die <strong>de</strong>n Namen <strong>de</strong>r Klasse erhalten, zu <strong>de</strong>r<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 „<strong>de</strong>fault“-Konstruktor aufgerufen (, <strong>de</strong>r hier zusammen mit <strong>de</strong>m<br />
Operator new verwen<strong>de</strong>t wird).<br />
import java.lang.*;<br />
class Rechentafeltest extends Object<br />
{<br />
// Zur Ausführung mit <strong>de</strong>m <strong>Java</strong>-Interpreter wird e<strong>in</strong>e ma<strong>in</strong>()-Metho<strong>de</strong><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 <strong>de</strong>r Klasse Rechentafel<br />
Rechentafel e<strong>in</strong>Rechenobjekt = new Rechentafel();<br />
// Setzen <strong>de</strong>r 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 <strong>de</strong>r Klasse Rechentafel<br />
System.out.pr<strong>in</strong>tln("Test mit e<strong>in</strong>em Rechentafel-Objekt");<br />
// Aufruf <strong>de</strong>r Metho<strong>de</strong>n und Ausgabe <strong>de</strong>s 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 />
72 vgl. pr14101<br />
58
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.1.1.2 E<strong>in</strong>fache Typen 74 , Referenztypen, Automatisches Boxen<br />
E<strong>in</strong>fache Typen und Wrapper-Klassen<br />
Je<strong>de</strong>s <strong>Java</strong>-Programm besteht aus e<strong>in</strong>er Sammlung von Klassen. Der vollständige<br />
Co<strong>de</strong> 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 an<strong>de</strong>re e<strong>in</strong>fache Typen 75 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 76<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> verschie<strong>de</strong>nen primitiven Typen darstellt. Über<br />
Wrapper-Objekte können alle e<strong>in</strong>fachen Typen wie Klassen behan<strong>de</strong>lt wer<strong>de</strong>n.<br />
Den primitiven Typen s<strong>in</strong>d „Wrapper“-Klassen zugeordnet, die e<strong>in</strong> nicht primitives<br />
Objekt auf <strong>de</strong>m „Heap“ zur Darstellung <strong>de</strong>s primitiven Typs erzeugen, z.B.:<br />
char zeichen = 'x';<br />
Character zeichenDarstellung = new Character(zeichen)<br />
bzw.<br />
Character zeichenDarstellung = new Character('x');<br />
PrimitivTyp Wrapper-Typ<br />
boolean Boolean<br />
byte Byte<br />
short Short<br />
<strong>in</strong>t<br />
Integer<br />
long Long<br />
float Float<br />
double Double<br />
void 77 Void 78<br />
Wrapper-Klassen erlauben es, Daten e<strong>in</strong>es primitiven Typs als Objekt zu speichern.<br />
Objekte dieser Klassen s<strong>in</strong>d nicht modifizierbar. Ist e<strong>in</strong>mal e<strong>in</strong> Integer-Objekt mit<br />
e<strong>in</strong>er bestimmten Zahl erzeugt, lässt sich die <strong>in</strong> diesem Objekt erzeugte Zahl nicht<br />
mehr modifizieren.<br />
Alle Wrapper-Typen bieten bestimmte Service-Metho<strong>de</strong>n an.<br />
Wichtige und gebrächliche Servive-Metho<strong>de</strong>n e<strong>in</strong>schl. weiterer Merkmale:<br />
- Alle Wrapper-Typen s<strong>in</strong>d f<strong>in</strong>al <strong>de</strong>klariert und können nicht weiter spezialisiert wer<strong>de</strong>n.<br />
- ...Value(), z.B. booleanValue(), byteValue(), shortValue(), <strong>in</strong>tValue(),<br />
longValue(), floatValue(), doubleValue(). All diese Metho<strong>de</strong>n geben <strong>de</strong>n <strong>in</strong>tern<br />
gekapselten Wert unverän<strong>de</strong>rt zurück. Darüber h<strong>in</strong>aus existieren Metho<strong>de</strong>n zur Ausgabe<br />
e<strong>in</strong>es numerischen Wrapper-Typs <strong>in</strong> e<strong>in</strong>en beliebigen numerischen Primitivtyp 79 .<br />
- Konstruktoren erlauben die Erzeugung e<strong>in</strong>es Wrappertyps aus e<strong>in</strong>em Ausdruck vom Typ <strong>de</strong>s<br />
gekapselten Typs o<strong>de</strong>r aus e<strong>in</strong>em Str<strong>in</strong>g.<br />
- compareTo() vergleicht <strong>de</strong>n gekapselten zweier Wrappertyp-Objekte.<br />
74 vgl. 2.2.1<br />
75 vgl. 2.2.1<br />
76 vgl. 1.4.2.7<br />
77 Dieser Typ ist nicht als Datentyp für Variable und Attribute verfügbar, kann nur als Rückgabetyp von<br />
Operationen spezifiziert wer<strong>de</strong>n.<br />
78 kann nicht <strong>in</strong>stanziiert wer<strong>de</strong>n<br />
79 ersetzen die explizite Typumwandlung<br />
59
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- parse...() Metho<strong>de</strong>n, z.B. parseByte(Str<strong>in</strong>g s), parseByte(Str<strong>in</strong>g s, <strong>in</strong>t<br />
radix), parseInt(Str<strong>in</strong>g s), parseInt(Str<strong>in</strong>g s, <strong>in</strong>t radix), erzeugen aus<br />
Zeichenketten <strong>de</strong>n jeweiligen Primitivtyp.<br />
- valueOf(). Für alle Wrapper-Typen <strong>in</strong>tegraler Primitivtypen (byte, char, long, <strong>in</strong>t, short) ist<br />
mit <strong>de</strong>r valueOf()-Metho<strong>de</strong> e<strong>in</strong>e (Factory-) Metho<strong>de</strong> zur Erzeugung e<strong>in</strong>es neuen Wrapper-<br />
Objekts aus e<strong>in</strong>er Zeichenkette <strong>de</strong>f<strong>in</strong>iert.<br />
- die üblichen arithmetischen Operationen stehen zur Verknüpfung von Wrapperobjekten nicht<br />
zur Verfügung (ke<strong>in</strong> Operator overload<strong>in</strong>g).<br />
Referenztypen<br />
Neben <strong>de</strong>n primitiven Typen gibt es die Referenztypen. Dazu gehören: Objekte <strong>de</strong>r<br />
benutzer<strong>de</strong>f<strong>in</strong>ierten und aus vom System bereitgestellten Klassen, <strong>de</strong>r Klassen<br />
Str<strong>in</strong>g und Array (Datenfeld). Weiterh<strong>in</strong> gibt es die vor<strong>de</strong>f<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 Beson<strong>de</strong>rheiten aus:<br />
- Für Str<strong>in</strong>gs und Arrays kennt <strong>de</strong>r Compiler Literale, die e<strong>in</strong>en expliziten Aufruf <strong>de</strong>s Operator new<br />
überflüssig machen<br />
- Arrays s<strong>in</strong>d klassenlose Objekte. Sie können ausschließlich vom Compiler erzeugt wer<strong>de</strong>n, besitzen<br />
aber ke<strong>in</strong>e explizite Klassen<strong>de</strong>f<strong>in</strong>ition. Sie wer<strong>de</strong>n <strong>de</strong>nnoch vom Laufzeitsystem wie normale<br />
Objeklte behan<strong>de</strong>lt.<br />
- Die Klasse Str<strong>in</strong>g ist zwar im JDK vorhan<strong>de</strong>n. Der Compiler hat aber Kenntnis über <strong>de</strong>n <strong>in</strong>neren<br />
Aufbau von Str<strong>in</strong>gs und generiert bei Anzeigeoperationen Co<strong>de</strong>, <strong>de</strong>r auf Metho<strong>de</strong>n <strong>de</strong>r Klassen<br />
Str<strong>in</strong>g und Str<strong>in</strong>gBuffer zugreift.<br />
Automatisches Boxen<br />
Box<strong>in</strong>g. Beim Speichern e<strong>in</strong>es Datums von e<strong>in</strong>em primitiven Typ <strong>in</strong> e<strong>in</strong>er Variablen,<br />
die nur Objekte speichern kann, ist kapseln <strong>in</strong> e<strong>in</strong>em Objekt <strong>de</strong>r entsprechen<strong>de</strong>n<br />
(Wrapper-) Klasse nötig (box<strong>in</strong>g). Es kam zu Konstruktoraufrufen dieser Klassen.<br />
Unbox<strong>in</strong>g. Sollte später mit Operatoren auf <strong>de</strong>n Zahlen, die durch gekapselte Objekte<br />
ausgedrückt wur<strong>de</strong>n, gerechnet wer<strong>de</strong>n, so war <strong>de</strong>r primitive Wert mit e<strong>in</strong>em<br />
Metho<strong>de</strong>naufruf aus <strong>de</strong>m Objekt wie<strong>de</strong>r zu extrahieren (unbox<strong>in</strong>g). Es kam zu<br />
Aufrufen wie <strong>in</strong>tValue() im Co<strong>de</strong> 80 .<br />
Bsp.: Manuelles Verpacken und Auspacken primitiver Daten<br />
public class ManuellesBoxen<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
<strong>in</strong>t i1 = 42;<br />
Object o = new Integer(i1);<br />
System.out.pr<strong>in</strong>tln(o);<br />
Integer i2 = new Integer(17);<br />
Integer i3 = new Integer(4);<br />
<strong>in</strong>t i4 = 21;<br />
System.out.pr<strong>in</strong>tln((i2.<strong>in</strong>tValue() + i3.<strong>in</strong>tValue()) * 14);<br />
}<br />
}<br />
Mit <strong>Java</strong> 1.5 können die primitiven Typen mit ihren entsprechen<strong>de</strong>n KLassen<br />
synonym verwen<strong>de</strong>t wer<strong>de</strong>n. Nach außen h<strong>in</strong> wer<strong>de</strong>n die primitiven Typen auch<br />
Objekttypen. Der Übersetzer nimmt die notwendigen box<strong>in</strong>g- und unbox<strong>in</strong>g-<br />
Operationen vor.<br />
80 vgl. 1.4.2.7<br />
60
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp. 81 : Automatic Box<strong>in</strong>g<br />
public class AutomatischesBoxen<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
<strong>in</strong>t i1 = 42;<br />
Object o = i1;<br />
System.out.pr<strong>in</strong>tln(o);<br />
Integer i2 = 17;<br />
Integer i3 = 4;<br />
<strong>in</strong>t i4 = 21;<br />
System.out.pr<strong>in</strong>tln((i2 + i3) * 14);<br />
}<br />
}<br />
1.4.1.1.3 Konstruktoren<br />
E<strong>in</strong>e „Constructor“-Metho<strong>de</strong> bestimmt, wie e<strong>in</strong> Objekt <strong>in</strong>itialisiert wird. Konstruktoren<br />
haben immer <strong>de</strong>n 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 folgen<strong>de</strong> Aufgaben:<br />
- Speicherzuweisung für das Objekt<br />
- Initialisieung <strong>de</strong>r Instanzvariablen <strong>de</strong>s Objekts auf ihre Anfangswerte o<strong>de</strong>r e<strong>in</strong>en Default-Wert (0 bei<br />
Zahlen, „null“ bei Objekten, „false“ bei booleschen Operatoren.<br />
- Aufruf <strong>de</strong>r Konstruktor-Metho<strong>de</strong> <strong>de</strong>r Klasse<br />
Gewöhnlich stellt man „explizit“ e<strong>in</strong>en „<strong>de</strong>fault“-Konstruktor zur Verfügung. Dieser<br />
parameterlose Konstruktor überlagert <strong>de</strong>n implizit bereitgestellten „<strong>de</strong>fault“-<br />
Konstruktor. Er wird dann bei allen parameterlosen Instanzierungen verwen<strong>de</strong>t.<br />
Konstruktoren können aber auch – wie normale Dateien – Parameter übergeben<br />
bekommen, z.B. 82 :<br />
public Rechentafel(<strong>in</strong>t ersterOperand, <strong>in</strong>t zweiterOperand)<br />
{<br />
super(); // Aufruf <strong>de</strong>s Default-Konstruktors <strong>de</strong>r Superklasse<br />
this.ersterOperand = ersterOperand;<br />
this.zweiterOperand = zweiterOperand;<br />
}<br />
super() bestimmt e<strong>in</strong>en Aufruf <strong>de</strong>s „<strong>de</strong>fault“-Konstruktors <strong>de</strong>r e<strong>in</strong><strong>de</strong>utig<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 <strong>de</strong>n<br />
gleichen Namen wie die entsprechen<strong>de</strong>n Instanzvariablen. In diesen Fällen löst die<br />
Verwendung von bsp. this.ersterOperand = ersterOperand; <strong>de</strong>rartige<br />
Namenskonflikte auf.<br />
Bei „this“ han<strong>de</strong>lt es sich um e<strong>in</strong>en Zeiger, <strong>de</strong>r 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 <strong>de</strong>r eigenen Metho<strong>de</strong>n und Instanzvariablen dient.<br />
Der „this“-Zeiger ist auch explizit verfügbar und kann wie e<strong>in</strong>e ganz normale<br />
81 vgl. pr14112<br />
82 pr14102<br />
61
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Objektvariable verwen<strong>de</strong>t wer<strong>de</strong>n. Er wird als versteckter Parameter an je<strong>de</strong> nicht<br />
statische Metho<strong>de</strong> übergeben.<br />
Konstruktoren können <strong>in</strong> <strong>Java</strong> verkettet aufgerufen wer<strong>de</strong>n, d.h. sie können sich<br />
gegenseitig aufrufen. Der aufrufen<strong>de</strong> Konstruktor wird dabei als normale Metho<strong>de</strong><br />
angesehen, die über this e<strong>in</strong>en weiteren Konstruktor <strong>de</strong>r aktuellen Klasse aufrufen<br />
kann, z.B.:<br />
public Rechentafel()<br />
{<br />
this(0,1);<br />
}<br />
1.4.1.1.4 Zugriffsrechte auf Klassen, Variable und Metho<strong>de</strong>n<br />
Es gibt <strong>in</strong> <strong>Java</strong> <strong>in</strong>sgesamt 4 Zugriffsrechte:<br />
private<br />
Ohne Schlüsselwort<br />
protected<br />
public<br />
Zugriff nur <strong>in</strong>nerhalb e<strong>in</strong>er Klasse<br />
Zugriff <strong>in</strong>nerhalb e<strong>in</strong>es Pakets<br />
Zugriff <strong>in</strong>nerhalb e<strong>in</strong>es Pakets o<strong>de</strong>r von Subklassen <strong>in</strong> e<strong>in</strong>em an<strong>de</strong>ren<br />
Paket<br />
Zugriff von überall<br />
Mit Voranstellen <strong>de</strong>s Schlüsselworts „public“ können alle Klassen, Variablen /<br />
Konstanten und Metho<strong>de</strong>n für e<strong>in</strong>en beliebigen Zugriff e<strong>in</strong>gerichtet wer<strong>de</strong>n. E<strong>in</strong>e<br />
<strong>de</strong>rartige Möglichkeit, die <strong>in</strong> etwa <strong>de</strong>r Zugriffsmöglichkeit globaler Variablen <strong>in</strong><br />
konventionellen Programmiersprachen entspricht, ist <strong>in</strong>sbeson<strong>de</strong>re bei komplexen<br />
Programm-Systemen gefährlich. Es ist nicht sichergestellt, daß zu je<strong>de</strong>m Zeitpunkt<br />
die Werte <strong>de</strong>r 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> <strong>de</strong>r Klasse „Rechentafeltest“. Mit Sicherheit führt diese Anweisung bei <strong>de</strong>r<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 <strong>de</strong>r Datenkapselung (data hid<strong>in</strong>g, data<br />
encapsulation). Instanzvariable wer<strong>de</strong>n als „private“ erklärt, d.h.: Zugriff auf diese<br />
Instanzvariable nur <strong>in</strong>nerhalb <strong>de</strong>r Klasse. Von außerhalb kann nur <strong>in</strong>direkt über das<br />
Aufrufen von Metho<strong>de</strong>n, die als „public“ erklärt s<strong>in</strong>d, auf die Instanzvariablen<br />
zugegriffen wer<strong>de</strong>n. Deshalb sollte auch pr<strong>in</strong>zipiell für je<strong>de</strong> Instanzvariable e<strong>in</strong>e<br />
entsprechen<strong>de</strong> „get“- und e<strong>in</strong>e „set“-Metho<strong>de</strong> („hole“ bzw. „setze“) zur Verfügung<br />
gestellt wer<strong>de</strong>n, die jeweils „public“ erklärt wer<strong>de</strong>n.<br />
Bsp.: Die Klasse „Rechentafel“ nimmt dann folgen<strong>de</strong>n Gestalt an:<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 />
62
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
Das Beispiel zeigt folgen<strong>de</strong> Empfehlungen für die Vergabemöglichkeit von Zugriffsrechten:<br />
Klassen<br />
Instanzvariable<br />
Instanzkonstanten<br />
Instanzmetho<strong>de</strong>n<br />
public<br />
private<br />
public<br />
public, falls e<strong>in</strong> Zugriff von außen erfor<strong>de</strong>rlich und s<strong>in</strong>nvoll ist.<br />
private, falls es sich um klasen<strong>in</strong>terne Hilfsmetho<strong>de</strong>n han<strong>de</strong>lt.<br />
Analoge Überlegungen gelten auch für Klassenvariable und -metho<strong>de</strong>n.<br />
„Freundliche“ Klassen und „freundliche“ Metho<strong>de</strong>n<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 verwen<strong>de</strong>t, wenn ke<strong>in</strong>e Angaben<br />
63
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
über die Sichtbarkeit (Spezifizierer, Modifizierer) am Beg<strong>in</strong>n <strong>de</strong>r Klassen<strong>de</strong>f<strong>in</strong>ition<br />
vorliegen.<br />
Die freundliche Grun<strong>de</strong><strong>in</strong>stellung aller Klassen be<strong>de</strong>utet: Diese Klasse kann von<br />
an<strong>de</strong>ren Klassen nur <strong>in</strong>nerhalb <strong>de</strong>sselben Pakets benutzt wer<strong>de</strong>n. 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“ wer<strong>de</strong>n 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 <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n, wer<strong>de</strong>n vom Compiler <strong>in</strong> e<strong>in</strong> Standardpaket gestellt. Die<br />
„.java“- und „.class“-Dateien dieses Pakets bef<strong>in</strong><strong>de</strong>n sich im aktuellen<br />
Verzeichnis o<strong>de</strong>r im darunterliegen<strong>de</strong>n Verzeichnis.<br />
Mit <strong>de</strong>m Voranstellen von „public“ vor die Klassen<strong>de</strong>klaration wird e<strong>in</strong>e Klasse als<br />
„öffentlich“ <strong>de</strong>klariert. Dies be<strong>de</strong>utet: Alle Objekte haben Zugriff auf „public“-<br />
Klassen (nicht nur die <strong>de</strong>s eigenen Pakets).<br />
Der vore<strong>in</strong>gestellte Defaultstaus e<strong>in</strong>er Metho<strong>de</strong> ist immer freundlich und wird immer<br />
dann verwen<strong>de</strong>t, wenn ke<strong>in</strong>e explizite Angabe zur Sichtbarkeit am Anfang <strong>de</strong>r<br />
Metho<strong>de</strong>n<strong>de</strong>klaration vorliegt. Die freundliche Grun<strong>de</strong><strong>in</strong>stellung aller Metho<strong>de</strong>n<br />
be<strong>de</strong>utet: Die Metho<strong>de</strong>n können sowohl <strong>in</strong>nerhalb <strong>de</strong>r Klasse als auch <strong>in</strong>nerhalb <strong>de</strong>s<br />
zugehörigen Pakets benutzt wer<strong>de</strong>n.<br />
1.4.1.1.5 Klassenvariable und Klassenmetho<strong>de</strong>n<br />
Die Klasse „Rechentafel" 83 wur<strong>de</strong> zusätzlich erweitert um<br />
// Klassenvariable<br />
static <strong>in</strong>t anzRechenobjekte = 0;<br />
Das reservierte Wort static macht Variable und Metho<strong>de</strong>n (wie bspw. ma<strong>in</strong>()) zu<br />
Klassenvariablen bzw. Klassenmetho<strong>de</strong>n.<br />
Klassenvariable wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r Klasse <strong>de</strong>f<strong>in</strong>iert und gespeichert. Deshalb wirken sich<br />
ihre Werte auf die Klasse und all ihre Instanzen aus. Je<strong>de</strong> Instanz hat Zugang zu <strong>de</strong>r<br />
Klassenvariablen, jedoch gibt es für alle Instanzen dieser Variablen nur e<strong>in</strong>en Wert.<br />
Durch Än<strong>de</strong>rung <strong>de</strong>s Werts än<strong>de</strong>rn sich die Werte aller Instanzen <strong>de</strong>r betreffen<strong>de</strong>n<br />
Klasse.<br />
Die folgen<strong>de</strong> Erweiterung <strong>de</strong>s Konstruktors <strong>de</strong>r 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, <strong>de</strong>nen nur e<strong>in</strong>mal bei <strong>de</strong>r<br />
Deklaration e<strong>in</strong> Wert zugewiesen wer<strong>de</strong>n kann, d.h. sie wer<strong>de</strong>n dadurch zu<br />
Konstanten, z.B.: public static f<strong>in</strong>al double PI = 3.1415926535897932846;<br />
83 pr14103<br />
64
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Klassenmetho<strong>de</strong>n wirken sich wie Klassenvariable auf die ganze Klasse, nicht auf<br />
e<strong>in</strong>zelne Instanzen aus. Klassenmetho<strong>de</strong>n s<strong>in</strong>d nützlich zum Zusammenfassen<br />
allgeme<strong>in</strong>er Metho<strong>de</strong>n an e<strong>in</strong>er Stelle <strong>de</strong>r Klasse. So umfaßt die Math-Klasse<br />
zahlreiche mathematische Funktionen <strong>in</strong> <strong>de</strong>r Form von Klassenmetho<strong>de</strong>n. Es gibt<br />
ke<strong>in</strong>e Instanzen <strong>de</strong>r Klasse Math.<br />
Auch rekurvive Programme benutzen Klassenmetho<strong>de</strong>n, z.B.:<br />
// Berechnung <strong>de</strong>r Fakultaet<br />
public static long fakultaet(<strong>in</strong>t n)<br />
{<br />
if (n < 0)<br />
{ return -1; }<br />
else if (n == 0)<br />
{ return 1; }<br />
else<br />
{ return n * fakultaet(n-1); }<br />
}<br />
Der Aufruf e<strong>in</strong>er Klassenmetho<strong>de</strong> kann im Rahmen <strong>de</strong>r Punktnotation aber auch<br />
direkt erfolgen, z.B.:<br />
long resultat = fakultaet(i);<br />
bzw.<br />
long resultat = Rechentafel.fakultaet(i);<br />
unter <strong>de</strong>r Voraussetzung: Die Klassenmetho<strong>de</strong> „fakultaet“ bef<strong>in</strong><strong>de</strong>t sich <strong>in</strong> <strong>de</strong>r Klasse<br />
„Rechentafel“.<br />
1.4.1.1.6 Lokale Variable und Konstanten<br />
Lokale Variable wer<strong>de</strong>n <strong>in</strong>nerhalb von Metho<strong>de</strong>n<strong>de</strong>f<strong>in</strong>itionen <strong>de</strong>klariert und können<br />
nur dort verwen<strong>de</strong>t wer<strong>de</strong>n. 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 verwen<strong>de</strong>t wer<strong>de</strong>n darf. Die<br />
Sichtbarkeit e<strong>in</strong>er lokalen Variablen erstreckt sich von <strong>de</strong>r Deklaration bis zum En<strong>de</strong><br />
<strong>de</strong>s umschließen<strong>de</strong>n Blocks.<br />
Lokale Variablen existieren nur solange im Speicher, wie die Metho<strong>de</strong> o<strong>de</strong>r <strong>de</strong>r Block<br />
existiert. Lokale Variable müssen unbed<strong>in</strong>gt e<strong>in</strong> Wert zugewiesen bekommen, bevor<br />
sie benutzt wer<strong>de</strong>n 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 wer<strong>de</strong>n. Lokale Variable können auch nicht als<br />
Konstanten 84 gesetzt wer<strong>de</strong>n.<br />
Beim Bezug e<strong>in</strong>er Variablen <strong>in</strong> e<strong>in</strong>er Metho<strong>de</strong>n<strong>de</strong>f<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 <strong>de</strong>r aktuellen Metho<strong>de</strong>. 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> <strong>de</strong>r aktuellen Klasse und zum Schluß <strong>in</strong> <strong>de</strong>r Superklasse.<br />
Konstanten s<strong>in</strong>d Speicherbereiche mit Werten, die sich nie än<strong>de</strong>rn. In <strong>Java</strong> können<br />
solche Konstanten ausschließlich für Instanz- und Klassenvariable erstellt wer<strong>de</strong>n.<br />
Konstante bestehen aus e<strong>in</strong>er Variablen<strong>de</strong>klaration, <strong>de</strong>r 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 />
84 Das be<strong>de</strong>utet: das Schlüsselwort f<strong>in</strong>al ist bei lokalen Variablen nicht erlaubt<br />
65
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.1.1.7 Überla<strong>de</strong>n von Metho<strong>de</strong>n<br />
In <strong>Java</strong> ist es erlaubt, Metho<strong>de</strong>n zu überla<strong>de</strong>n, d.h. <strong>in</strong>nerhalb e<strong>in</strong>er Klasse zwei<br />
unterschiedliche Metho<strong>de</strong>n mit <strong>de</strong>nselben Namen zu <strong>de</strong>f<strong>in</strong>ieren. Der Compiler<br />
unterschei<strong>de</strong>t die verschie<strong>de</strong>nen Varianten anhand Anzahl und Typisierung <strong>de</strong>r<br />
Parameter. Es ist nicht erlaubt, zwei Metho<strong>de</strong>n mit exakt <strong>de</strong>mselben Namen und<br />
i<strong>de</strong>ntischer Parameterliste zu <strong>de</strong>f<strong>in</strong>ieren. Es wer<strong>de</strong>n auch zwei Metho<strong>de</strong>n, die sich<br />
nur durch <strong>de</strong>n Typ ihres Rückgabewerts unterschei<strong>de</strong>n als gleich angesehen.<br />
Der Compiler kann die Namen <strong>in</strong> allen drei Fällen unterschei<strong>de</strong>n, <strong>de</strong>nn er arbeitet mit<br />
<strong>de</strong>r Signatur <strong>de</strong>r Metho<strong>de</strong>. Darunter versteht man ihren <strong>in</strong>ternen Namen. Dieser setzt<br />
sich aus <strong>de</strong>m nach außen sichtbaren Namen und zusätzlich kodierter Information<br />
über Reihenfolge und die Typen <strong>de</strong>r formalen Parameter zusammen.<br />
Überla<strong>de</strong>n kann be<strong>de</strong>uten, daß bei Namensgleichheit von Metho<strong>de</strong>n <strong>in</strong> „Superklasse“<br />
und abgeleiteter Klasse die Metho<strong>de</strong> <strong>de</strong>r abgeleitetem Klasse, die <strong>de</strong>r Superklasse<br />
über<strong>de</strong>ckt. Es wird aber vorausgesetzt, daß sich die Parameter signifikant<br />
unterschei<strong>de</strong>n, sonst han<strong>de</strong>lt es sich bei <strong>de</strong>r Konstellation Superklasse – Subklasse<br />
um <strong>de</strong>n Vorgang <strong>de</strong>s Überschreibens. Soll die Orig<strong>in</strong>almetho<strong>de</strong> aufgerufen wer<strong>de</strong>n,<br />
dann wird das Schlüsselwort „super“ benutzt. Damit wird <strong>de</strong>r Metho<strong>de</strong>naufruf <strong>in</strong> <strong>de</strong>r<br />
Hierarchie nach oben weitergegeben.<br />
Überschreiben e<strong>in</strong>er Oberklassen-Metho<strong>de</strong>: Zum Überschreiben e<strong>in</strong>er Metho<strong>de</strong> wird<br />
e<strong>in</strong>e Metho<strong>de</strong> erstellt, die <strong>de</strong>n gleichen Namen, Ausgabetyp und die gleiche<br />
Parameterliste wie e<strong>in</strong>e Metho<strong>de</strong> <strong>de</strong>r Superklasse besitzt. Da <strong>Java</strong> die erste<br />
Metho<strong>de</strong>n<strong>de</strong>f<strong>in</strong>ition ausführt, die es f<strong>in</strong><strong>de</strong>t und die <strong>in</strong> Namen, Ausgabetyp und<br />
Parameterliste übere<strong>in</strong>stimmt, wird die ursprüngliche Metho<strong>de</strong>n<strong>de</strong>f<strong>in</strong>ition dadurch<br />
verborgen. Klassen-Metho<strong>de</strong>n wer<strong>de</strong>n nicht überschrieben, son<strong>de</strong>rn über<strong>de</strong>ckt, da<br />
sie (z. B. Klasse.metho<strong>de</strong>(), Superklasse.metho<strong>de</strong>()) <strong>in</strong> je<strong>de</strong>m Fall verschie<strong>de</strong>ne<br />
Namen haben.<br />
Konstruktor-Metho<strong>de</strong>n können „technisch“ nicht überschrieben wer<strong>de</strong>n. Da sie <strong>de</strong>n<br />
gleichen Namen wie die aktuelle Klasse haben, wer<strong>de</strong>n Konstruktoren nicht vererbt,<br />
son<strong>de</strong>rn immer neu erstellt. Wird e<strong>in</strong> Konstruktor e<strong>in</strong>er bestimmten Klasse<br />
aufgerufen, wird gleichzeitig auch <strong>de</strong>r Konstruktor aller Superklassen aktiviert, so daß<br />
alle Teile e<strong>in</strong>er Klasse <strong>in</strong>itialisiert wer<strong>de</strong>n. E<strong>in</strong> spezielles Überschreiben kann über<br />
super(arg1, arg2, ...) ermöglicht wer<strong>de</strong>n.<br />
Die Metho<strong>de</strong> toStr<strong>in</strong>g() ist e<strong>in</strong>e <strong>in</strong> <strong>Java</strong> häufig verwen<strong>de</strong>te Metho<strong>de</strong>.<br />
„toStr<strong>in</strong>g()“ wird als weitere Instanzmetho<strong>de</strong> <strong>de</strong>r Klasse Rechentafel <strong>de</strong>f<strong>in</strong>iert und<br />
überschreibt die Metho<strong>de</strong> gleichen Namens, die <strong>in</strong> <strong>de</strong>r Oberklasse Object <strong>de</strong>f<strong>in</strong>iert<br />
ist, z.B. 85 :<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 />
85 pr14103<br />
66
<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 an<strong>de</strong>re Klassen beziehen. Ausgangspunkt ist e<strong>in</strong>e<br />
Superklasse, von <strong>de</strong>r Subklassen (Unter-) abgeleitet se<strong>in</strong> können. Je<strong>de</strong> Subklasse<br />
erbt <strong>de</strong>n Zustand (über die Variablen-Deklarationen) und das Verhalten <strong>de</strong>r<br />
Superklasse. Darüber h<strong>in</strong>aus können Subklassen eigene Variable und Metho<strong>de</strong>n<br />
h<strong>in</strong>zufügen. Superklassen, Subklassen bil<strong>de</strong>n 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 – <strong>de</strong>r Klasse Object.<br />
Sie stellt die allgeme<strong>in</strong>ste Klasse <strong>in</strong> <strong>de</strong>r Hierarchie dar und legt die Verhaltensweisen<br />
und Attribute, die an alle Klassen <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Klassenbibliothek vererbt wer<strong>de</strong>n, fest.<br />
Vererbung be<strong>de</strong>utet, 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 wer<strong>de</strong>n? Beim Erstellen e<strong>in</strong>er neuen Instanz erhält man e<strong>in</strong> Exemplar je<strong>de</strong>r<br />
Variablen, die <strong>in</strong> <strong>de</strong>r aktuellen Klasse <strong>de</strong>f<strong>in</strong>iert ist. Zusätzlich wird e<strong>in</strong> Exemplar für<br />
je<strong>de</strong> Variable bereitgestellt, die sich <strong>in</strong> <strong>de</strong>n Superklassen <strong>de</strong>r aktuellen Klasse<br />
bef<strong>in</strong><strong>de</strong>t. Bei <strong>de</strong>r Metho<strong>de</strong>nauswahl haben neue Objekte Zugang zu allen<br />
Metho<strong>de</strong>nnamen ihrer Klasse und <strong>de</strong>ren Superklasse. Metho<strong>de</strong>nnamen wer<strong>de</strong>n<br />
dynamisch beim Aufruf e<strong>in</strong>er Metho<strong>de</strong> gewählt. Das be<strong>de</strong>utet: <strong>Java</strong> prüft zuerst die<br />
Klasse <strong>de</strong>s Objekts auf Def<strong>in</strong>ition <strong>de</strong>r betreffen<strong>de</strong>n Metho<strong>de</strong>. Ist sie nicht <strong>in</strong> <strong>de</strong>r<br />
Klasse <strong>de</strong>s Objekts <strong>de</strong>f<strong>in</strong>iert, sucht <strong>Java</strong> <strong>in</strong> <strong>de</strong>r Superklasse dieser Klasse usw.<br />
aufwärts <strong>in</strong> <strong>de</strong>r Hierarchie bis die Def<strong>in</strong>ition <strong>de</strong>r Metho<strong>de</strong> gefun<strong>de</strong>n wird.<br />
Ist <strong>in</strong> e<strong>in</strong>er Subklasse e<strong>in</strong>e Metho<strong>de</strong> mit gleichem Namen, gleicher Anzahl und<br />
gleichem Typ <strong>de</strong>r Argumente wie <strong>in</strong> <strong>de</strong>r Superklasse <strong>de</strong>f<strong>in</strong>iert, dann wird die<br />
Metho<strong>de</strong>n<strong>de</strong>f<strong>in</strong>ition, die zuerst (von unten nach oben <strong>in</strong> <strong>de</strong>r Hierarchie) gefun<strong>de</strong>n<br />
wird, ausgeführt. Metho<strong>de</strong>n <strong>de</strong>r abgeleiteten Klasse über<strong>de</strong>cken die Metho<strong>de</strong>n <strong>de</strong>r<br />
Superklasse (Overrid<strong>in</strong>g beim Überschreiben / Über<strong>de</strong>f<strong>in</strong>ieren).<br />
Zum Ableiten e<strong>in</strong>er Klasse aus e<strong>in</strong>er bestehen<strong>de</strong>n Klasse ist im Kopf <strong>de</strong>r Klasse mit<br />
Hilfe <strong>de</strong>s Schlüsselworts „extends“ e<strong>in</strong> Verweis auf die Basisklasse anzugeben.<br />
Wird <strong>de</strong>r Name e<strong>in</strong>er Klasse nach <strong>de</strong>m Schlüsselwort extends angegeben, dann<br />
wird damit diese Klasse als Superklasse spezifiziert, auf <strong>de</strong>r e<strong>in</strong>e neue Klasse<br />
aufbaut. Durch Erweiterung <strong>de</strong>r Superklasse entsteht e<strong>in</strong>e neue Kopie dieser Klasse,<br />
an <strong>de</strong>r Verän<strong>de</strong>rungen möglich s<strong>in</strong>d. Die neue Klasse erbt alle Daten und Metho<strong>de</strong>n,<br />
die <strong>in</strong> <strong>de</strong>r Orig<strong>in</strong>alklasse <strong>de</strong>f<strong>in</strong>iert wur<strong>de</strong>n. Durch H<strong>in</strong>zufügen neuer Elemente o<strong>de</strong>r<br />
Überla<strong>de</strong>n <strong>de</strong>r vorhan<strong>de</strong>nen kann die Funktionalität <strong>de</strong>r abgeleiteten Klasse erweitert<br />
wer<strong>de</strong>n.<br />
Die Vererbung e<strong>in</strong>er Klasse kann beliebig tief geschachtelt wer<strong>de</strong>n. E<strong>in</strong>e abgeleitete<br />
Klasse erbt dabei jeweils die Eigenschaften <strong>de</strong>r 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 Metho<strong>de</strong><br />
enthalten und s<strong>in</strong>d damit auch nicht <strong>in</strong>stanziierbar. <strong>Java</strong> charakterisiert abstrakte<br />
Klassen mit <strong>de</strong>m Schlüsselwort abstract. Abstrakte Klassen wer<strong>de</strong>n zum Aufbau<br />
e<strong>in</strong>er Klassenhierarchie verwen<strong>de</strong>t, z.B. für die Zusammenfassung von zwei o<strong>de</strong>r<br />
mehr Klassen.<br />
Auch e<strong>in</strong>e abstrakte Metho<strong>de</strong> ist zunächst e<strong>in</strong>mal durch das reservierte Wort<br />
"abstract" erklärt. E<strong>in</strong>e abstrakte Metho<strong>de</strong> besteht nur aus <strong>de</strong>m Metho<strong>de</strong>nkopf,<br />
67
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
anstelle <strong>de</strong>s Metho<strong>de</strong>nrumpfs (<strong>de</strong>r Metho<strong>de</strong>n<strong>de</strong>f<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><strong>de</strong>stens e<strong>in</strong>e abstrakte Metho<strong>de</strong>, 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 je<strong>de</strong>r<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 Metho<strong>de</strong>n stellen e<strong>in</strong>e Schnittstellenbeschreibung dar, die<br />
<strong>de</strong>r Programmierer e<strong>in</strong>er Subklasse zu <strong>de</strong>f<strong>in</strong>ieren hat. E<strong>in</strong> konkrete Subklasse e<strong>in</strong>er<br />
abstrakten Klasse muß alle abstrakten Metho<strong>de</strong>n <strong>de</strong>r Superklasse(n)<br />
implementieren.<br />
Beispiel: E<strong>in</strong>e Klassenhierarchie für "geometrische" Objekte 86<br />
Das folgen<strong>de</strong> Klassendiagramm zeigt die hierarchische Struktur von Klassen, die<br />
"geometrische Objekte" beschreiben. All diesen geometrischen Objekten ist<br />
geme<strong>in</strong>sam: Sie wer<strong>de</strong>n durch e<strong>in</strong>en Bezugspunkt (x,y) fixiert. DieGeme<strong>in</strong>samkeiten<br />
s<strong>in</strong>d <strong>in</strong> <strong>de</strong>r abstrakten Klasse "Geomobjekt" zusammengefaßt.<br />
86 vgl. pr14131<br />
68
<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<br />
Rechteck<br />
private double r;<br />
public double holeR();<br />
public void setzeR(double r);<br />
public double umfang();<br />
public double flaeche();<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g();<br />
private double breite;<br />
private double hoehe;<br />
public double holeBreite();<br />
public void setzeBreite(double breite)<br />
public double holeHoehe(double hoehe);<br />
public void setzeHoehe(double hoehe);<br />
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 <strong>de</strong>r allen Objekten<br />
zugeordnete Bezugspunkt fixiert. Subklassen (z.B. Kreis und Rechteck) erben diesen<br />
Bezugspunkt und die zum Zugriff auf ihn bereitgestellte Metho<strong>de</strong>n. Außer<strong>de</strong>m 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 />
// Instanzmetho<strong>de</strong>n<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 Metho<strong>de</strong>n<br />
public abstract Str<strong>in</strong>g toStr<strong>in</strong>g();<br />
69
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public abstract double umfang();<br />
public abstract double flaeche();<br />
}<br />
import java.lang.*;<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 />
// Instanzmetho<strong>de</strong>n<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 />
70
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public Rechteck(double x, double y, double breite, double hoehe)<br />
{<br />
super();<br />
super.setzeX(x);<br />
super.setzeY(y);<br />
this.setzeBreite(breite);<br />
this.setzeHoehe(hoehe);<br />
}<br />
// Instanzmetho<strong>de</strong>n<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 vorliegen<strong>de</strong> 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 an<strong>de</strong>ren 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 />
71
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
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, Referenztypen und Aufzählungstyp<br />
Referenzen<br />
<strong>Java</strong> erlaubt die Def<strong>in</strong>ition von Klassen, aus <strong>de</strong>nen Objekte erzeugt wer<strong>de</strong>n können.<br />
Objekte können als Referenztypen behan<strong>de</strong>lt wer<strong>de</strong>n, die von Variablen angelegt<br />
und verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Beim Zuweisen von Variablen für Objekte bzw. beim Weiterreichen von Objekten als<br />
Argumente an Metho<strong>de</strong>n wer<strong>de</strong>n Referenzen auf diese Objekte festgelegt.<br />
Bsp.: Referenzen auf Objekte <strong>in</strong> <strong>de</strong>r 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("Operan<strong>de</strong>n von Instanz 1: " +<br />
rechenObj1.ersterOperand + ", " + rechenObj1.zweiterOperand);<br />
System.out.pr<strong>in</strong>tln("Operan<strong>de</strong>n von Instanz 2 vor Zuweisung: " +<br />
rechenObj3.ersterOperand + ", " + rechenObj3.zweiterOperand);<br />
rechenObj3 = rechenObj1;<br />
System.out.pr<strong>in</strong>tln("Operan<strong>de</strong>n 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 bei<strong>de</strong>n Objekte s<strong>in</strong>d tatsaechlich gleich");<br />
}<br />
Der Test mit „==“ 87 bestätigt: Es han<strong>de</strong>lt sich jetzt (nach <strong>de</strong>r Zuweisung) um das<br />
gleiche Objekt, d.h.: die gleiche Referenz.<br />
Die „null“-Referenz. In <strong>Java</strong> gibt es das spezielle Literal null. Es zeigt an, daß<br />
e<strong>in</strong>e Referenz auf ke<strong>in</strong> Objekt verweist. Der Wert ist nur für Referenzen vorgesehen<br />
und kann nicht <strong>in</strong> e<strong>in</strong>en primitiven Typ umgewan<strong>de</strong>lt wer<strong>de</strong>n. Die „null“-Referenz ist<br />
typenlos, d.h.: Sie kann je<strong>de</strong>m Objekt zugewiesen wer<strong>de</strong>n, z.B.:<br />
87 Der Operator „==“ überprüft die Gleichheit <strong>de</strong>r Referenzen.<br />
72
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Po<strong>in</strong>t p = null;<br />
Str<strong>in</strong>g s = null;<br />
Da sich h<strong>in</strong>ter „null“ ke<strong>in</strong> Objekt verbirgt, kann darüber auch ke<strong>in</strong> Objekt aufgerufen<br />
wer<strong>de</strong>n.<br />
<strong>Java</strong> verfügt über e<strong>in</strong> automatisches Speichermanagement. Deshalb braucht <strong>de</strong>r<br />
<strong>Java</strong>-Programmierer sich nicht um die Rückgabe von Speicher zu kümmern, <strong>de</strong>r von<br />
Referenzvariablen belegt ist. E<strong>in</strong> mit nie<strong>de</strong>rer Priorität im H<strong>in</strong>tergrund arbeiten<strong>de</strong>r<br />
„Garbage Collector“ sucht ständig nach Objekten, die nicht mehr referenziert wer<strong>de</strong>n,<br />
um <strong>de</strong>n belegten Speicher freizugeben.<br />
F<strong>in</strong>alizer-Metho<strong>de</strong>n. Sie wer<strong>de</strong>n aufgerufen, kurz bevor das Objekt im Papierkob<br />
lan<strong>de</strong>t und se<strong>in</strong> Speicher freigegeben wird. Zum Erstellen e<strong>in</strong>er F<strong>in</strong>alizer-Metho<strong>de</strong><br />
dient <strong>de</strong>r folgen<strong>de</strong> E<strong>in</strong>trag <strong>in</strong> <strong>de</strong>r Klassen<strong>de</strong>f<strong>in</strong>ition void f<strong>in</strong>alize(){ ... }. Im<br />
Körper dieser Metho<strong>de</strong> können alle möglichen Re<strong>in</strong>igungsprozeduren stehen, die das<br />
Objekt ausführen soll. Der Aufruf <strong>de</strong>r Metho<strong>de</strong> f<strong>in</strong>alize() bewirkt nicht unmittelbar<br />
die Ablage im Papierkorb. Nur durch das Entfernen aller Referenzen auf das Objekt<br />
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 <strong>de</strong>s<br />
Operators new erzeugt wer<strong>de</strong>n.<br />
Aufzählungstyp<br />
Mit <strong>Java</strong> 1.5 wur<strong>de</strong> e<strong>in</strong> Aufzählungstyp <strong>in</strong> <strong>Java</strong> <strong>in</strong>tegriert. Syntaktisch ersche<strong>in</strong>t dieser<br />
Typ wie e<strong>in</strong>e Klasse, die statt <strong>de</strong>s Schlüsselworts class das Schlüsselwort enum<br />
hat.<br />
Konzeptionell s<strong>in</strong>d Aufzählungstypen Variablen und Attributen gleichgestellt.<br />
public, protected, private 88 static 89 f<strong>in</strong>al 90 enum i<strong>de</strong>ntifier { value }<br />
Im e<strong>in</strong>fachsten Anwendungsfall besteht die Def<strong>in</strong>ition e<strong>in</strong>es Aufzählungstyps aus <strong>de</strong>r<br />
durch Kommata vone<strong>in</strong>an<strong>de</strong>r getrennten vollständigen Aufzählung aller Werte.<br />
Bsp. 91 :<br />
public class PR14132<br />
{<br />
enum jahreszeiten { w<strong>in</strong>ter, fruehl<strong>in</strong>g, sommer, herbst };<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
jahreszeiten en<strong>de</strong> = jahreszeiten.w<strong>in</strong>ter;<br />
if (en<strong>de</strong> == jahreszeiten.w<strong>in</strong>ter)<br />
88 e<strong>in</strong>er aus public, protecetd, private<br />
89 optional<br />
90 optional<br />
91 pr14132<br />
73
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
System.out.pr<strong>in</strong>tln("Es ist " + en<strong>de</strong>);<br />
jahreszeiten kalt = jahreszeiten.w<strong>in</strong>ter;<br />
}<br />
}<br />
Die Verwendung von Aufzählungstypen entspricht <strong>de</strong>r von primitiven Typen. Aus<br />
diesem Grund ist ke<strong>in</strong>e Anfor<strong>de</strong>rung von Speicherplatz durch new erfor<strong>de</strong>rlich 92 .<br />
Im Gegensatz zu Ausprägungen von Primitivtypen besitzen Aufzählungstypen jedoch<br />
ke<strong>in</strong>en Vorgabewert mit <strong>de</strong>m sie standardmäßig <strong>in</strong>itialisiert wer<strong>de</strong>n. Die Verwendung<br />
e<strong>in</strong>er nicht <strong>in</strong>itialisierten Ausprägung e<strong>in</strong>es Aufzählungstypen führt zu e<strong>in</strong>em<br />
Übersetzungsfehler 93 .<br />
I<strong>de</strong>ntisch zu <strong>de</strong>n Primitivtypen besitzen Aufzählungstypen ke<strong>in</strong>e I<strong>de</strong>ntität. Zwei mit<br />
<strong>de</strong>mselben Wert belegte Aufzählungen wer<strong>de</strong>n als i<strong>de</strong>ntisch betrachtet.<br />
Aufzählungstypen lassen sich klassenartig ausbauen, z.B. 94 :<br />
public enum Tage<br />
{<br />
montag, dienstag, mittwoch, donnerstag,<br />
freitag, samstag, sonntag;<br />
public boolean istWerktag()<br />
{<br />
switch(this)<br />
{<br />
case sonntag :<br />
case samstag : return false;<br />
<strong>de</strong>fault : return true;<br />
}<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Tage tag = freitag;<br />
System.out.pr<strong>in</strong>tln(tag);<br />
System.out.pr<strong>in</strong>tln(tag.ord<strong>in</strong>al());<br />
System.out.pr<strong>in</strong>tln(tag.istWerktag());<br />
System.out.pr<strong>in</strong>tln(sonntag.istWerktag());<br />
}<br />
}<br />
Aufzählungsklassen enthalten <strong>in</strong> e<strong>in</strong>er Reihung alle Werte <strong>de</strong>r Aufzählung, über die<br />
mit <strong>de</strong>r neuen for-Schleife 95 iteriert wer<strong>de</strong>n kann, z.B.:<br />
public class IterTage<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
for (Tage tag : Tage.values())<br />
System.out.pr<strong>in</strong>tln(tag.ord<strong>in</strong>al() + ": " + tag);<br />
}<br />
}<br />
Die bei<strong>de</strong>n letzten Programme zeigen die Ausgabe:<br />
92 Der Übersetzer verh<strong>in</strong><strong>de</strong>rt die Instanziierung <strong>de</strong>s Aufzählungstyps mit new und bricht beim Versuch mit <strong>de</strong>r<br />
Fehlermeldung enum types may not be <strong>in</strong>stantiated.<br />
93 variable ... might not have been <strong>in</strong>itialized<br />
94 pr14132<br />
95 vgl. 2.4.7.4<br />
74
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.1.4 Konvertieren von Objekten und Primitivtypen<br />
„Cast<strong>in</strong>g“ ist e<strong>in</strong> Mechanismus zum Konvertieren <strong>de</strong>s Werts e<strong>in</strong>es Objekts o<strong>de</strong>r e<strong>in</strong>es<br />
primitiven Typs <strong>in</strong> e<strong>in</strong>en an<strong>de</strong>ren Typ. „Cast<strong>in</strong>g“ ergibt e<strong>in</strong> neues Objekt o<strong>de</strong>r e<strong>in</strong>en<br />
neuen Wert und wirkt sich nicht auf das ursprüngliche Objekt bzw. <strong>de</strong>n<br />
ursprünglichen Wert aus.<br />
Konvertieren von Primitivtypen<br />
Ist <strong>de</strong>r angestrebte Typ „größer“ als <strong>de</strong>r zu konvertieren<strong>de</strong> Typ, ist häufig ke<strong>in</strong><br />
explizites „Cast<strong>in</strong>g“ nötig. E<strong>in</strong> „Byte“ o<strong>de</strong>r 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“ behan<strong>de</strong>lt wer<strong>de</strong>n. Es gehen beim<br />
Konvertieren <strong>de</strong>s Werts ke<strong>in</strong>e Informationen verloren, weil <strong>de</strong>r größere Typ mehr<br />
Genauigkeit bietet als <strong>de</strong>r kle<strong>in</strong>ere.<br />
Ist <strong>de</strong>r angestrebte Typ „kle<strong>in</strong>er“ als <strong>de</strong>r zu konvertieren<strong>de</strong> Typ, ist „Cast<strong>in</strong>g“ nötig.<br />
Explizites Cast<strong>in</strong>g sieht so aus: (typname) wert<br />
„typname“ ist <strong>de</strong>r Name <strong>de</strong>s Typs, auf <strong>de</strong>n konvertiert wird, „wert“ ist e<strong>in</strong> Ausdruck,<br />
<strong>de</strong>r <strong>de</strong>n zu konvertieren<strong>de</strong>n Wert ergibt, z.B.: „(<strong>in</strong>t) x/y;“. Dieser Ausdruck teilt x<br />
durch y und wan<strong>de</strong>lt 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 wer<strong>de</strong>n.<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 an<strong>de</strong>rer<br />
Klassen konvertiert wer<strong>de</strong>n. Die betroffenen Klassen müssen durch Vererbung<br />
mite<strong>in</strong>an<strong>de</strong>r verbun<strong>de</strong>n se<strong>in</strong>, d.h.: E<strong>in</strong> Objekt kann nur <strong>in</strong> e<strong>in</strong>e Instanz <strong>de</strong>r Sub- o<strong>de</strong>r<br />
Superklassen konvertiert wer<strong>de</strong>n, 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 <strong>de</strong>r Superklasse gehen<br />
Informationen, die die Subklasse bereitgestellt hat, verloren. Spezifisches Cast<strong>in</strong>g ist<br />
erfor<strong>de</strong>rlich: (klassename) objekt.<br />
„klassename“ ist <strong>de</strong>r Name <strong>de</strong>r Klasse, <strong>in</strong> die das Objekt konvertiert wer<strong>de</strong>n soll.<br />
75
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
„objekt“ ist e<strong>in</strong>e Referenz auf das zu konvertieren<strong>de</strong> Objekt.<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 verschie<strong>de</strong>ne 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 entsprechen:<br />
Integer, Float, Boolean usw. Mit <strong>de</strong>n <strong>in</strong> diesen Klassen <strong>de</strong>f<strong>in</strong>ierten Klassenmetho<strong>de</strong>n<br />
kann mit Hilfe von new für alle Primitivtypen e<strong>in</strong>e „Art Objekt“ erstellt wer<strong>de</strong>n, z.B.:<br />
„Integer <strong>in</strong>tObjekt = new Integer(13);“. Mit <strong>in</strong>tValue() wird e<strong>in</strong><br />
primitiver „<strong>in</strong>t“-Wert aus e<strong>in</strong>em Integer-Objekt extrahiert, z.B.: <strong>in</strong>t ganzeZahl =<br />
<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> <strong>de</strong>r Regel nur mit Primitivtypen, nicht mit<br />
Objekten. Die Ausnahme zu dieser Regel bil<strong>de</strong>n die Operatoren „==“ und „!=“. Die<br />
Operatoren können für Objekte benutzt wer<strong>de</strong>n und prüfen, ob sich zwei Operan<strong>de</strong>n<br />
auf genau das gleiche Objekt beziehen.<br />
<strong>Java</strong> besitzt ke<strong>in</strong> Konzept für das Überla<strong>de</strong>n (Overload<strong>in</strong>g) von Operatoren. Zum<br />
Vergleichen von Instanzen eigen<strong>de</strong>f<strong>in</strong>ierter Klassen müssen Son<strong>de</strong>rmetho<strong>de</strong>n <strong>in</strong> die<br />
Klasse e<strong>in</strong>bezogen wer<strong>de</strong>n.<br />
Bsp.: Gleichheitstest mit Objekten <strong>de</strong>r „Str<strong>in</strong>g“-Klasse 96 .<br />
Die Str<strong>in</strong>g-Klasse <strong>de</strong>f<strong>in</strong>iert die Metho<strong>de</strong> equals(), die je<strong>de</strong>n Zeichen <strong>de</strong>r<br />
Zeichenkette prüft und „true“ ausgibt, falls die bei<strong>de</strong>n Zeichenketten <strong>de</strong>n<br />
gleichen Wert haben. Nach <strong>de</strong>m Operator „==“ s<strong>in</strong>d die bei<strong>de</strong>n „Str<strong>in</strong>g“-<br />
Objekte nicht gleich, weil sie zwar <strong>de</strong>n gleichen Inhalt haben, aber nicht die<br />
gleichen Objekte s<strong>in</strong>d.<br />
// Beson<strong>de</strong>rheiten 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 folgen<strong>de</strong>n Anweisungen geben wahr o<strong>de</strong>r falsch<br />
// an die Konsole aus<br />
System.out.pr<strong>in</strong>tln("a == b " + (a==b));<br />
System.out.pr<strong>in</strong>tln("c == d " + (c==d));<br />
System.out.pr<strong>in</strong>tln("a == c " + (a==c));<br />
System.out.pr<strong>in</strong>tln("a == \"test\" " + (a=="test"));<br />
System.out.pr<strong>in</strong>tln("c == \"test\" " + (c=="test"));<br />
System.out.pr<strong>in</strong>tln();<br />
System.out.pr<strong>in</strong>tln("a.equals(b) " + a.equals(b));<br />
System.out.pr<strong>in</strong>tln("c.equals(d) " + c.equals(d));<br />
System.out.pr<strong>in</strong>tln("a.equals(c) " + a.equals(c));<br />
// true<br />
// false<br />
// false<br />
// true<br />
// false<br />
// true<br />
// true<br />
// true<br />
96 pr14110<br />
76
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
Kopieren von Objekten<br />
Die clone()-Metho<strong>de</strong> erzeugt e<strong>in</strong> Duplikat als Kopie e<strong>in</strong>es Objekts. Damit e<strong>in</strong><br />
Objekt geklont wer<strong>de</strong>n kann, muß es die „Cloneable“-Schnittstelle unterstützen.<br />
Die Cloneable-Schnittstelle im Paket java.lang hat selbst ke<strong>in</strong>e Metho<strong>de</strong>n, sie<br />
dient lediglich als Indikator dafür, daß e<strong>in</strong> Objekt geklont wer<strong>de</strong>n kann. Das Format<br />
für die clone()-Metho<strong>de</strong> ist: protected Object clone() throws<br />
CloneNotSupportedException<br />
Bsp.: Die Klasse Rechentafel erhält e<strong>in</strong>e clone()-Metho<strong>de</strong> zum Klonen von<br />
Rechentafel-Objekten 97 .<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;<br />
// I<strong>de</strong>ntifikationsnummer<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 />
97 pr14202<br />
77
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
try {<br />
/* Innerhalb <strong>de</strong>s try-Blocks wer<strong>de</strong>n 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 wer<strong>de</strong>n");<br />
}<br />
return o;<br />
}<br />
}<br />
Diese Metho<strong>de</strong> kann dann über e<strong>in</strong> <strong>in</strong> <strong>de</strong>r Klasse Rechentafeltest <strong>in</strong>stanziertes<br />
Objekt <strong>de</strong>r Klasse Rechentafel aufgerufen wer<strong>de</strong>n:<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 <strong>de</strong>r Klasse Rechentafel<br />
Rechentafel erstesRechenobjekt = new Rechentafel(3,2);<br />
System.out.pr<strong>in</strong>tln("E<strong>in</strong>e Instanz <strong>de</strong>r Klasse " +<br />
erstesRechenobjekt.getClass().getName() +<br />
" wur<strong>de</strong> 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 <strong>de</strong>s Objekts");<br />
78
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
System.out.pr<strong>in</strong>tln("Erstes Objekt != Zweites Objekt");<br />
// Manipulation<br />
System.out.pr<strong>in</strong>tln(<br />
"Aen<strong>de</strong>rungen 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 <strong>de</strong>s 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("Aen<strong>de</strong>rungen 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 <strong>de</strong>r Klasse e<strong>in</strong>es Objekts<br />
Die Klasse Class stellt über die Metho<strong>de</strong> getName() <strong>de</strong>n Namen e<strong>in</strong>er Klasse zur<br />
Verfügung: public Str<strong>in</strong>g getName()<br />
Bsp.: Der folgen<strong>de</strong> 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 <strong>de</strong>r Klasse ");<br />
e<strong>in</strong>Rechenobjekt.zeigeKlasse();<br />
betimmt <strong>de</strong>n Namen <strong>de</strong>r Klasse von „e<strong>in</strong>Rechenobjekt“. Die Metho<strong>de</strong> „zeigeKlasse“<br />
enthält die Metho<strong>de</strong> getName() <strong>de</strong>r Klasse Class. Das Objekt, <strong>de</strong>ssen<br />
Klassenzugehörigkeit bestimmt wer<strong>de</strong>n soll ruft die Metho<strong>de</strong> getClass() <strong>de</strong>r Klasse<br />
Object auf. Das Ergebnis dieser Metho<strong>de</strong> ist e<strong>in</strong> Class-Objekt, das die Metho<strong>de</strong><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 />
79
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
E<strong>in</strong> an<strong>de</strong>ren Test bietet <strong>de</strong>r Operator „<strong>in</strong>stanceof“. Er hat zwei Operan<strong>de</strong>n: E<strong>in</strong><br />
Objekt l<strong>in</strong>ks und <strong>de</strong>n Namen <strong>de</strong>r Klasse rechts. Der Ausdruck gibt true o<strong>de</strong>r false<br />
aus, je nach <strong>de</strong>m, ob das Objekt e<strong>in</strong>e Instanz <strong>de</strong>r benannten Klasse ist, z.B.:<br />
if (!(an<strong>de</strong>resObj <strong>in</strong>stanceof Rechentafel)) return false;<br />
<strong>de</strong>r Operator <strong>in</strong>stanceof kann auch als Schnittstelle benutzt wer<strong>de</strong>n. Falls e<strong>in</strong><br />
Objekt e<strong>in</strong>e Schnittstelle implementiert, gibt <strong>in</strong>stanceof mit <strong>de</strong>m<br />
Schnittstellennamen auf <strong>de</strong>r rechten Seite true aus.<br />
1.4.1.6 Innere (lokale) und anonyme Klassen<br />
Bisher gab es nur Klassen, die entwe<strong>de</strong>r <strong>in</strong> Paketen organisiert waren o<strong>de</strong>r sich <strong>in</strong><br />
e<strong>in</strong>em Verzeichnis befan<strong>de</strong>n. Diese Form von Klassen heißen „Top-Level“-Klassen.<br />
Klassen können aber auch <strong>in</strong> an<strong>de</strong>re Klassen aufgenommen wer<strong>de</strong>n. Das nennt sich<br />
dann „<strong>in</strong>nere Klassen“.<br />
class Aussen<br />
{<br />
...<br />
class Innen<br />
{<br />
...<br />
}<br />
...<br />
}<br />
Lokale Klassen<br />
Seit JDK 1.1 kann man <strong>in</strong>nerhalb e<strong>in</strong>er bestehen<strong>de</strong>n Klasse z.B. X e<strong>in</strong>e neue Klasse<br />
z.B. Y <strong>de</strong>f<strong>in</strong>ieren 98 . Diese Klasse ist nur <strong>in</strong>nerhalb von X sichtbar. Objekte von Y<br />
können damit nur aus X erzeugt wer<strong>de</strong>n. Y kann aber auf alle Instanzmerkmale von X<br />
zugreifen. Bei <strong>de</strong>r Instanzierung wird (neben e<strong>in</strong>em impliziten this-Zeiger) e<strong>in</strong><br />
weiterer Verweis auf die erzeugen<strong>de</strong> Instanz <strong>de</strong>r umschließen<strong>de</strong>n Klasse übergeben,<br />
<strong>de</strong>r es ermöglicht, auf sie zuzugreifen. Für <strong>in</strong>nere Klassen wird e<strong>in</strong>e eigenständige<br />
Datei mit <strong>de</strong>r Namenskonvention Umgeben<strong>de</strong>Klasse$<strong>in</strong>nereKllasse erzeugt.<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, das<br />
e<strong>in</strong>en Event-Handler benötigt, e<strong>in</strong>e lokale Klasse <strong>de</strong>f<strong>in</strong>iert und aus e<strong>in</strong>er passen<strong>de</strong>n<br />
Adapter-Klasse abgeleitet. Es braucht nicht mehr das gesamte Interface<br />
implementiert zu wer<strong>de</strong>n, ( <strong>de</strong>nn die Metho<strong>de</strong>nrümpfe wer<strong>de</strong>n ja aus <strong>de</strong>r<br />
Adapterklasse geerbt,) son<strong>de</strong>rn lediglich die tatsächlich benötigetn Metho<strong>de</strong>n.<br />
Anonyme Klassen<br />
E<strong>in</strong>e Variante <strong>de</strong>r lokalen Klassen s<strong>in</strong>d anonyme Klassen. Sie wer<strong>de</strong>n ebenfalls lokal<br />
zu e<strong>in</strong>er an<strong>de</strong>ren Klasse erzeugt, kommen aber ohne Klassennamen aus.<br />
98 Im JDK wird das Konzept als Inner Classes bezeichnet<br />
80
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Klassen<strong>de</strong>f<strong>in</strong>ition: new BasisKlasse(parameter) { /* <strong>in</strong>ner class<br />
methods and data */ }<br />
Damit e<strong>in</strong>e anonyme Klasse überhaupt irgen<strong>de</strong><strong>in</strong>er s<strong>in</strong>nvollen Aufgabe zugeführt<br />
wer<strong>de</strong>n kann, muß sie aus e<strong>in</strong>er an<strong>de</strong>ren Klasse abgeleitet se<strong>in</strong> o<strong>de</strong>r e<strong>in</strong><br />
bestehen<strong>de</strong>s Interface implementieren.<br />
Bsp. 99 :<br />
public class Anonymous<br />
{<br />
private TestClass test()<br />
{<br />
return new TestClass()<br />
{<br />
public void hello()<br />
{ System.out.pr<strong>in</strong>tln("overrid<strong>de</strong>n test!"); } //hello()<br />
}; //class TestClass<br />
} //test()<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
TestClass myRV;<br />
myRV = (new Anonymous()).test();<br />
myRV.hello();<br />
System.out.pr<strong>in</strong>tln( myRV <strong>in</strong>stanceof TestClass);<br />
System.out.pr<strong>in</strong>tln( myRV.getClass().getName() );<br />
} //end ma<strong>in</strong>()<br />
} //class Anonymous<br />
class TestClass<br />
{<br />
public void hello()<br />
{<br />
System.out.pr<strong>in</strong>tln("orig<strong>in</strong>al");<br />
} //hello()<br />
} //class TestClass<br />
Adapterklassen<br />
E<strong>in</strong>e Adapterklasse implementiert e<strong>in</strong> vorgegebenes Interface mit leeren<br />
Metho<strong>de</strong>nrümpfen. Adapterklassen können verwen<strong>de</strong>t wer<strong>de</strong>n, wenn aus e<strong>in</strong>em<br />
Interface lediglich e<strong>in</strong> Teil <strong>de</strong>r Metho<strong>de</strong>n benötigt wird, <strong>de</strong>r Rest aber un<strong>in</strong>teressant<br />
ist. In diesem Fall leitet man e<strong>in</strong>e neue Klasse aus <strong>de</strong>r Adapterklasse ab, anstatt das<br />
zugehörige Interface zu implementieren und überlagert die benötigten Metho<strong>de</strong>n. Alle<br />
übrigen Metho<strong>de</strong>n <strong>de</strong>s Interfaces wer<strong>de</strong>n von <strong>de</strong>r Basisklasse zur Verfügung gestellt.<br />
Zu je<strong>de</strong>m <strong>de</strong>r Low-Level-Ereignisempfänger stellt java.awt.event e<strong>in</strong>e passen<strong>de</strong><br />
Adapterklasse zur Verfügung.<br />
99 pr14160<br />
81
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.1.7 Schnittstellen und Pakete<br />
1.4.1.7.1 Schnittstellen<br />
Def<strong>in</strong>ition<br />
E<strong>in</strong>e Schnittstelle ist <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e Sammlung von Metho<strong>de</strong>nnamen 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 Metho<strong>de</strong>n und Konstanten (f<strong>in</strong>ale Daten)<br />
<strong>de</strong>f<strong>in</strong>ieren 100 .<br />
Schnittstellen bil<strong>de</strong>n <strong>in</strong> <strong>Java</strong> <strong>de</strong>n Ersatz für Mehrfachvererbung. E<strong>in</strong>e Klasse kann<br />
<strong>de</strong>mnach 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 beson<strong>de</strong>re Form <strong>de</strong>r Klasse, die ausschließlich<br />
abstrakte Metho<strong>de</strong>n 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" wer<strong>de</strong>n formal wie Klassen <strong>de</strong>f<strong>in</strong>iert, z.B.:<br />
public <strong>in</strong>terface me<strong>in</strong>eSchnittstelle<br />
{<br />
// Abstrakte Metho<strong>de</strong>n<br />
}<br />
bzw.<br />
public <strong>in</strong>terface me<strong>in</strong>eSpezialschnittstelle extends me<strong>in</strong>eSchnittstelle<br />
{<br />
// Abstrakte Metho<strong>de</strong>n<br />
}<br />
"Interfaces" können benutzt wer<strong>de</strong>n, <strong>in</strong><strong>de</strong>m sie <strong>in</strong> e<strong>in</strong>er Klasse implementiert wer<strong>de</strong>n,<br />
z.B.:<br />
public class Me<strong>in</strong>eKlasse extends Object implements me<strong>in</strong>eSchnittstelle<br />
{<br />
/* Normale Klassen<strong>de</strong>f<strong>in</strong>ition + Metho<strong>de</strong>n 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 Klassen<strong>de</strong>f<strong>in</strong>ition + Metho<strong>de</strong>n aus me<strong>in</strong>erSchnittstelle1<br />
und me<strong>in</strong>erSchnittstelle2 */<br />
}<br />
Verwendung<br />
Bei <strong>de</strong>r 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 Metho<strong>de</strong>n, die im Interface <strong>de</strong>f<strong>in</strong>iert s<strong>in</strong>d, zu implementieren. Die<br />
100 Angaben zur Implementierung s<strong>in</strong>d nicht möglich<br />
82
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Implementierung e<strong>in</strong>es Interface wird durch das Schlüsselwort „implements“ bei <strong>de</strong>r<br />
Klassen<strong>de</strong>f<strong>in</strong>ition angezeigt.<br />
1. Bsp.: Natürliche Ordnungsbeziehungen s<strong>in</strong>d <strong>in</strong> <strong>Java</strong> über das Interface<br />
Comparable e<strong>in</strong>gefangen:<br />
/**************** Comparable.java *****************************<br />
/** Das Interface <strong>de</strong>klariert e<strong>in</strong>e Metho<strong>de</strong> anhand <strong>de</strong>r sich das<br />
* das aufgerufene Objekt mit <strong>de</strong>m uebergebenen vergleicht.<br />
* Fuer je<strong>de</strong>n vom Objekt abgeleiteten Datentyp muss e<strong>in</strong>e solche<br />
* Vergleichsklasse implementiert wer<strong>de</strong>n.<br />
* Die Metho<strong>de</strong> erzeugt e<strong>in</strong>e Fehlermeldung, wenn "a" e<strong>in</strong> Objekt<br />
* e<strong>in</strong>er an<strong>de</strong>ren Klasse als dieses Objekt ist.<br />
*<br />
* <strong>in</strong>t compareTo(Comparable a)<br />
* liefert 0, wenn this == 0<br />
* liefert < 0, wenn this < a<br />
* liefert > 0, wenn this > a<br />
*<br />
*/<br />
public <strong>in</strong>terface Comparable<br />
{<br />
public <strong>in</strong>t compareTo(Comparable a);<br />
}<br />
Zahlreiche von <strong>Java</strong> bereitgestellte Referenztypen (Klassen) haben dieses Interface<br />
implementiert. Deshalb sortiert die nachfolgen<strong>de</strong>n Sortierrout<strong>in</strong>e (Sort) Str<strong>in</strong>g- und<br />
Zahlen-Objekte, wie <strong>de</strong>r Aufrufe aus SortTest beweisen.<br />
public class Sort<br />
{<br />
public void sort(Comparable x[])<br />
{<br />
bubbleSort(x);<br />
}<br />
public void bubbleSort(Comparable x[])<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 (x[i].compareTo(x[j]) > 0)<br />
{<br />
Comparable temp = x[i];<br />
x[i] = x[j];<br />
x[j] = temp;<br />
}<br />
}<br />
}<br />
}<br />
}<br />
public class SortTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g sa[] = {<br />
"Juergen","Christian","Bernd","Werner","Uwe",<br />
"Erich","Kurt","Karl","Emil","Ernst"<br />
};<br />
// Ausgabe <strong>de</strong>s noch nicht sortierten x<br />
System.out.pr<strong>in</strong>tln("Vor <strong>de</strong>m Sortieren:");<br />
for (<strong>in</strong>t i = 0; i < sa.length; i++)<br />
83
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
System.out.pr<strong>in</strong>tln("sa["+i+"] = " + sa[i]);<br />
}<br />
// Aufruf <strong>de</strong>r Sortierout<strong>in</strong>e<br />
Sort s = new Sort();<br />
s.sort(sa);<br />
// Gib das sortierte Feld x aus<br />
System.out.pr<strong>in</strong>tln();<br />
System.out.pr<strong>in</strong>tln("Nach <strong>de</strong>m Sortieren:");<br />
for (<strong>in</strong>t i = 0; i < sa.length; i++)<br />
{<br />
System.out.pr<strong>in</strong>tln("sa["+i+"] = " + sa[i]);<br />
}<br />
System.out.pr<strong>in</strong>tln();<br />
<strong>in</strong>t za[] = { 50, 70, 80, 10, 20, 30, 1, 2, 3, 99, 12, 11, 13};<br />
Integer o[] = new Integer[za.length];<br />
for (<strong>in</strong>t i = 0; i < za.length; i++)<br />
{<br />
o[i] = new Integer(za[i]);<br />
}<br />
// Ausgabe <strong>de</strong>s noch nicht sortierten za<br />
System.out.pr<strong>in</strong>tln("Vor <strong>de</strong>m Sortieren:");<br />
for (<strong>in</strong>t i = 0; i < za.length; i++)<br />
{<br />
System.out.pr<strong>in</strong>tln("za["+i+"] = " + za[i]);<br />
}<br />
// Aufruf <strong>de</strong>r Sortierout<strong>in</strong>e<br />
Sort zs = new Sort();<br />
zs.sort(o);<br />
// Gib das sortierte Feld x aus<br />
for (<strong>in</strong>t i = 0; i < za.length; i++)<br />
{<br />
za[i] = ((Integer) o[i]).<strong>in</strong>tValue();;<br />
}<br />
System.out.pr<strong>in</strong>tln();<br />
System.out.pr<strong>in</strong>tln("Nach <strong>de</strong>m Sortieren:");<br />
for (<strong>in</strong>t i = 0; i < za.length; i++)<br />
{<br />
System.out.pr<strong>in</strong>tln("za["+i+"] = " + za[i]);<br />
}<br />
}<br />
}<br />
2. Bsp. 101 : Erweiterte Form <strong>de</strong>r for-Schleife for {Type i<strong>de</strong>ntifier : expr) {<br />
... } <strong>in</strong> <strong>Java</strong> 1. 5<br />
1.4.1.7.2 Pakete<br />
Def<strong>in</strong>ition: package packageName; // Am Anfang <strong>de</strong>r Quelldatei<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> <strong>de</strong>n Bibliotheken an<strong>de</strong>rer Programmiersprachen. Pakete<br />
ermöglichen, daß modulare Klassengruppen nur verfügbar s<strong>in</strong>d, wenn sie gebraucht<br />
wer<strong>de</strong>n. Potentielle Konflikte zwischen Klassenamen <strong>in</strong> unterschiedlichen<br />
Klassengruppen können dadurch vermie<strong>de</strong>n wer<strong>de</strong>n.<br />
Für Metho<strong>de</strong>n und Variablen <strong>in</strong>nerhalb von Paketen besteht e<strong>in</strong>e<br />
Zugriffsschutzschablone. Je<strong>de</strong>s Paket ist gegenüber an<strong>de</strong>ren, nicht zum Paket<br />
101 vgl. 2.4.7.4<br />
84
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
zählen<strong>de</strong>n Klassen abgeschirmt. Klassen, Metho<strong>de</strong>n o<strong>de</strong>r Variablen s<strong>in</strong>d nur sichtbar<br />
für Klassen im gleichen Paket. Klassen, die ohne „package“ Anweisung <strong>de</strong>f<strong>in</strong>iert s<strong>in</strong>d,<br />
wer<strong>de</strong>n vom Compiler <strong>in</strong> e<strong>in</strong> „Standardpaket“ gestellt. Voraussetzung dafür ist: Die<br />
„.java“- und „.class“-Dateien dieses Pakets bef<strong>in</strong><strong>de</strong>n sich im aktuellen Verzeichnis<br />
(o<strong>de</strong>r <strong>in</strong> e<strong>in</strong>en darunter liegen<strong>de</strong>n Klassenverzeichnis).<br />
Die <strong>Java</strong>-Klassenbibliothek 102 von <strong>Java</strong> 1.0 enthält folgen<strong>de</strong> 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ßer<strong>de</strong>m die Son<strong>de</strong>rklassen für die<br />
Primitivtypen (Integer, Character, Float, etc.)<br />
Object<br />
Class<br />
Str<strong>in</strong>g<br />
Str<strong>in</strong>gBuffer<br />
Thread<br />
ThreadGroup<br />
Throwable<br />
System<br />
Runtime<br />
Process<br />
Math<br />
Number<br />
Character<br />
Aus dieser Klasse leiten sich alle weiteren Klassen ab. Ohne explizite Angabe <strong>de</strong>r Klasse,<br />
die e<strong>in</strong>e neue Klasse erweitern soll, erweitert die neue Klasse die Object-Klasse. Die<br />
Klasse Object ist die Basis-Klasse je<strong>de</strong>r an<strong>de</strong>ren Klasse <strong>in</strong> <strong>Java</strong>. Sie <strong>de</strong>f<strong>in</strong>iert Metho<strong>de</strong>n,<br />
die von allen Klasse <strong>in</strong> <strong>Java</strong> unterstützt wer<strong>de</strong>n.<br />
Für je<strong>de</strong> <strong>in</strong> <strong>Java</strong> <strong>de</strong>f<strong>in</strong>ierte Klasse gibt es e<strong>in</strong>e Instanz von Class, die diese Klasse<br />
beschreibt<br />
Enthält Metho<strong>de</strong>n zur Manipulation von <strong>Java</strong>-Zeichenketten<br />
Dient zum Erstellen von <strong>Java</strong>-Zeichenketten<br />
Stellt e<strong>in</strong>en Ausführungs-Thread <strong>in</strong> e<strong>in</strong>em <strong>Java</strong>-Programm dar. Je<strong>de</strong>s Programm kann<br />
mehrere Threads laufen lassen<br />
Ermöglicht die Verknüpfung von Threads untere<strong>in</strong>an<strong>de</strong>r. E<strong>in</strong>ige Thread-Operationen<br />
können nur von Threads aus <strong>de</strong>r gleichen ThreadGroup ausgeführt wer<strong>de</strong>n.<br />
Ist die Basisklasse für Ausnahmen. Je<strong>de</strong>s Objekt, das mit <strong>de</strong>r "catch"-Anweisung<br />
gefangen o<strong>de</strong>r mit <strong>de</strong>r "throw"-Anweisung verworfen wird, muß e<strong>in</strong>e Subklasse von<br />
Throwable se<strong>in</strong>.<br />
Stellt spezielle Utilities auf Systemebene zur Verfügung<br />
Enthält e<strong>in</strong>e Vielzahl gleicher Funktionen wie System, behan<strong>de</strong>lt aber auch das Laufen<br />
externer Programme<br />
Stellt e<strong>in</strong> externes Programm dar, das von e<strong>in</strong>em Runtime-Objekt gestartet wur<strong>de</strong>.<br />
Stellt e<strong>in</strong>e Reihe mathematischer Funktionen zur verfügung<br />
Ist die Basisklasse für Double,Float, Integer und Long (Objeckt-Wrapper)<br />
Ist e<strong>in</strong> Objekt-Wrapper für <strong>de</strong>n datentyp char und enthält e<strong>in</strong>e Reihe nützlicher<br />
zeichenorientierter Operationen<br />
Ist e<strong>in</strong> Objekt-Wrapper für <strong>de</strong>n Datentyp boolean<br />
Boolean<br />
ClassLoa<strong>de</strong>r Ermöglicht <strong>de</strong>r Laufzeit-Umgebung von <strong>Java</strong> neue Klassen h<strong>in</strong>zuzufügen<br />
SecurityManager Legt die Sicherheits-Restriktionen <strong>de</strong>r aktuellen Laufzeitumgebung fest. Viele <strong>Java</strong>-<br />
Klassen benutzen <strong>de</strong>n Security-Manager zur Sicherstellung, daß e<strong>in</strong>e Operation auch<br />
tatsächlich genehmigt ist.<br />
Compiler Ermöglicht, falls vorhan<strong>de</strong>n, <strong>de</strong>n Zugriff auf <strong>de</strong>n "just-<strong>in</strong>-time" Compiler<br />
Abb.: Klassen <strong>de</strong>s java.lang-Pakets<br />
Zusätzlich enthält das java.lang-Paket noch zwei Schnittstellen:<br />
Cloneable<br />
Runnable<br />
Muß von e<strong>in</strong>em an<strong>de</strong>ren Objekt implementiert wer<strong>de</strong>n, das dann geklont o<strong>de</strong>r kopiert<br />
wer<strong>de</strong>n kann<br />
Wird zusammen mit <strong>de</strong>r Thread-Klasse benutzt, um die aufgerufene Metho<strong>de</strong> zu<br />
<strong>de</strong>f<strong>in</strong>ieren, wenn e<strong>in</strong> Thread gestartet wird.<br />
Abb.: Schnittstellen im java.lang-Paket<br />
- java.util<br />
102 Die Klassenbibliothek <strong>de</strong>s JDK bef<strong>in</strong><strong>de</strong>t sich <strong>in</strong> e<strong>in</strong>em Paket mit <strong>de</strong>m namen „java“.<br />
85
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- java.io: Klassen zum Lesen und Schreiben von Datenströmen und zum<br />
Handhaben von Dateien.<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 Wi<strong>de</strong> 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<br />
Applet.<br />
Die <strong>Java</strong> Version 1.1 hat die Klassenbibliothek umfassend erweitert 103 :<br />
Paket<br />
Be<strong>de</strong>utung<br />
<strong>Java</strong>.applet<br />
Applets<br />
<strong>Java</strong>.awt<br />
Abstract W<strong>in</strong>dow Toolkit<br />
<strong>Java</strong>.awt.datatranfer<br />
ClipBoard-Funktionalität (Copy / Paste)<br />
<strong>Java</strong>.awt.event<br />
AWT Event-handl<strong>in</strong>g<br />
<strong>Java</strong>.awt.image<br />
Bildanzeige<br />
<strong>Java</strong>.beans<br />
<strong>Java</strong> Beans<br />
<strong>Java</strong>.io<br />
E<strong>in</strong>- und Ausgabe, Streams<br />
<strong>Java</strong>.lang<br />
Elementare Sprachunterstützung<br />
<strong>Java</strong>.lang.reflect<br />
Introspektion, besserer Zugriff auf Klassen durch<br />
Debugger und Inspektoren<br />
<strong>Java</strong>.math<br />
<strong>Java</strong>.net<br />
Netzzugriffe<br />
<strong>Java</strong>.rmi<br />
Remote Method Invocation, Zugriff auf Objekte <strong>in</strong><br />
an<strong>de</strong>ren virtuellen Masch<strong>in</strong>en<br />
<strong>Java</strong>.rmi.dgc<br />
RMI Distributed Garbage Collection<br />
<strong>Java</strong>.rmi.registry Verwaltet Datenbank, die RMI-Verb<strong>in</strong>dungen<br />
koord<strong>in</strong>iert<br />
<strong>Java</strong>.rmi.server<br />
RMI-Server<br />
<strong>Java</strong>.security<br />
Sicherheit durch digitale Signaturen, Schlüssel<br />
<strong>Java</strong>.security.aci<br />
Access Control Lists<br />
<strong>Java</strong>.security.<strong>in</strong>terfaces<br />
Digital Signature Algorithm (DAS-Klassen)<br />
<strong>Java</strong>.sql<br />
Datenbankzugriff (JDBC)<br />
<strong>Java</strong>.util<br />
Diverse Utilities, Datenstrukturen<br />
<strong>Java</strong>.util.zip<br />
JAR-Files, Kompression, Prüfsummen<br />
Abb.: Klassenbibliothek <strong>de</strong>r <strong>Java</strong>-Version 1.1<br />
Verwendung<br />
Je<strong>de</strong> Klasse ist Bestandteil e<strong>in</strong>es Pakets. Der vollständige Name e<strong>in</strong>er Klasse<br />
besteht aus <strong>de</strong>m Namen <strong>de</strong>s Pakets, danach kommt <strong>de</strong>r e<strong>in</strong> Punkt, gefolgt von <strong>de</strong>m<br />
eigentlichen Namen <strong>de</strong>r Klasse.<br />
Zur Verwendung e<strong>in</strong>er Klasse muß angegeben wer<strong>de</strong>n, <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 <strong>de</strong>s Klassenprogramms wer<strong>de</strong>n die gewünschten Klassen mit Hilfe <strong>de</strong>r import-<br />
Anweisung e<strong>in</strong>gebun<strong>de</strong>n, z.B.:<br />
import java util.*;<br />
103 Zusätzlich 15 weitere Packages, etwa 500 Klassen und Schnittstellen<br />
86
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
......<br />
Date d = new Date();<br />
Die import-Anweisung gibt es <strong>in</strong> unterschiedlichen Ausprägungen:<br />
- Mit "import paket.Klasse" wird genau e<strong>in</strong>e Klasse importiert, alle an<strong>de</strong>ren Klassen <strong>de</strong>s<br />
Pakets bleiben verborgen<br />
- Mit "import paket.*" 104 können alle Klassen <strong>de</strong>s angegebenen Pakets auf e<strong>in</strong>mal importiert<br />
wer<strong>de</strong>n.<br />
Standardmäßig haben <strong>Java</strong>-Klassen Zugang zu <strong>de</strong>n <strong>in</strong> java.lang bef<strong>in</strong>dlichen<br />
Klassen. Klassen aus an<strong>de</strong>ren Paketen müssen explizit über <strong>de</strong>n Paketnamen<br />
e<strong>in</strong>bezogen o<strong>de</strong>r <strong>in</strong> die Quelldatei importiert wer<strong>de</strong>n.<br />
Statische Imports<br />
Mit <strong>de</strong>r Überarbeitung zur Sprachversion 1.5 wur<strong>de</strong>n durch die statischen Importe<br />
e<strong>in</strong>e abkürzen<strong>de</strong> Schreibweise für importierte statische Metho<strong>de</strong>n etabliert:<br />
Durch die zusätzliche Angabe <strong>de</strong>s Schlüsselworts static vor <strong>de</strong>r vollqualifizierte<br />
Klasseni<strong>de</strong>ntifikation stehen als Resultate alle als statisch <strong>de</strong>klarierten Metho<strong>de</strong>n<br />
zum direkten Aufruf zur Verfügung.<br />
Bsp.: Über statische Importe kann die Funktion max() aus Math importiert wer<strong>de</strong>n,<br />
so dass <strong>de</strong>r Klassenname entfallen kann<br />
import static java.lang.Math.max;<br />
class StatischesImport<br />
{<br />
static <strong>in</strong>t max3(<strong>in</strong>t a, <strong>in</strong>t b, <strong>in</strong>t c)<br />
{<br />
return max(a, max(b,c));<br />
}<br />
}<br />
104 type import on <strong>de</strong>mand, d.h.: Die Klasse wird erst dann <strong>in</strong> <strong>de</strong>m angegebenen Paket gesucht, wenn das<br />
Programm sie wirklich benötigt.<br />
87
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.1.8 Polymorphismus und B<strong>in</strong><strong>de</strong>n<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. 105 : Das folgen<strong>de</strong> Programm Poly ist e<strong>in</strong>e Anwendung zu <strong>de</strong>r bereits<br />
bekannten Klassenhierarchie für geometrische Objekte. Es behan<strong>de</strong>lt<br />
Ersche<strong>in</strong>ungsformen <strong>de</strong>s 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 />
// Folgen<strong>de</strong> 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 <strong>de</strong>r Metho<strong>de</strong>n 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 <strong>de</strong>r Wert von geom1 e<strong>in</strong>e Referenz auf<br />
e<strong>in</strong> Objekt <strong>de</strong>r Klasse Kreis, daher wer<strong>de</strong>n die im Kreis<br />
<strong>de</strong>f<strong>in</strong>ierten (allgeme<strong>in</strong>er: die <strong>in</strong> Kreis <strong>de</strong>f<strong>in</strong>ierten<br />
bzw. ererbten) Metho<strong>de</strong>n toStr<strong>in</strong>g() und umfang() ausgefuehrt.<br />
*/<br />
// Aufruf <strong>de</strong>r Metho<strong>de</strong>n toStr<strong>in</strong>g() und umfang() ueber o<br />
// System.out.pr<strong>in</strong>tln(o.toStr<strong>in</strong>g());<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 <strong>de</strong>r <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 o<strong>de</strong>r erbt ke<strong>in</strong>e<br />
Def<strong>in</strong>ition von umfang(), daher akzeptiert <strong>de</strong>r <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 <strong>de</strong>r <strong>Java</strong>-Compiler<br />
(zur Uebesersetzungszeit) aus <strong>de</strong>m gleichen Grund wie<br />
zuvor nicht.<br />
Die Schreibweise (Rechteck) o.umfang() be<strong>de</strong>utet auch:<br />
Der Rueckgabewert von o.umfang() soll als Rechteck-<br />
105 Vgl. pr14181<br />
88
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Referenz <strong>in</strong>terpretiert wer<strong>de</strong>n.<br />
*/<br />
System.out.pr<strong>in</strong>tln("Umfang: " + ((Rechteck) o).umfang());<br />
/* o ist e<strong>in</strong> Object, (Rechteck o) be<strong>de</strong>utet: o soll als<br />
Rechteck <strong>in</strong>terprtiert wer<strong>de</strong>n. Fuer Rechteck-Objekte<br />
ist umfang() erkaert, <strong>de</strong>r <strong>Java</strong>-Compiler akzeptiert<br />
(zur Uebersetzungszeit) ((Rechteck o).umfang().<br />
Zur Laufzeit wird die <strong>in</strong> Recteck <strong>de</strong>f<strong>in</strong>ierte<br />
(allgeme<strong>in</strong>er: die <strong>in</strong> Recheck <strong>de</strong>f<strong>in</strong>ierte bzw. ererbte)<br />
Metho<strong>de</strong> umfang() ausgefuehrt.<br />
*/<br />
}<br />
}<br />
B<strong>in</strong><strong>de</strong>n<br />
Das Schema e<strong>in</strong>er Botschaft wird aus "Empfänger Metho<strong>de</strong> Argument" gebil<strong>de</strong>t.<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><strong>de</strong>n. Trotz Polymorphismus und Vererbung ist <strong>de</strong>r Metho<strong>de</strong>nname (oft. Selektor<br />
genannt) nur e<strong>in</strong>e Verknüpfung zum Programmco<strong>de</strong> e<strong>in</strong>er Metho<strong>de</strong>. Vor <strong>de</strong>r<br />
Ausführung e<strong>in</strong>er Metho<strong>de</strong> muß daher e<strong>in</strong>e genaue Zuordnung zwischen <strong>de</strong>m<br />
Selektor und <strong>de</strong>r physikalischen Adresse <strong>de</strong>s tatsächlichen Programmco<strong>de</strong>s erfolgen<br />
(B<strong>in</strong><strong>de</strong>n o<strong>de</strong>r L<strong>in</strong>ken).<br />
In <strong>de</strong>r objektorientierten Programmierung unterschei<strong>de</strong>t man: frühes und spätes<br />
B<strong>in</strong><strong>de</strong>n:<br />
Frühes B<strong>in</strong><strong>de</strong>n: E<strong>in</strong> Compiler ordnet schon zum Zeitpunkt <strong>de</strong>r Übersetzung <strong>de</strong>s Programms die<br />
tatsächliche, physikalische Adresse <strong>de</strong>r Metho<strong>de</strong> <strong>de</strong>m Metho<strong>de</strong>naufruf zu.<br />
Spätes B<strong>in</strong><strong>de</strong>n: Hier wir erst zur Laufzeit <strong>de</strong>s Programms die tatsächliche Verknüpfung zwischen<br />
Selektor und Co<strong>de</strong> hergestellt. Die richtige Verb<strong>in</strong>dung übernimmt das Laufzeitprogramm <strong>de</strong>r<br />
Programmiersprache.<br />
<strong>Java</strong> unterstützt das Konzept <strong>de</strong>s „Late B<strong>in</strong>d<strong>in</strong>g“.<br />
89
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2 Klassen <strong>de</strong>s Pakets java.lang<br />
1.4.2.1 Die Klasse Object<br />
Die Object-Klasse ist die Basisklasse für je<strong>de</strong> an<strong>de</strong>re Klasse <strong>in</strong> <strong>Java</strong>. Sie <strong>de</strong>f<strong>in</strong>iert<br />
Metho<strong>de</strong>n, die von allen Klassen <strong>in</strong> <strong>Java</strong> unterstützt wer<strong>de</strong>n.<br />
Test auf Gleichheit von Objekten: public boolean equals(Object obj)<br />
Darüber kann ermittelt wer<strong>de</strong>n, ob zwei Objekte gleich s<strong>in</strong>d. Subklassen<br />
überschreiben diese Metho<strong>de</strong> zur Durchführung e<strong>in</strong>es <strong>in</strong>haltlichen Vergleichs. In<br />
je<strong>de</strong>r Klasse ist die Metho<strong>de</strong> auch gut aufgehoben, <strong>de</strong>nn nur e<strong>in</strong> Objekt weiß, wann<br />
es mit e<strong>in</strong>em an<strong>de</strong>ren gleich ist. Ob zwei Referenzen auf das gleiche Objekt zeigen,<br />
läßt sich durch <strong>de</strong>n Vergleichsoperator == feststellen.<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 wer<strong>de</strong>n.<br />
Berechnung von Hashco<strong>de</strong>: public <strong>in</strong>t hashCo<strong>de</strong>() berechnet <strong>de</strong>n<br />
numerischen Wert, <strong>de</strong>r als In<strong>de</strong>x zur Speicherung e<strong>in</strong>es Objekts <strong>in</strong> e<strong>in</strong>er Hashtabelle<br />
verwen<strong>de</strong>t wer<strong>de</strong>n kann.<br />
Hashso<strong>de</strong>s wer<strong>de</strong>n zur Speicherung von Elementen <strong>in</strong> Hashtabellen. Das s<strong>in</strong>d<br />
Datenstrukturen, die e<strong>in</strong>e effizienten Zugriff auf ihre Elemente erlauben.<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 wer<strong>de</strong>n, falls es die Cloneable-<br />
Schnittstelle unterstützt.<br />
Fragen nach <strong>de</strong>m Namen <strong>de</strong>r Objektklasse: public f<strong>in</strong>al Class getClass()<br />
Benachrichtungsmechanismus. Hierfür gibt es die Metho<strong>de</strong>n: public f<strong>in</strong>al void<br />
notify() bzw. public f<strong>in</strong>al void notifyAll() und public f<strong>in</strong>al void<br />
wait() throws InterruptedException bzw. public f<strong>in</strong>al void<br />
wait(long timeout) throws InterruptedException. Threads 106 können<br />
mite<strong>in</strong>an<strong>de</strong>r kommunizieren und gegenseitig auf sich warten. Object <strong>de</strong>f<strong>in</strong>iert fünf<br />
Versionen von wait() und notify() zur Synchronisation von Threads.<br />
Aufräumen: protected void f<strong>in</strong>alize() throws Throwable. E<strong>in</strong>e spezielle<br />
Metho<strong>de</strong> f<strong>in</strong>alize() wird immer dann aufgerufen, wenn <strong>de</strong>r Garbage Collector<br />
das Objekt entfernen möchte. Objekte sollten diese Funktion überschreiben, wenn<br />
sie bspw. noch Dateien schliessen müssen.<br />
Objekti<strong>de</strong>ntifikation: public Str<strong>in</strong>g toStr<strong>in</strong>g(). Je<strong>de</strong>s Objekt sollte sich durch<br />
die Metho<strong>de</strong> toStr<strong>in</strong>g() mit e<strong>in</strong>er Zeichenkette i<strong>de</strong>ntifizieren. Die Zeichenkette gibt<br />
die Inhalt <strong>de</strong>r Attribute an. Neue Objekte sollten diese Metho<strong>de</strong> überschreiben. Ist<br />
dies nicht <strong>de</strong>r Fall, gelangt das zugehörige Programm zur Standardimplementierung<br />
<strong>in</strong> Object.<br />
106 vgl. 1.4.2.4<br />
90
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.2 Die Class-Klasse<br />
Diese Klasse stellt Metho<strong>de</strong>n zur Abfrage von Eigenschaften von Klassen zur<br />
Verfügung und erlaubt es, Klassen dynamisch zu la<strong>de</strong>n und Instanzen dynamisch zu<br />
erzeugen. In <strong>Java</strong> hat je<strong>de</strong> Klasse e<strong>in</strong>e entsprechen<strong>de</strong> Instanz von Class. In <strong>Java</strong><br />
liegen Klassen selbst als Objekt vor. Neben normalen Klassen wer<strong>de</strong>n auch<br />
Interfaces über Class-Objekte abgelegt. Für e<strong>in</strong> bestimmtes Objekt kann man auf<br />
mehreren Wegen das zugehörige Class-Objekt <strong>in</strong> Erfahrung br<strong>in</strong>gen. Für e<strong>in</strong><br />
bestimmtes Objekt kann man auf mehreren Wegen das zugehörige Class-Objekt <strong>in</strong><br />
Erfahrung br<strong>in</strong>gen:<br />
- Ist e<strong>in</strong> Exemplar <strong>de</strong>r Klasse verfügbar, dann ruft man die Metho<strong>de</strong> getClass() von<br />
java.lang.Object auf. Man erhält die zugehörige Klasse.<br />
- Ist die Klasse bekannt, besteht aber zusätzlich Interesse an <strong>de</strong>n Vorfahren, dann kann man das mit<br />
getSuperClass() herausf<strong>in</strong><strong>de</strong>n<br />
- Ist die Klasse nicht zur Compilezeit aber zur Laufzeit bekannt, dann hilft die Klassenmetho<strong>de</strong><br />
forName() weiter.<br />
E<strong>in</strong> Klassenobjekt kann e<strong>in</strong>e Schnittstelle, e<strong>in</strong>e Klasse, e<strong>in</strong>en primitiven Datentyp<br />
o<strong>de</strong>r auch e<strong>in</strong> Array beschreiben.<br />
Class<br />
public static Class forName(Str<strong>in</strong>g className) throws ClassNotFoundException<br />
// liefert das Klassen-Objekt mit <strong>de</strong>m vollqualifizierten Namen <strong>de</strong>r Klasse o<strong>de</strong>r <strong>de</strong>r Schnittstelle<br />
// className. Das Metaobjekt wird, falls es nicht von <strong>de</strong>r VM e<strong>in</strong>gebun<strong>de</strong>n ist, gesucht und<br />
// gela<strong>de</strong>n. Der Rückgabewert ist nicht null, falls es nicht gefun<strong>de</strong>n wer<strong>de</strong>n konnte, son<strong>de</strong>rn e<strong>in</strong>e<br />
// ClassNotFoundException.<br />
public Str<strong>in</strong>g getName()<br />
// liefert <strong>de</strong>n voll qualifizierten Namen <strong>de</strong>r Klasse, <strong>de</strong>r Schittstelle, <strong>de</strong>s Arrays o<strong>de</strong>r <strong>de</strong>s<br />
// primitiven Datentyps <strong>de</strong>s Class-Objekts<br />
public Class getSuperclass()<br />
// liefert die Superklasse <strong>de</strong>s Klassen-Objekts.<br />
public boolean isInterface()<br />
// liefert true, falls das Class-Objekt e<strong>in</strong> Interface beschreibt<br />
public boolean isArray()<br />
// liefert true, falls das Class-Objekt e<strong>in</strong>en Array beschreibt<br />
public boolean isPrimitive()<br />
// testet, ob das Interface e<strong>in</strong>en primitiven Datentyp beschreibt<br />
public <strong>in</strong>t getModifiers()<br />
// liefert die Modifizierer für e<strong>in</strong>e Klasse o<strong>de</strong>r e<strong>in</strong> Interface<br />
public Field[] getFields() throws SecurityException<br />
// liefert e<strong>in</strong> Feld mit Field-Objekten 107 .<br />
public Method[] getMethods() throws SecurityException<br />
// gibt e<strong>in</strong> Array von Method-Objekten 108 zurück, die alle öffentlichen Metho<strong>de</strong>n <strong>de</strong>r Klasse/<br />
// Schnittstelle beschreiben<br />
...<br />
Abb.: Die Klasse Class<br />
107 Objekten <strong>de</strong>r Klasse java.lang.reflect.Field<br />
108 Objekte <strong>de</strong>r Klasse java.lang.reflect.Method<br />
91
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Class besitzt Metho<strong>de</strong>n, die hauptsächlich zur Beschreibung <strong>de</strong>r Schnittstellen e<strong>in</strong>er<br />
Klasse und zur E<strong>in</strong>ordnung <strong>in</strong> die Klassenhierarchie dienen. Diese abstrakte und<br />
dynamische Dokumentation von Klassen wird als Reflection bezeichnet 109 .<br />
Das folgen<strong>de</strong> Programmstück 110 testet Objekte systematisch durch:<br />
import java.util.*;<br />
class CheckClassTyp<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Class observer = Observer.class;<br />
Class observable = Observable.class;<br />
Class array = (new <strong>in</strong>t[2][3][4]).getClass();<br />
Class primitive = Integer.TYPE;<br />
checkClassType(observer);<br />
checkClassType(observable);<br />
checkClassType(array);<br />
checkClassType(primitive);<br />
}<br />
static void checkClassType(Class c)<br />
{<br />
Str<strong>in</strong>g name = c.getName();<br />
if (c.isArray())<br />
System.out.pr<strong>in</strong>tln(name + " ist e<strong>in</strong> Array.");<br />
else if (c.isPrimitive())<br />
System.out.pr<strong>in</strong>tln(name + " ist e<strong>in</strong> primitiver Datentyp.");<br />
else if (c.isInterface())<br />
System.out.pr<strong>in</strong>tln(name + " ist e<strong>in</strong> Schnittstelle.");<br />
else<br />
System.out.pr<strong>in</strong>tln(name + " ist e<strong>in</strong>e Klasse.");<br />
}<br />
}<br />
Liegt <strong>de</strong>r Name <strong>de</strong>r Klasse als Class-Objekt vor, kann man zur Laufzeit <strong>de</strong>n voll<br />
qualifizierten Namen über die Metho<strong>de</strong> getName() ausgeben.<br />
import java.util.Date;<br />
class BspName<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Date d = new Date();<br />
Class c = d.getClass();<br />
Str<strong>in</strong>g s = c.getName();<br />
System.out.pr<strong>in</strong>tln(s);<br />
System.out.pr<strong>in</strong>tln((new <strong>in</strong>t[2][3][4]).getClass().getName());<br />
}<br />
}<br />
Arrays wer<strong>de</strong>n über getName() mit führen<strong>de</strong>n „[“ kodiert. Je<strong>de</strong> Klammer beschreibt<br />
die Tiefe <strong>de</strong>s Arrays. Nach <strong>de</strong>r Klammer folgt <strong>in</strong> kodierter Form, welchen Typ das<br />
Array speichert. So liefert System.out.pr<strong>in</strong>tln((new <strong>in</strong>t [2] [3] [4] ).<br />
getClass().getName());<strong>de</strong>n Str<strong>in</strong>g „[[[I“. Nimmt das Array Objekte auf, wird dies<br />
mit e<strong>in</strong>em „LKlassenname;“ kodiert. So ergibt (new<br />
Object[3]).getClass().getName() <strong>de</strong>n Str<strong>in</strong>g „[Ljava.lang.Object;“.<br />
109 Die Klasse java.lang.Class ist Basis für Metho<strong>de</strong>n, die Objekte vom Typ Constructor, Method, Field usw.<br />
zurückliefern. Die zugehörigen Klassen s<strong>in</strong>d im Package java.lang.reflect <strong>de</strong>f<strong>in</strong>iert.<br />
110 vgl. pr14220<br />
92
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.3 Die Klasse System<br />
Die Klasse System besteht nur aus Klassenvariablen und –metho<strong>de</strong>n und kann nicht<br />
<strong>in</strong>stanziiert wer<strong>de</strong>n. Sie stellt die Verb<strong>in</strong>dung zum Betriebssystem her und erlaubt<br />
bspw. <strong>de</strong>n Zugriff auf die Standar<strong>de</strong><strong>in</strong>- / Standardausgabe.<br />
System<br />
public static f<strong>in</strong>al InputStream <strong>in</strong><br />
public static f<strong>in</strong>al Pr<strong>in</strong>tStream out<br />
public static f<strong>in</strong>al Pr<strong>in</strong>tStream err<br />
public static void setIn(Inputstream <strong>in</strong>)<br />
public static void setOut(Pr<strong>in</strong>tStream out)<br />
public static void setErr(Pr<strong>in</strong>tStream err)<br />
public static Securitymanager getSecurityManager()<br />
public static void setSecurityManager(SecurityManager s)<br />
public static long currentTimeMillis()<br />
public static Properties getProperties()<br />
public static void setProperties(Properties props)<br />
public static Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key)<br />
public static void exit(<strong>in</strong>t status)<br />
public static void gc()<br />
public static void load(Str<strong>in</strong>g filename)<br />
Abb.: Die Klasse System<br />
System-Properties<br />
Properties s<strong>in</strong>d Listen von Eigenschaften, die Programmen vom <strong>Java</strong>-Laufzeitsystem<br />
zur Verfügung gestellt wer<strong>de</strong>n. Je<strong>de</strong> Eigenschaft besitzt e<strong>in</strong>en Name, unter <strong>de</strong>m auf<br />
sie zugegriffen wer<strong>de</strong>n kann.<br />
Property<br />
java.version<br />
java.vendor<br />
java.vendor.url<br />
java.home<br />
java.class.version<br />
java.class.path<br />
os.name<br />
os.arch<br />
os.version<br />
file.seperator<br />
path.seperator<br />
l<strong>in</strong>e.seperator<br />
user.name<br />
user.home<br />
user.dir<br />
Be<strong>de</strong>utung<br />
<strong>Java</strong>-Versionsnummer<br />
Herstellerspez. Zeichenkette<br />
URL (Internet-L<strong>in</strong>k)<br />
Installationsverzeichnis<br />
Versionsnummer <strong>de</strong>r <strong>Java</strong>-Klassenbibliothek<br />
Aktueller Klassenpfad<br />
Name <strong>de</strong>s Betriebssystems<br />
Betriebssystem-Architektur<br />
Versionsnummer <strong>de</strong>s Betriebssystems<br />
Trennzeichen für die Bestandteile <strong>de</strong>s Pfadnamens<br />
Trennzeichen für die Laufwerksangabe e<strong>in</strong>es Pfadnamens<br />
Zeichenkette für Zeilenumschaltung<br />
Name <strong>de</strong>s angemel<strong>de</strong>ten Benutzers<br />
Home-Verzeichnis<br />
Aktuelles Arbeitsverzeichnis<br />
Für <strong>de</strong>n Zugriff auf diese Eigenschaften steht die Klasse Properties aus <strong>de</strong>m<br />
Paket java.util zur Verfügung. Sie erzeugt Property-Listen. Die Klasse<br />
Properties ist e<strong>in</strong>e Ableitung <strong>de</strong>r Klasse HashTable und stellt darüber e<strong>in</strong>e<br />
Tabelle mit Schlüssel/Wertepaaren zur Verfügung.<br />
93
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Für <strong>de</strong>n Zugriff auf e<strong>in</strong>zelne Properties reicht meistens die Klassenmetho<strong>de</strong> <strong>de</strong>r<br />
Klasse System aus:<br />
public static Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key)<br />
liefert die Eigenschaft zu <strong>de</strong>m key <strong>in</strong> Form e<strong>in</strong>er Zeichenkette. Falls ke<strong>in</strong>e Eigenschaft unter diesem<br />
Namen (key) gefun<strong>de</strong>n wird, wird „null“ zurückgegeben.<br />
Die Metho<strong>de</strong><br />
public static Properties getProperties();<br />
liefert das komplette Properties-Objekt mit <strong>de</strong>n System-Properties.<br />
Bsp. 111 : Ausgabe e<strong>in</strong>er Liste aller System-Properties auf <strong>de</strong>m 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 <strong>de</strong>s System<br />
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>. Dabei dient err zur Ausgabe von<br />
Fehlermeldungen, <strong>in</strong> ist e<strong>in</strong> Standar<strong>de</strong><strong>in</strong>gabekanal, <strong>de</strong>r zur E<strong>in</strong>gabe von <strong>de</strong>r<br />
Tastatur verwen<strong>de</strong>t wird.<br />
Mit Hilfe von<br />
public static void setIn(InputStream <strong>in</strong>);<br />
public static void setOut(Pr<strong>in</strong>tStream out);<br />
public static void setErr(Pr<strong>in</strong>tStream err);<br />
kann die Standar<strong>de</strong><strong>in</strong>- und Standardausgabe aus <strong>de</strong>m Programm heraus umgeleitet<br />
wer<strong>de</strong>n.<br />
public static void exit(<strong>in</strong>t status)<br />
Mit System.exit(status) wird das laufen<strong>de</strong> Programm been<strong>de</strong>t. „status“ dient<br />
als Fehleranzeige und wird als Exitco<strong>de</strong> an <strong>de</strong>n Aufrufer <strong>de</strong>s Programms<br />
zurückgegeben. Gemäß Konvention zeigt e<strong>in</strong> Wert größer o<strong>de</strong>r gleich 1 e<strong>in</strong>en Fehler<br />
während <strong>de</strong>r Programmausführung an, 0 signalisiert e<strong>in</strong> fehlerfreies Programmen<strong>de</strong>.<br />
111 pr14231<br />
94
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public static void gc()<br />
führt e<strong>in</strong>en expliziten Aufruf <strong>de</strong>s 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 Metho<strong>de</strong> nicht erfor<strong>de</strong>rlich, <strong>de</strong>nn <strong>de</strong>r Garbage Collector läuft als<br />
niedrig priorisierter Thread im H<strong>in</strong>tergrund.<br />
public static long currentTimeMillis()<br />
liefert die Anzahl <strong>de</strong>r Millisekun<strong>de</strong>n, die zum Zeitpunkt <strong>de</strong>s Aufrufs seit Mitternacht<br />
<strong>de</strong>s 1.1.1970 vergangen s<strong>in</strong>d. Ob tatsächlich e<strong>in</strong>e Auflösung von e<strong>in</strong>er Millisekun<strong>de</strong><br />
erreicht wird, ist von <strong>de</strong>r <strong>Java</strong>-Implementierung abhängig. In PC-basierten Systemen<br />
orientiert sie sich meistens an <strong>de</strong>r Auflösung <strong>de</strong>s „System-Timer“.<br />
1.4.2.4 Multithread<strong>in</strong>g<br />
1.4.2.4.1. Die Klasse Thread<br />
Threads wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> durch die Klasse Thread und das Interface Runnable<br />
implementiert. In bei<strong>de</strong>n Fällen wird <strong>de</strong>r Thread-Körper (, also <strong>de</strong>r parallel<br />
auszuführen<strong>de</strong> Co<strong>de</strong>) <strong>in</strong> Form <strong>de</strong>r zu überlagern<strong>de</strong>n Metho<strong>de</strong> run bereitgestellt. Die<br />
Kommunikation kann durch Zugriff auf die Instanz- o<strong>de</strong>r Klassenvariablen o<strong>de</strong>r durch<br />
Aufruf beliebiger Metho<strong>de</strong>n, 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 <strong>de</strong>s Pakets java.lang und steht damit allen<br />
Anwendungen zur Verfügung. Über die Klasse Thread hat <strong>Java</strong> das<br />
(Betriebssystem-) Konzept <strong>de</strong>r Nebenläufigkeit implementiert. Mit Nebenläufigkeit<br />
bezeichnet man die Fähigkeit e<strong>in</strong>es Systems zwei o<strong>de</strong>r mehr Vorgänge gleichzeitig<br />
o<strong>de</strong>r 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 an<strong>de</strong>ren Thread laufen kann.<br />
95
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
Runnable<br />
public abstract void run()<br />
Thread<br />
public static f<strong>in</strong>al <strong>in</strong>t MIN_PRIORITY<br />
public static f<strong>in</strong>al <strong>in</strong>t NORM_PRIORITY<br />
public static f<strong>in</strong>al <strong>in</strong>t MAX_PRIORITY<br />
><br />
public Thread()<br />
public Thread(Runnable target)<br />
><br />
public static Thread currentThread()<br />
public static void yield()<br />
public static void sleep(long millis) throws InterruptedException<br />
public void start()<br />
public void run()<br />
public f<strong>in</strong>al void stop()<br />
//<strong>de</strong>precated<br />
public f<strong>in</strong>al void stop(Throwable obj)<br />
//<strong>de</strong>precated<br />
public void <strong>in</strong>terrupt()<br />
public static boolean <strong>in</strong>terrupted()<br />
public boolean isInterrupted()<br />
public void <strong>de</strong>stroy()<br />
public f<strong>in</strong>al boolean isAlive()<br />
public f<strong>in</strong>al void suspend()<br />
//<strong>de</strong>precated<br />
public f<strong>in</strong>al void resume()<br />
//<strong>de</strong>precated<br />
public f<strong>in</strong>al void setPriority(<strong>in</strong>t newPriority)<br />
public f<strong>in</strong>al <strong>in</strong>t getPriority()<br />
...<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
Abb.: Thread-Klassen<br />
Metho<strong>de</strong>n <strong>de</strong>r Klasse Thread<br />
public void run()<br />
Zum Erzeugen e<strong>in</strong>es Thread muß e<strong>in</strong>e eigene Klasse aus <strong>de</strong>r Klasse Thread<br />
abgeleitet, und die Metho<strong>de</strong> run überlagert wer<strong>de</strong>n. Mit Hilfe <strong>de</strong>s Aufrufs <strong>de</strong>r<br />
Metho<strong>de</strong> start wird <strong>de</strong>r Thread gestartet, die weitere Ausführung wird an run()<br />
übertragen. „start()“ wird nach <strong>de</strong>m Start been<strong>de</strong>t, <strong>de</strong>r Aufrufer kann parallel zum<br />
neu erzeugten Thread fortfahren.<br />
Bsp.: E<strong>in</strong>facher Thread, <strong>de</strong>r <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 />
96
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r Metho<strong>de</strong> run()<br />
}<br />
}<br />
Der (quasi) parallel auszuführen<strong>de</strong> Co<strong>de</strong> wird durch die überlagerte Metho<strong>de</strong> run<br />
bereitgestellt. Die Kommunikation kann durch Zugriff auf Instanz- und<br />
Klassenvariablen o<strong>de</strong>r durch Aufruf beliebiger Metho<strong>de</strong>n 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 been<strong>de</strong>t, wenn <strong>de</strong>r letzte Thread been<strong>de</strong>t<br />
wur<strong>de</strong>(, <strong>de</strong>r 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 />
e<strong>in</strong>en e<strong>in</strong>zigen Vor<strong>de</strong>rgrund-Thread besitzt, (nämlich <strong>de</strong>n, <strong>in</strong> <strong>de</strong>m ma<strong>in</strong>() läuft 112 ,)<br />
wird es been<strong>de</strong>t, wenn ma<strong>in</strong>() been<strong>de</strong>t wird. Das Beispielprogramm erzeugt e<strong>in</strong>en<br />
zusätzlichen Vor<strong>de</strong>rgrund-Thread und kann erst dann been<strong>de</strong>t wer<strong>de</strong>n, wenn dieser<br />
Thread been<strong>de</strong>t wur<strong>de</strong>.<br />
public static void sleep(long millis) throws InterruptedException<br />
sorgt dafür, daß <strong>de</strong>r aktuelle Prozeß für die (<strong>in</strong> Millisekun<strong>de</strong>n) angegebene Zeit<br />
unterbrochen wird.<br />
public static void sleep(long millis, <strong>in</strong>t nanos) throws<br />
InterruptedException<br />
Die erzielbare Genauigkeit <strong>de</strong>r Unterbrechungs-Wartezeit wird durch Hardware-<br />
Restriktionen <strong>de</strong>r Masch<strong>in</strong>e begrenzt<br />
public f<strong>in</strong>al boolean isAlive()<br />
gibt true zurück, wenn <strong>de</strong>r aktuelle Thread gestartet, aber noch nicht been<strong>de</strong>t<br />
wur<strong>de</strong>.<br />
Been<strong>de</strong>t wird e<strong>in</strong> Thread, wenn das En<strong>de</strong> <strong>de</strong>r run-Metho<strong>de</strong> erreicht ist, o<strong>de</strong>r wenn<br />
die Metho<strong>de</strong> stop aufgerufen wur<strong>de</strong>.<br />
Bsp.: Been<strong>de</strong>n <strong>de</strong>s Thread nach 2 Sekun<strong>de</strong>n 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 />
112 Beim Starten e<strong>in</strong>es <strong>Java</strong>-Programms wird automatisch e<strong>in</strong> Thread für die Ausführung <strong>de</strong>s Hauptprogramms<br />
angelegt.<br />
97
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
Me<strong>in</strong>Thread1 t = new Me<strong>in</strong>Thread1();<br />
// Start vom erzeugten Thread<br />
t.start();<br />
// Impliziter Aufruf <strong>de</strong>r Metho<strong>de</strong> run()<br />
try {<br />
Thread.sleep(2000);<br />
}<br />
catch(InterruptedException e)<br />
{ }<br />
t.stop();<br />
Mit <strong>de</strong>m JDK 1.2 wur<strong>de</strong> stop() als <strong>de</strong>precated markiert, da es nicht vorhersehbar<br />
und auch nicht <strong>de</strong>f<strong>in</strong>iert ist, an welcher Stelle e<strong>in</strong> Thread beim Aufruf von stop()<br />
abgebrochen wird.<br />
Ersatz für stop(): Man kann e<strong>in</strong> Flag für Threadabbruch setzen und dieses zyklisch<br />
<strong>in</strong> <strong>de</strong>r Metho<strong>de</strong> run <strong>de</strong>s Thread abfragen. Falls dieses gesetzt ist, können alle<br />
Ressourcen freigegeben und <strong>de</strong>r Thread durch reguläres Been<strong>de</strong>n von run() (bpw.<br />
mit Hilfe von return) been<strong>de</strong>t wer<strong>de</strong>n. Das Flag darf allerd<strong>in</strong>gs nicht zu oft aber<br />
auch nicht zu selten abgefragt wer<strong>de</strong>n.<br />
Bsp. 113 :<br />
class Me<strong>in</strong>Thread extends Thread<br />
{<br />
boolean ok = true;<br />
public void run()<br />
{<br />
<strong>in</strong>t i = 0;<br />
while (ok)<br />
System.out.pr<strong>in</strong>tln(i++);<br />
}<br />
}<br />
public class Me<strong>in</strong>ThreadTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Me<strong>in</strong>Thread t = new Me<strong>in</strong>Thread();<br />
t.start();<br />
try {<br />
Thread.sleep(2000);<br />
}<br />
catch (InterruptedException e)<br />
{ }<br />
t.ok = false;<br />
}<br />
}<br />
Es gibt <strong>in</strong> <strong>de</strong>r Klasse Thread e<strong>in</strong>ige Metho<strong>de</strong>n, die e<strong>in</strong>en solchen Mechanismus<br />
standardmäßig unterstützen.<br />
public void <strong>in</strong>terrupt()<br />
setzt e<strong>in</strong> Flag, das e<strong>in</strong>e Unterbrechungsanfor<strong>de</strong>rung signalisiert.<br />
public boolean isInterrupted()<br />
stellt fest, ob das Abbruchflag gesetzt wur<strong>de</strong> und <strong>de</strong>r Thread been<strong>de</strong>t wur<strong>de</strong>.<br />
public static boolean <strong>in</strong>terrupted()<br />
113 pr14240<br />
98
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
stellt <strong>de</strong>n Status <strong>de</strong>s Abbruchflag beim aktuellen Thread fest und setzt zusätzlich das<br />
Abbruchflag auf se<strong>in</strong>en Initialisierungswert zurück.<br />
Bsp. 114 :<br />
public class PR14240 extends Thread<br />
{<br />
<strong>in</strong>t zaehler = 0;<br />
public void run()<br />
{<br />
while (true)<br />
{<br />
if (isInterrupted())<br />
{<br />
break;<br />
}<br />
pr<strong>in</strong>tL<strong>in</strong>e(++zaehler);<br />
}<br />
}<br />
private void pr<strong>in</strong>tL<strong>in</strong>e(<strong>in</strong>t cnt)<br />
{<br />
//Zeile ausgeben<br />
System.out.pr<strong>in</strong>t(zaehler + ": ");<br />
for (<strong>in</strong>t i = 0; i < 30; ++i)<br />
{<br />
System.out.pr<strong>in</strong>t(i == zaehler % 30 ? "* " : ". ");<br />
}<br />
System.out.pr<strong>in</strong>tln();<br />
// 100 ms. warten<br />
try {<br />
Thread.sleep(100);<br />
}<br />
catch (InterruptedException e)<br />
{<br />
<strong>in</strong>terrupt();<br />
}<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
PR14240 th = new PR14240();<br />
{<br />
//Thread starten<br />
th.start();<br />
//2 Sekun<strong>de</strong>n warten<br />
try {<br />
Thread.sleep(2000);<br />
}<br />
catch (InterruptedException e) { }<br />
//Thread unterbrechen<br />
th.<strong>in</strong>terrupt();<br />
}<br />
}<br />
}<br />
Das Programm gibt zunächst über e<strong>in</strong>en separaten Thread zunächst Textzeilen aus.<br />
Wahrsche<strong>in</strong>lich erfolgt <strong>de</strong>r Aufruf von <strong>in</strong>terrupt() während <strong>de</strong>s Aufrufs von<br />
sleep(), da die Pause nach <strong>de</strong>r Bildschirmausgabe vermulich länger dauert als die<br />
Bildschirmausgabe. Ist dies <strong>de</strong>r Fall wird sleep() mit e<strong>in</strong>er<br />
InterruptedException abgebrochen. Das Abbruchflag wird zurückgesetzt und<br />
<strong>de</strong>r Aufruf von <strong>in</strong>terrupt() damit wirkungslos. Da aber <strong>in</strong> <strong>de</strong>r catch-Klausel<br />
114 vgl. pr14240<br />
99
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
<strong>in</strong>terrupt() erneut aufgerufen wird, wird das Flag wie<strong>de</strong>r gesetzt und run() die<br />
Abbruchauffor<strong>de</strong>rung signalisiert.<br />
public f<strong>in</strong>al void jo<strong>in</strong>() throws InterruptedException<br />
Mit Hilfe dieser Metho<strong>de</strong> kann gezielt auf die Beendigung e<strong>in</strong>es Thread gewartet<br />
wer<strong>de</strong>n. So etwas ist s<strong>in</strong>nvoll, wenn zeitaufwendige Operationen vor <strong>de</strong>m Aufruf<br />
e<strong>in</strong>er Folgeoperation noch been<strong>de</strong>t wer<strong>de</strong>n müssen. Der zeitaufwendigsten<br />
Operation ist e<strong>in</strong> eigener Thread zugeordnet.<br />
public static void yield()<br />
“Freiwilliges” Angebot <strong>de</strong>s laufen<strong>de</strong>n Thread, <strong>de</strong>n Prozessor abzugeben.<br />
Unterbrechen e<strong>in</strong>es Thread: Mit Hilfe <strong>de</strong>r Metho<strong>de</strong>n 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 <strong>de</strong>r Thread<br />
(genauer: die Metho<strong>de</strong> run) an <strong>de</strong>r Stelle fortgesetzt, an <strong>de</strong>r die Unterbrechung<br />
erfolgte. Sowohl suspend() als auch resume() s<strong>in</strong>d aber <strong>de</strong>precated und sollten<br />
nicht mehr verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Verwaltung von Threads<br />
Threads besitzen adm<strong>in</strong>istrative Eigenschaften, die sich <strong>in</strong> zwei Gruppen e<strong>in</strong>teilen<br />
lassen:<br />
- Priorität und Name<br />
- Thread-Gruppen<br />
Priorität, Name. Je<strong>de</strong>r Thread hat e<strong>in</strong>en e<strong>in</strong><strong>de</strong>utigen Namen. Ohne explizite Vorgabe<br />
erfolgt die Vergabe <strong>de</strong>s Namens automatisch <strong>in</strong> <strong>de</strong>r Form “Thread-“+n , wobei n<br />
e<strong>in</strong> <strong>in</strong>t ist. Mit public void setName(Str<strong>in</strong>g name) kann e<strong>in</strong>em Thread e<strong>in</strong><br />
Name zugewiesen wer<strong>de</strong>n. Mit public Str<strong>in</strong>g getName() kann <strong>de</strong>r Name e<strong>in</strong>es<br />
Thread abgefragt wer<strong>de</strong>n. public static Thread currentThread() liefert<br />
<strong>de</strong>n Zugriff auf <strong>de</strong>n aktuellen Thread, <strong>de</strong>r die Metho<strong>de</strong> gera<strong>de</strong> ausführt, z.B.:<br />
public class ThreadTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
System.out.pr<strong>in</strong>tln("THREAD: " + Thread.currentThread() );<br />
}<br />
}<br />
/* Ausgabe am Bildschirm: THREAD: Thread[ma<strong>in</strong>,5,ma<strong>in</strong>]<br />
Die Ausgabe umfasst : Name, Priorität und Gruppe<br />
*/<br />
Neben <strong>de</strong>m Namen besitzt e<strong>in</strong> Thread noch e<strong>in</strong>e Priorität. Die Priorität steuert <strong>de</strong>r<br />
Scheduler <strong>in</strong> <strong>de</strong>r Weise, daß bei Vorhan<strong>de</strong>nse<strong>in</strong> mehrerer Threads diejenigen mit<br />
höherer Priorität vor <strong>de</strong>nen mit niedrigerer Priorität ausgeführt wer<strong>de</strong>n. Beim Anlegen<br />
e<strong>in</strong>es neuen Thread bekommt dieser die Priorität <strong>de</strong>s aktuellen Thread. Mit public<br />
void setPriority(<strong>in</strong>t neuePrioritaet) kann die neue Priorität gesetzt und<br />
mit public <strong>in</strong>t getPriority() abgefragt wer<strong>de</strong>n. Als Parameter kann an<br />
setPriority() e<strong>in</strong> Wert übergeben wer<strong>de</strong>n, <strong>de</strong>r zwischen <strong>de</strong>n Konstanten<br />
Thread.MIN_PRIORITY und Thread.MAX_PRIORITY liegt. <strong>Java</strong> bietet 10<br />
100
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Prioritätsstufen zwischen 1 (Thread.MIN_PRIORITY) und 10<br />
(Thread.MAX_PRIORITY) an. Der Normalwert wird durch die Konstante<br />
Thread.NORM_PRIORITY festgelegt 115 .<br />
Thread-Gruppen. Sie verwalten Informationen für e<strong>in</strong>e ganze Gruppe und bieten<br />
Metho<strong>de</strong>n an, die auf alle Threads e<strong>in</strong>er Gruppe angewen<strong>de</strong>t wer<strong>de</strong>n können. In <strong>de</strong>r<br />
Klassenbibliothek gibt es dafür e<strong>in</strong>e eigen<strong>de</strong> ThreadGroup.<br />
ThreadGroup<br />
><br />
public ThreadGroup(Str<strong>in</strong>g name)<br />
public ThreadGroup(ThreadGroup parent, Str<strong>in</strong>g name)<br />
><br />
public f<strong>in</strong>al Str<strong>in</strong>g getName();<br />
public f<strong>in</strong>al ThreadGroup getParent()<br />
public <strong>in</strong>t activeCount()<br />
public <strong>in</strong>t activeGroupCount()<br />
public <strong>in</strong>t enumerate(Thread[] list)<br />
public enumerate(ThreadGroup[] list)<br />
public void <strong>in</strong>terrupt();<br />
public boolean isDaemon()<br />
public void setDaemon(boolean daemon)<br />
public f<strong>in</strong>al <strong>in</strong>t getMaxPriority()<br />
public f<strong>in</strong>al void setMaxPriority()<br />
Abb.: Die Klasse TheadGroup<br />
Die Klasse ThreadGroup stellt zur Verwaltung mehrerer Threads Metho<strong>de</strong>n bereit.<br />
Sie besitzt e<strong>in</strong>e Default-Priorität, kann alle Threads anhalten und kann sie als<br />
Daemons ablaufen lassen. Threads wer<strong>de</strong>n durch Konstruktoren e<strong>in</strong>er Gruppe<br />
zugeordnet. Thread-Gruppen können auch <strong>in</strong>e<strong>in</strong>an<strong>de</strong>r verschachtelt wer<strong>de</strong>n.<br />
Daemon-Threads. Es gibt Aufgaben, die zur Laufzeit <strong>de</strong>s Programms zu erledigen<br />
s<strong>in</strong>d, aber nie term<strong>in</strong>ieren, z.B. <strong>de</strong>r Garbage Collector. Da die virtuelle Masch<strong>in</strong>e erst<br />
been<strong>de</strong>t wird, wenn ke<strong>in</strong> <strong>Java</strong>-Thread mehr aktiv ist, müssen am En<strong>de</strong> <strong>de</strong>r<br />
Anwendung alle Threads angehalten wer<strong>de</strong>n. Es wäre aber lästig (und manchmal<br />
schwierig), die H<strong>in</strong>tergrund-Threads explizit zu been<strong>de</strong>n. Hierfür existiert das<br />
Konzept <strong>de</strong>r Daemon-Threads. Da sich die virtuelle Masch<strong>in</strong>e been<strong>de</strong>t, wenn nur<br />
noch Daemon-Threads laufen, brauch die Beendigung dieser Threads nicht weiter<br />
berücksichtigt wer<strong>de</strong>n. E<strong>in</strong> Thread ist e<strong>in</strong> Daemon, wenn ihm das durch<br />
public f<strong>in</strong>al void setDaemon(boolean on)<br />
mitgeteilt wur<strong>de</strong>. Die Metho<strong>de</strong><br />
public f<strong>in</strong>al boolean isDaemon()<br />
gibt Auskunft über die Art e<strong>in</strong>es Thread.<br />
115 im aktuellen JDK 1, 5, 10<br />
101
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.4.2 Das Interface Runnable<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 <strong>de</strong>shalb auch über Implementierung <strong>de</strong>s Interface<br />
Runnable erzeugt wer<strong>de</strong>n. Runnable enthält nur e<strong>in</strong>e e<strong>in</strong>zige Deklaration nämlich<br />
die <strong>de</strong>r Metho<strong>de</strong> run:<br />
public <strong>in</strong>terface Runnable<br />
{<br />
public abstract void run();<br />
}<br />
Implementierung von Runnable: Je<strong>de</strong> Klasse, <strong>de</strong>ren Instanzen als Thread laufen,<br />
muß das Interface Runnable implementieren 116 . E<strong>in</strong>e nicht von Thread abgeleitete<br />
Instanz kann nach folgen<strong>de</strong>n Implementierungsschritten als Thread laufen:<br />
- Erzeugen e<strong>in</strong>es neuen Thread-Objekts<br />
- Übergabe <strong>de</strong>s Objekts, das parallel ausgeführt wer<strong>de</strong>n soll, an <strong>de</strong>n Konstruktor<br />
- Aufruf <strong>de</strong>r Metho<strong>de</strong> start() <strong>de</strong>s Thread-Objekts<br />
Über start() startet das Thread-Objekt die run-Meto<strong>de</strong> <strong>de</strong>s übergebenen Objekts<br />
(das sie durch die Übergabe an <strong>de</strong>n Konstruktor kennt). Da dieses Objekt das<br />
Interface Runnable implementiert, ist garantiert, daß e<strong>in</strong>e geeignete Metho<strong>de</strong> run<br />
zur Verfügung steht.<br />
Bsp. 117 : ThreadDemo<br />
Thread<br />
MAX_PRIORITY<br />
….<br />
Runnable<br />
><br />
sleep()<br />
run()<br />
start()<br />
jo<strong>in</strong>()<br />
….<br />
ErsterThread<br />
ZweiterThread<br />
run() runs run()<br />
class ErsterThread extends Thread<br />
{<br />
public void run()<br />
{<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
try {<br />
Thread.sleep( Math.round(1000 * Math.random()) );<br />
System.out.pr<strong>in</strong>tln(this + " " + i);<br />
}<br />
116 sogar die Klasse Thread selbst<br />
117 vgl. pr14240<br />
102
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
catch (InterruptedException e)<br />
{ System.err.pr<strong>in</strong>tln(e); }<br />
}<br />
}<br />
class ZweiterThread implements Runnable<br />
{<br />
public void run()<br />
{<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
try {<br />
Thread.sleep( Math.round(1000 * Math.random()) );<br />
System.out.pr<strong>in</strong>tln(Thread.currentThread().toStr<strong>in</strong>g() + " " + i);<br />
}<br />
catch (InterruptedException e)<br />
{ System.err.pr<strong>in</strong>tln(e); }<br />
}<br />
}<br />
public class ThreadDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
ErsterThread thread1 = new ErsterThread();<br />
thread1.start();<br />
Thread thread2 = new Thread(new ZweiterThread());<br />
thread2.start();<br />
try {<br />
thread1.jo<strong>in</strong>();<br />
thread2.jo<strong>in</strong>();<br />
}<br />
catch (InterruptedException e)<br />
{ System.err.pr<strong>in</strong>tln(e); }<br />
}<br />
}<br />
Abb.: Def<strong>in</strong>ition von Threads<br />
Die Klasse Thread implementiert Runnable. Dort ist die Metho<strong>de</strong> run() <strong>de</strong>klariert. Mit <strong>de</strong>r Metho<strong>de</strong><br />
start() wird e<strong>in</strong> Thread gestartet, <strong>in</strong> <strong>de</strong>m run() aufgerufen wird. „jo<strong>in</strong>()“ wartet auf die Beendigung<br />
<strong>de</strong>s Thread.<br />
ErsterThread ist Subklasse von Thread. „run()“ von Thread wird überschrieben.<br />
„sleep()“ legt e<strong>in</strong>en Thread für e<strong>in</strong>e bestimmte Zeit (<strong>in</strong> Millisekun<strong>de</strong>n) schlafen. Hier wird zufällig<br />
e<strong>in</strong>e Zeitspanne zwischen 0 und 1000 ms gewartet und dann <strong>de</strong>r Scheifenzählerwert ausgegeben.<br />
103
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
ma<strong>in</strong><br />
start thread2<br />
start thread1<br />
jo<strong>in</strong> thread2<br />
jo<strong>in</strong> thread1<br />
thread1<br />
thread2<br />
Zeit<br />
Abb.: Zusammenspiel von Threads <strong>in</strong> ThreadDemo<br />
ZweiterThread implementiert Runnable. Hier muß explizit e<strong>in</strong>e Instanz von Thread erzeugt<br />
wer<strong>de</strong>n.<br />
Die Instanz von ZweiterThread wird e<strong>in</strong>em Thread-Objekt übergeben, <strong>de</strong>r die run()-Metho<strong>de</strong><br />
betreibt.<br />
ErsterThread kann sich selber schlafen legen. ZweiterThread legt die benutzte Instanz von Thread<br />
schlafen.<br />
Bei Programmstart existiert immer automatisch e<strong>in</strong> ErsterThread, <strong>de</strong>ssen Ausführung <strong>in</strong> <strong>de</strong>r<br />
ma<strong>in</strong>()-Metho<strong>de</strong> beg<strong>in</strong>nt. Dieser ma<strong>in</strong>-Thread startet nun zwei weitere Threads und wartet (jo<strong>in</strong>())<br />
auf das En<strong>de</strong> dieser Threads.<br />
Bei je<strong>de</strong>m Ablauf ergibt sich nicht-<strong>de</strong>term<strong>in</strong>istisch e<strong>in</strong>e an<strong>de</strong>re Reihenfolge <strong>de</strong>r Ausgaben<br />
1.4.2.4.3. Prozesse und Threads <strong>in</strong> <strong>Java</strong><br />
E<strong>in</strong> <strong>Java</strong>-Programm besitzt <strong>in</strong> <strong>de</strong>r Regel e<strong>in</strong>e Klasse mit e<strong>in</strong>er statischen Metho<strong>de</strong><br />
ma<strong>in</strong>().<br />
Bei je<strong>de</strong>m Start e<strong>in</strong>es <strong>Java</strong>-Programms erzeugt das Betriebssystem e<strong>in</strong>en Prozeß<br />
und startet die virtuelle Masch<strong>in</strong>e (VM). Die VM erzeugt e<strong>in</strong>en Haupt-Thread (ma<strong>in</strong><br />
thread) auch Programmfa<strong>de</strong>n, Kontrollfluß o<strong>de</strong>r leichtgewichtiger Prozeß genannrt.<br />
Der Ma<strong>in</strong>-Thread führt daraufh<strong>in</strong> die Metho<strong>de</strong> ma<strong>in</strong>() aus.<br />
E<strong>in</strong>e Metho<strong>de</strong> im Quelltext besteht aus e<strong>in</strong>er Sequenz von Anweisungen. Beim<br />
Übersetzen <strong>de</strong>s Quelltextes, wird je<strong>de</strong> Anweisung <strong>in</strong> mehrere elementare<br />
Teilanweisungen (byte co<strong>de</strong>s) für die VM zerlegt. E<strong>in</strong> <strong>Java</strong>-Thread führt diese<br />
e<strong>in</strong>zelnen elementaren Anweisungen e<strong>in</strong>er Metho<strong>de</strong> (z.B. ma<strong>in</strong>()) und die<br />
Anweisungen <strong>de</strong>r dar<strong>in</strong> enthaltenen Metho<strong>de</strong>n squentiell aus.<br />
<strong>Java</strong>-Prozesse wer<strong>de</strong>n auf Betriebssystem-Prozesse abgebil<strong>de</strong>t, d.h.: Auch <strong>Java</strong>-<br />
Threads können auf Betriebssystem-Threads abgebil<strong>de</strong>t wer<strong>de</strong>n. Man spricht von<br />
e<strong>in</strong>er virtuellen Masch<strong>in</strong>e, die native Threads unterstützt.<br />
104
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Anwendung_1<br />
Betriebssystem<br />
Anwendung_2<br />
<strong>Java</strong>_VM_1<br />
<strong>Java</strong>_VM_2<br />
VM Prozess_1 lok. Variable<br />
Prozess_2 lok. Variable<br />
glob.<br />
Variable Prozess_3 lok. Variable<br />
Abb. Betriebssystem - VM<br />
Die Abbildung <strong>de</strong>r <strong>Java</strong>-Prozesse auf BS-Prozesse hängt von <strong>de</strong>r Implementierung<br />
<strong>de</strong>r VM ab. Es gibt Implementierungen<br />
- die das Schedul<strong>in</strong>g <strong>de</strong>r VM-Prozesse übernehmen<br />
- die das Schedul<strong>in</strong>g <strong>de</strong>m darunterliegen<strong>de</strong>n BS überlassen<br />
"schedul<strong>in</strong>g strategies". Threads benötigen für ihre Ausführung e<strong>in</strong>en Prozessor.<br />
Viele <strong>Java</strong>-Anwendungen unterstützen nur e<strong>in</strong>en Prozessor. Bei nur e<strong>in</strong>em<br />
Prozessor kann nur e<strong>in</strong> Thread aktiv se<strong>in</strong>. Der Thread wird <strong>de</strong>m Prozessor zugeteilt.<br />
Man spricht <strong>in</strong> diesem Zusammenhang von Schedul<strong>in</strong>g. Die Zuteilungsstrategie<br />
bee<strong>in</strong>flusst das Verhalten <strong>de</strong>s Systems bei mehreren Threads. Folgen<strong>de</strong> Zustän<strong>de</strong><br />
e<strong>in</strong>es Thread können unterschie<strong>de</strong>n wer<strong>de</strong>n:<br />
- Initialzustand<br />
Der Thread wur<strong>de</strong> erzeugt, führt aber die noch ke<strong>in</strong>e Metho<strong>de</strong> aus, d.h. start() wur<strong>de</strong> noch nicht<br />
aufgerufen.<br />
- Lauffähig<br />
E<strong>in</strong> Thread geht vom Initialzustand mit start() <strong>in</strong> <strong>de</strong>n Zustand "lauffähig" über.<br />
- Aktiv<br />
E<strong>in</strong> Thread wird aktiv, wenn er von <strong>de</strong>r VM aus <strong>de</strong>r Menge <strong>de</strong>r lauffähigen Threads ausgewählt wird.<br />
In diesem Zustand führt <strong>de</strong>r Thread tatsächlich Co<strong>de</strong> aus. Der Thread wird von <strong>de</strong>r VM dazu entwe<strong>de</strong>r<br />
<strong>in</strong> <strong>de</strong>n Zustand lauffähig zurückgesetzt o<strong>de</strong>r er kommt <strong>in</strong> <strong>de</strong>n Zustand "blockiert".<br />
- Blockiert<br />
E<strong>in</strong> Thread ist blockiert, wenn er auf <strong>de</strong>n exklusiven Zugriff auf e<strong>in</strong>es bei synchronized<br />
angegebenen Objekts o<strong>de</strong>r auf das Ergebnis mit wait() wartet.<br />
Ist <strong>de</strong>r Thread blockiert, dann geht er <strong>in</strong> <strong>de</strong>n Zustand "lauffähig" über, falls e<strong>in</strong> an<strong>de</strong>rer Thread mit<br />
e<strong>in</strong>em notify() o<strong>de</strong>r notifyAll() das Ergebnis mel<strong>de</strong>t und daraufh<strong>in</strong> die VM <strong>de</strong>s blockierten<br />
Threads auswählt.<br />
- Endzustand.<br />
Der Thread ist <strong>in</strong> se<strong>in</strong>em Endzustand, falls run() ausgeführt wur<strong>de</strong> o<strong>de</strong>r mit e<strong>in</strong>er Ausnahme<br />
been<strong>de</strong>t wur<strong>de</strong>.<br />
105
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Auswahl durch VM<br />
nach notify()<br />
start() lauffähig blockiert<br />
notify(), notifyAll()<br />
Initial run() En<strong>de</strong><br />
sleep() o<strong>de</strong>r<br />
Auswahl durch VM<br />
<strong>in</strong> synchronized()<br />
aktiv warten auf Zugriff<br />
En<strong>de</strong> von run() o<strong>de</strong>r unbehan<strong>de</strong>lte<br />
Ausnahme<br />
Abb.: Automatendarstellung <strong>de</strong>r Übergänge zwischen <strong>de</strong>n Zustän<strong>de</strong>n e<strong>in</strong>es Thread<br />
1.4.2.4.4 Synchronisation nebenläufiger Prozesse<br />
E<strong>in</strong>führen<strong>de</strong>s Beispiel. Mehrere Threads mit geme<strong>in</strong>samer Variablen.<br />
public class OhneSynchroTest extends Thread<br />
{<br />
static <strong>in</strong>t zaehler = 0;<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
Thread t1 = new OhneSynchroTest();<br />
Thread t2 = new OhneSynchroTest();<br />
t1.start();<br />
t2.start();<br />
}<br />
static void schreibe()<br />
{<br />
System.out.pr<strong>in</strong>t(zaehler + " ");<br />
zaehler++;<br />
if (zaehler > 25) System.exit(0);<br />
}<br />
public void run()<br />
{<br />
while (true) schreibe();<br />
}<br />
}<br />
Die bei<strong>de</strong>n Threads versuchen <strong>de</strong>n Zählerstand zu <strong>in</strong>krementieren. Ziel ist, dass bei<strong>de</strong> geme<strong>in</strong>sam<br />
zaehler von 0 auf 25 hochzählen.<br />
Auszüge aus e<strong>in</strong>er möglichen Ausgabe:<br />
Abb.: Mögliche Ausgabe vom nicht synchronisierten Programm OhneSynchroTest<br />
Die Ausgabe von OhneSynchroTest ist nicht plausibel.<br />
106
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Offensichtlich ist es notwendig, bei<strong>de</strong> Threads zu koord<strong>in</strong>ieren. Sie müssen so<br />
synchronisiert wer<strong>de</strong>n, dass nur e<strong>in</strong> Thread das Prüfen <strong>de</strong>r Bed<strong>in</strong>gung und das<br />
Inkrementieren atomar, d.h. vollständig ohne Unterbrechung ausführt.<br />
H<strong>in</strong>weis. Wie immer bei fehlen<strong>de</strong>r Synchronisation muß <strong>de</strong>r im Beispiel gezeigte<br />
Fehler nicht zw<strong>in</strong>gend auftreten und kann lange Zeit völlig unbemerkt bleiben. Je<br />
nach<strong>de</strong>m, wann die Threads aktiv s<strong>in</strong>d bzw. bei e<strong>in</strong>em Prozessor sich abwechseln,<br />
ergeben sich unterschiedliche Resultate 118 .<br />
Synchronisation paralleler Prozesse <strong>in</strong> <strong>Java</strong>. Mehrere Threads können nur über<br />
geme<strong>in</strong>same Variable kommunizieren. Folgen<strong>de</strong> Konflikte können dabei auftreten:<br />
- Gleichzeitiges Lesen und Schreiben<br />
E<strong>in</strong> Thread liest und e<strong>in</strong> an<strong>de</strong>rer än<strong>de</strong>rt gera<strong>de</strong> das Objekt, ist aber noch nicht fertig.<br />
- Gleichzeitiges Schreiben<br />
Mehrere Threads versuchen das Objekt gleichzeitig zu än<strong>de</strong>rn.<br />
Rufen mehrere Threads Metho<strong>de</strong>n gleichzeitig auf, dann kann ohne Synchronisation<br />
e<strong>in</strong> Zwischenzustand e<strong>in</strong>er Metho<strong>de</strong> <strong>de</strong>n Ablauf e<strong>in</strong>er an<strong>de</strong>ren Metho<strong>de</strong><br />
bee<strong>in</strong>flussen. Zur Vermeidung von Konflikten gibt es mehrere Möglichkeiten:<br />
- Schreiben nicht zulassen<br />
E<strong>in</strong>e Klasse wird so <strong>de</strong>f<strong>in</strong>iert, dass e<strong>in</strong>e Än<strong>de</strong>rung <strong>de</strong>r Attribute nach <strong>de</strong>m Erzeugen von Objekten<br />
nicht mehr möglich ist (immutable class). Bei <strong>Java</strong> können bspw. mehrere Threads problemlos<br />
auf e<strong>in</strong> gleiches Objekt <strong>de</strong>r Klasse java.lang.Str<strong>in</strong>g zugreifen, da e<strong>in</strong> Str<strong>in</strong>g nicht mehr<br />
geän<strong>de</strong>rt wer<strong>de</strong>n kann. Je<strong>de</strong> Metho<strong>de</strong> <strong>de</strong>r Klasse produziert bei e<strong>in</strong>er Än<strong>de</strong>rung <strong>de</strong>s Werts e<strong>in</strong><br />
neues Str<strong>in</strong>g Objekt. 119<br />
- Lesen und Schreiben synchronisieren<br />
Für e<strong>in</strong>en Bereich, <strong>in</strong> <strong>de</strong>n geme<strong>in</strong>same Variable geschrieben o<strong>de</strong>r gelesen wer<strong>de</strong>n, benötigt je<strong>de</strong>r<br />
Thread e<strong>in</strong>e Sperre bevor er diesen Bereich ausführt. Danach gibt er die Sperre wie<strong>de</strong>r frei. Mit<br />
diesem gegenseitigen Ausschluß (mutually exclusive lock) lassen sich Zugriffe auf Objekte so<br />
koord<strong>in</strong>ieren, dass Konflikte vermie<strong>de</strong>n wer<strong>de</strong>n.<br />
In <strong>Java</strong> müssen alle Bereiche, <strong>in</strong> <strong>de</strong>m geme<strong>in</strong>same Variable geschrieben o<strong>de</strong>r<br />
gelesen wer<strong>de</strong>n, explizit mit <strong>de</strong>m Schlüsselwort synchronized zur Vermeidung von<br />
Konflikten versehen wer<strong>de</strong>n.<br />
synchronized(O)<br />
{<br />
S<br />
}<br />
O ist e<strong>in</strong> beliebiger Ausdruck, <strong>de</strong>r e<strong>in</strong> <strong>Java</strong>-Objekt liefert, und S e<strong>in</strong>e Menge von Anweisungen.<br />
Erreicht e<strong>in</strong> Thread die synchronized Anweisung, dann gelten folgen<strong>de</strong> Regeln:<br />
- Der Thread versucht exklusiven Zugriff auf das Objekt O zu erhalten.<br />
- Wenn ke<strong>in</strong> an<strong>de</strong>rer Thread <strong>de</strong>n exklusiven Zugriff auf das Objekt hat, gel<strong>in</strong>g dies.<br />
- Besitzt e<strong>in</strong> an<strong>de</strong>rer Thread <strong>de</strong>n exklusiven Zugriff auf das Objekt, dann wartet <strong>de</strong>r Thread, bis das<br />
Objekt O wie<strong>de</strong>r freigegeben wird. Es können mehrere Threads auf die Freigabe warten.<br />
- Erhält e<strong>in</strong> Thread <strong>de</strong>n exklusiven Zugriff auf O, dann tritt er <strong>in</strong> <strong>de</strong>n Anweisungsblock e<strong>in</strong>.<br />
- Verläßt <strong>de</strong>r Thread <strong>de</strong>n Anweisungsblock, <strong>in</strong> <strong>de</strong>m er <strong>de</strong>n exklusiven Zugriff erhalten hat, dann gibt er<br />
das Objekt wie<strong>de</strong>r frei.<br />
118 Dies macht es extrem schwierig <strong>in</strong> e<strong>in</strong>em fertigen System fehlerhafte Co<strong>de</strong>-Stellen zu f<strong>in</strong><strong>de</strong>n. Vor allem kann<br />
alle<strong>in</strong> das Suchen <strong>de</strong>s Fehlers mit Hilfe vom Debugger <strong>de</strong>n Fehler verschw<strong>in</strong><strong>de</strong>n lassen. Durch das Beobachten<br />
mit <strong>de</strong>m Debugger wird das Abwechseln von Threads bee<strong>in</strong>flusst.<br />
119 Für e<strong>in</strong>e performante Än<strong>de</strong>rung e<strong>in</strong>es Str<strong>in</strong>g steht die Klasse java.lang.Str<strong>in</strong>gBuffer zur<br />
Verfügung, diese ist aber nicht sicher für die gleichzeitige Verwendung durch mehrere Threads (thread safe).<br />
107
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Wenn e<strong>in</strong>e Ausnahme (exception) auftritt, die nicht <strong>in</strong>nerhalb e<strong>in</strong>es<br />
Anweisungsblocks abgefangen wird, dann wird <strong>de</strong>r Ausnahmeblock automatisch<br />
verlassen und dabei auch die Sperre wie<strong>de</strong>r freigegeben.<br />
Verschachteln von synchronisierten Anweisungsblöcken ist möglich, auch wenn<br />
mehrmals mit <strong>de</strong>m gleichen Objekt synchronisiert wird. Erst beim Verlassen <strong>de</strong>s<br />
äußeren Anweisungsblocks wird das Objekt freigegeben.<br />
Kritischer Bereich. In das letzte Beispiel kann zum Synchronisieren das<br />
Schlüsselwort synchronized e<strong>in</strong>gesetzt wer<strong>de</strong>n. Prüfung und Inkrementierung<br />
stellen e<strong>in</strong>en kritischen Bereich dar. Das ist e<strong>in</strong> Bereich, <strong>in</strong> <strong>de</strong>m Konflikte auftreten<br />
können.<br />
Den kritischen Bereich kann man auch <strong>in</strong> e<strong>in</strong>er eigenen Metho<strong>de</strong> zusammen fassen.<br />
public class SynchroTest extends Thread<br />
{<br />
static <strong>in</strong>t zaehler = 0;<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
Thread t1 = new SynchroTest();<br />
Thread t2 = new SynchroTest();<br />
t1.start();<br />
t2.start();<br />
}<br />
static synchronized void schreibe()<br />
{<br />
}<br />
System.out.pr<strong>in</strong>t(zaehler + " ");<br />
zaehler++;<br />
if (zaehler > 25) System.exit(0);<br />
}<br />
public void run()<br />
{<br />
while (true) schreibe();<br />
}<br />
Abb.: Mögliche Ausgabe von OhneSynchroTest bzw. SynchroTest<br />
Es wird gewährleistet, dass nur e<strong>in</strong> Thread gleichzeitig <strong>in</strong> genau dieser Metho<strong>de</strong> aktiv<br />
se<strong>in</strong> kann. Es wird nicht gewährleistet, dass ke<strong>in</strong> an<strong>de</strong>rer Thread gleichzeitig <strong>in</strong> e<strong>in</strong>er<br />
an<strong>de</strong>ren Metho<strong>de</strong> aktiv ist, d. h. zaehler kann <strong>in</strong> e<strong>in</strong>er an<strong>de</strong>ren Metho<strong>de</strong> weiterh<strong>in</strong><br />
gleichzeitig geän<strong>de</strong>rt wer<strong>de</strong>n. Das be<strong>de</strong>u<strong>de</strong>t auch:<br />
"Lesen<strong>de</strong> Metho<strong>de</strong>n müssen synchronisiert wer<strong>de</strong>n".<br />
Bsp.: E<strong>in</strong>führen <strong>de</strong>r Metho<strong>de</strong> getZaehler(), die <strong>de</strong>n Zählerstand zurückliefert<br />
static long getZaehler()<br />
{<br />
return zaehler;<br />
}<br />
108
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Metho<strong>de</strong> getZaehler() kann aus folgen<strong>de</strong>n Grün<strong>de</strong>n e<strong>in</strong> fehlerhaftes Ergebnis haben:<br />
- getZaehler() kann ausgeführt wer<strong>de</strong>n, während irgen<strong>de</strong><strong>in</strong>e an<strong>de</strong>re auch synchronisierte<br />
Metho<strong>de</strong> (z.B. <strong>in</strong>krementieren()) aus e<strong>in</strong>er Subklasse heraus ausgeführt wird. Diese an<strong>de</strong>re<br />
Metho<strong>de</strong> könnte zaehler zwischenzeitlich auf –1 setzen und erst am En<strong>de</strong> e<strong>in</strong>en korrekten Wert<br />
zuweisen. Die Metho<strong>de</strong> getZaehler() könnte zwischenzeitlich <strong>de</strong>n uns<strong>in</strong>nigen Wert –1 liefern.<br />
- Auch wenn ke<strong>in</strong>er <strong>de</strong>n Wert zwischenzeitlich auf –1 setzt, kann getZaehler() e<strong>in</strong>en falschen Wert<br />
liefern. <strong>Java</strong> garantiert, dass alle Operationen auf primitiven Typen atomar ausgeführt wer<strong>de</strong>n,<br />
außer für double und long. Das be<strong>de</strong>utet: Die Ausführung von ++zaehler könnte <strong>in</strong> zwei<br />
Schritten ablaufen. Zwischen <strong>de</strong>n bei<strong>de</strong>n Schritten könnte e<strong>in</strong> Schrittwechsel auftreten. Der Wert<br />
von zaehler nach <strong>de</strong>m 1. Schritt ist nicht spezifiziert.<br />
Aus diesen Grün<strong>de</strong>n muß getZaehler() synchronisiert wer<strong>de</strong>n:<br />
static synchronized long getZaehler()<br />
{<br />
return zaehler;<br />
}<br />
Synchronisierte Metho<strong>de</strong>n und Vererbung. Die Synchronisation gehört <strong>in</strong> <strong>Java</strong> nur<br />
zur Implementierung und wird nicht vererbt. Daher kann auch e<strong>in</strong>e Interface-<br />
Def<strong>in</strong>ition nicht das Schlüsselwort synchronized enthalten.<br />
Synchronisation statischer Metho<strong>de</strong>n. In <strong>Java</strong> gehört zu je<strong>de</strong>r Klasse e<strong>in</strong>e, vom<br />
System erzeugte Instanz <strong>de</strong>r Klasse java.lang.Class. Diese Instanz beschreibt<br />
<strong>de</strong>n Aufbau <strong>de</strong>r Klasse und macht dies zur Laufzeit verfügbar. Der Klassenname<br />
gefogt von ".class" liefert die Instanz. Wenn e<strong>in</strong>e statische Metho<strong>de</strong> als<br />
synchronized gekennzeichnet ist, entspricht dies e<strong>in</strong>er Synchronisierung mit <strong>de</strong>r<br />
zu dieser Instanz gehören<strong>de</strong>n Instanz <strong>de</strong>r Klasse java.lang.Class 120 .<br />
Bsp.:<br />
public class Zaehler<br />
{<br />
private static long maximum = 1000;<br />
public static synchronized long getMaximum()<br />
{<br />
return maximum;<br />
}<br />
…<br />
}<br />
Die Metho<strong>de</strong> getMaximum() entspricht folgen<strong>de</strong>r Implementierung:<br />
public static long getMaximum()<br />
{<br />
synchronized(Zaehler.class)<br />
{<br />
return maximum;<br />
}<br />
}<br />
Bewachte kritische Bereiche. Bisher konnte e<strong>in</strong> Thread nur auf e<strong>in</strong>e e<strong>in</strong>zige<br />
Bed<strong>in</strong>gung warten und zwar darauf, ob e<strong>in</strong> Zugriff zur Verfügung steht o<strong>de</strong>r nicht.<br />
Manchmal möchte man komplexere zustandabhängige Bed<strong>in</strong>gungen formulieren, auf<br />
<strong>de</strong>ren Erfüllung man wartet. Das könnte man so beschreiben: await E then S<br />
endwait, wobei E e<strong>in</strong> boolscher Ausdruck (Wächter) und S e<strong>in</strong>e Menge von<br />
120 vgl. 1.4.2.2<br />
109
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Anweisungen ist. Sobald E erfüllt ist, wird S exklusiv von e<strong>in</strong>em e<strong>in</strong>zigen Thread<br />
ausgeführt.<br />
public class ClassMitGur<strong>de</strong>dSuspension<br />
{<br />
…<br />
private synchronized void awaitConditionE()<br />
{<br />
while (!E)<br />
{<br />
try {<br />
wait();<br />
}<br />
catch (InterruptedException ex) { }<br />
}<br />
}<br />
public void synchronized guar<strong>de</strong>dStatementS<br />
{<br />
awaitConditionE();<br />
S<br />
}<br />
}<br />
Die folgen<strong>de</strong>n Metho<strong>de</strong>n <strong>de</strong>r Klasse Object übernehmen "Wächter"-Funktionen:<br />
public f<strong>in</strong>al void wait()<br />
throws InterruptedException<br />
public f<strong>in</strong>al void wait(long timeout)<br />
throws InterruptedException<br />
public f<strong>in</strong>al void wait(long timeout,<strong>in</strong>t nanos) throws InterruptedException<br />
- Der aktuelle Thread wird auf wartend gesetzt und <strong>in</strong> e<strong>in</strong>en mit <strong>de</strong>m Objekt verknüpften Wartebereich<br />
gestellt<br />
- Der exklusive Zugriff, <strong>de</strong>n <strong>de</strong>r Thread hat, wird freigegeben. Das ist Voraussetzung dafür, dass<br />
an<strong>de</strong>re Threads überhaupt notify() bzw. notifyAll() aufrufen können.<br />
- Es existiert noch die Möglichkeit bei wait() die maximale Wartezeit anzugeben. Ist diese<br />
verstrichen, dann wird automatisch für diesen Thread wie bei notify() verfahren.<br />
public f<strong>in</strong>al void notify()<br />
- Wenn warten<strong>de</strong> Threads existieren, dann wird nicht<strong>de</strong>term<strong>in</strong>istisch e<strong>in</strong>er ausgewählt und dieser aus<br />
<strong>de</strong>m Wartebereich entfernt<br />
- Der ausgewählte Thread versucht Zugriff auf das Objekt zu bekommen. Der ausgewählte Thread<br />
kann <strong>de</strong>n Zugriff nur dann bekommen, wenn <strong>de</strong>r Thread <strong>de</strong>r notify() aufgerufen hat und noch im<br />
Besitz <strong>de</strong>s Zugriffs, diesen freigibt, und ke<strong>in</strong> an<strong>de</strong>rer Thread <strong>de</strong>n Zugriff erhält.<br />
- Erhält <strong>de</strong>r ausgewählte Thread später <strong>de</strong>n Zugriff, dann setzt er die Ausführung mit <strong>de</strong>m auf wait()<br />
folgen<strong>de</strong>n Co<strong>de</strong> fort.<br />
public f<strong>in</strong>al void notifyAll()<br />
- Verläuft wie notify() mit <strong>de</strong>m Unterschied, daß alle warten<strong>de</strong>n Threads aus <strong>de</strong>m Wartebereich<br />
entfernt wer<strong>de</strong>n und wie<strong>de</strong>r versuchen die Sperre zu bekommen.<br />
Nur wenn e<strong>in</strong> Thread <strong>de</strong>n exklusiven Zugriff auf e<strong>in</strong> Objekt hat, kann er <strong>de</strong>ssen<br />
wait(), notify(), o<strong>de</strong>r notifyAll() aufrufen. Ansonsten wird e<strong>in</strong>e<br />
IllegalMonitorStateException vom Laufzeitsystem erzeugt.<br />
Wenn e<strong>in</strong>e Unterbrechung während e<strong>in</strong>es wait() passiert (z.B. durch Aufruf von<br />
<strong>in</strong>terrupt() <strong>de</strong>r Klasse Thread, dann wird wie bei notify() verfahren. Die<br />
Ausführung wird aber fortgefahren mit <strong>de</strong>m Werfen e<strong>in</strong>er Ausnahme <strong>de</strong>r Klasse<br />
InterruptedException.<br />
Das Ziel ist es mit wait() auf e<strong>in</strong> Ereignis zu warten. Das Ereignis wird durch das<br />
Objekt o<strong>de</strong>r e<strong>in</strong>en Zustand <strong>de</strong>s Objekts repräsentiert. Mit notify() wird dann das<br />
E<strong>in</strong>treten <strong>de</strong>s Ereignisses mitgeteilt.<br />
Das Monitor-Konzept <strong>in</strong> <strong>Java</strong>. Zur Synchronisation nebenläufiger Prozesse hat <strong>Java</strong><br />
das Konzept <strong>de</strong>s Monitors implementiert. E<strong>in</strong> Monitor ist die Kapselung e<strong>in</strong>es<br />
kritischen Bereichs (also e<strong>in</strong>es Programmteils, <strong>de</strong>r nur von jeweils e<strong>in</strong>em Prozeß zur<br />
110
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
aktuellen Zeit durchlaufen wer<strong>de</strong>n darf) mit Hilfe e<strong>in</strong>er automatisch gesetzten Sperre.<br />
Die Sperre wird beim E<strong>in</strong>tritt <strong>in</strong> <strong>de</strong>n Monitor gesetzt und beim Verlassen wie<strong>de</strong>r<br />
zurückgenommen. Ist sie beim E<strong>in</strong>tritt <strong>in</strong> <strong>de</strong>n Monitor bereits von e<strong>in</strong>em an<strong>de</strong>ren<br />
Prozeß gesetzt, dann muß <strong>de</strong>r aktuelle Prozeß warten, bis <strong>de</strong>r Konkurent die Sperre<br />
freigegeben und <strong>de</strong>n Monitor verlassen hat.<br />
Das Monitor-Konzept wird mit Hilfe <strong>de</strong>s Schlüsselworts synchronized realisiert.<br />
Durch synchronized kann entwe<strong>de</strong>r e<strong>in</strong>e komplette Metho<strong>de</strong> o<strong>de</strong>r e<strong>in</strong> Block<br />
<strong>in</strong>nerhalb e<strong>in</strong>er Metho<strong>de</strong> geschützt wer<strong>de</strong>n. Der E<strong>in</strong>tritt <strong>in</strong> <strong>de</strong>n so <strong>de</strong>klarierten Monitor<br />
wird als Sperre <strong>de</strong>r this-Po<strong>in</strong>ter verwen<strong>de</strong>t, an<strong>de</strong>renfalls ist die Objektvariable<br />
explizit anzugeben.<br />
Neben <strong>de</strong>m Monitorkonzept stehen mit <strong>de</strong>n Metho<strong>de</strong>n wait() und notify() <strong>de</strong>r<br />
Klasse Object noch weitere Synchronisationsprimitive zur Verfügung. Zusätzlich zu<br />
<strong>de</strong>r 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 han<strong>de</strong>lt es sich um e<strong>in</strong>e (möglicherweise leere) Menge von<br />
Threads, die von e<strong>in</strong>em Scheduler unterbrochen wur<strong>de</strong>n und auf Ereignisse warten,<br />
um fortgesetzt wer<strong>de</strong>n zu können.<br />
wait() und notify() dürfen nur aufgerufen wer<strong>de</strong>n, 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 wait()<br />
nimmt die bereits gewährten Sperren (temporär) zurück und stellt <strong>de</strong>m Prozeß, <strong>de</strong>r<br />
<strong>de</strong>n Aufruf von wait() verursachte, <strong>in</strong> die Warteliste <strong>de</strong>s Objekts. Dadurch wird er<br />
unterbrochen. E<strong>in</strong> Aufruf von notify() entfernt e<strong>in</strong>en (beliebigen) Prozeß aus <strong>de</strong>r<br />
Warteliste <strong>de</strong>s Objekts, stellt die (temporär) aufgehobenen Sperren wie<strong>de</strong>r her und<br />
führt ihn <strong>de</strong>m normalen Schedul<strong>in</strong>g zu. „wait()“ und „notify()“ s<strong>in</strong>d damit für<br />
elementare Synchronisationsaufgaben geeignet, bei <strong>de</strong>nen es weniger auf die<br />
Kommunikation als auf die Steuerung zeitlicher Abläufe ankommt . Zusätzlich bietet<br />
die Klasse Object auch noch die Metho<strong>de</strong> notifyAll(). Der Unterschied zu<br />
notify() ist, dass alle warten<strong>de</strong>n Threads „aufgeweckt“ (reaktiviert wer<strong>de</strong>n, bei<br />
notify() nur e<strong>in</strong> e<strong>in</strong>ziger.<br />
Threadkommunikation<br />
Verschie<strong>de</strong>ne Threads können auf verschie<strong>de</strong>nen Wegen effizient Daten<br />
austauschen: Streams, geme<strong>in</strong>sam genutzte Objekte, statische Variablen. Die<br />
bei<strong>de</strong>n zuletzt angegebenen Alternativen basieren darauf, dass verschie<strong>de</strong>n Threads<br />
e<strong>in</strong>en geme<strong>in</strong>samen Adressraum (Heap) teilen. Somit können mehrere Thread-<br />
Objekte diesselben Objekte im Speicher ansprechen.<br />
111
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.5 Die Klassen Str<strong>in</strong>g und Str<strong>in</strong>gBuffer<br />
E<strong>in</strong> Str<strong>in</strong>g ist e<strong>in</strong>e Sammluung von Zeichen, die im Speicher geordnet abgelegt<br />
wer<strong>de</strong>n. Die Zeichen setzen sich aus e<strong>in</strong>em Zeichensatz zusammen, <strong>de</strong>r <strong>in</strong> <strong>Java</strong><br />
<strong>de</strong>m Unico<strong>de</strong>-Standard entspricht. In <strong>Java</strong> ist e<strong>in</strong>e Symbiose zwischen Str<strong>in</strong>g als<br />
Objekt und Str<strong>in</strong>g als e<strong>in</strong>gebautem Datentyp vorgenommen wor<strong>de</strong>n. Möglich ist e<strong>in</strong>e<br />
Zuweisung von Str<strong>in</strong>g-Literalen an Objekte und die Verknüpfung mehrerer Str<strong>in</strong>gs zu<br />
e<strong>in</strong>em.<br />
1.4.2.5.1 Die Klasse Str<strong>in</strong>g<br />
Die Klasse Str<strong>in</strong>g repräsentiert Zeichenketten, die sich nicht än<strong>de</strong>rn.<br />
Konstruktoren:<br />
Str<strong>in</strong>g()<br />
Str<strong>in</strong>g(Str<strong>in</strong>g wert)<br />
Str<strong>in</strong>g(char[] wert)<br />
Erzeugt e<strong>in</strong> leeres Str<strong>in</strong>g-Objekt<br />
Erzeugt e<strong>in</strong>en neuen Str<strong>in</strong>g durch Duplizierung e<strong>in</strong>es bereits<br />
vorhan<strong>de</strong>nen.<br />
Erzeugt e<strong>in</strong>en neuen Str<strong>in</strong>g aus e<strong>in</strong>em vorhan<strong>de</strong>nen Zeichen-<br />
Array.<br />
Zeichenextraktion<br />
char charAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
Str<strong>in</strong>g substr<strong>in</strong>g(<strong>in</strong>t<br />
anfang, <strong>in</strong>t en<strong>de</strong>)<br />
Str<strong>in</strong>g trim()<br />
Liefert das Zeichen an Position <strong>in</strong><strong>de</strong>x. Dabei hat das erste<br />
Element e<strong>in</strong>es Str<strong>in</strong>g <strong>de</strong>n Wert 0 und das letzte <strong>de</strong>n In<strong>de</strong>x<br />
„length()-1“. Falls <strong>de</strong>r Str<strong>in</strong>g kürzer als „<strong>in</strong><strong>de</strong>x + 1“ ist, wird e<strong>in</strong>e<br />
Ausnahme <strong>de</strong>s Typs „In<strong>de</strong>xOutOfBoundsException“ erzeugt<br />
Liefert <strong>de</strong>n Teilstr<strong>in</strong>g, <strong>de</strong>r an Position anfang beg<strong>in</strong>nt und an<br />
Position en<strong>de</strong> en<strong>de</strong>t. Wie bei allen Zugriffen über e<strong>in</strong>en<br />
numerischen In<strong>de</strong>x beg<strong>in</strong>nt hier das Zählen bei 0. „en<strong>de</strong>“<br />
verweist auf das erste Zeichen h<strong>in</strong>ter <strong>de</strong>m zu extrahieren<strong>de</strong>n<br />
Teilstr<strong>in</strong>g. Der Rückgabewert ist also die Zeichenkette, die von<br />
In<strong>de</strong>xposition anfang bis zur In<strong>de</strong>xpostion „en<strong>de</strong> –1“ reicht<br />
Liefert <strong>de</strong>n Str<strong>in</strong>g, <strong>de</strong>r entsteht, wenn auf bei<strong>de</strong>n Seiten <strong>de</strong>r<br />
Zeichenkette jeweils alle zusammenhängen<strong>de</strong>n Leerzeichen<br />
entfernt wer<strong>de</strong>n. Dabei wer<strong>de</strong>n alle Zeichen, die e<strong>in</strong>en Co<strong>de</strong><br />
kle<strong>in</strong>er 32 haben, als Leerzeichen angesehen. „trim“ entfernt<br />
immer Leerzeichen auf bei<strong>de</strong>n Seiten. Da die Klasse Str<strong>in</strong>g als<br />
f<strong>in</strong>al <strong>de</strong>f<strong>in</strong>iert wur<strong>de</strong>, gibt es ke<strong>in</strong>e Möglichkeit, entsprechen<strong>de</strong><br />
Metho<strong>de</strong>n nachzurüsten, z.B. für das rechtsbündige o<strong>de</strong>r<br />
l<strong>in</strong>ksbündige Entfernen von Leerzeichen.<br />
Länge <strong>de</strong>r Zeichenkette: <strong>in</strong>t length() liefert die aktuelle Länge <strong>de</strong>s Str<strong>in</strong>g-<br />
Objekts. Ist <strong>de</strong>r Rückgabewert 0, dann ist <strong>de</strong>r Str<strong>in</strong>g leer. Wird e<strong>in</strong> Wert „n“ größer 0<br />
zurückgegeben, dann enthält <strong>de</strong>r Str<strong>in</strong>g „n“ Zeichen, die an <strong>de</strong>n In<strong>de</strong>xpositionen 0 bis<br />
„n-1“ liegen.<br />
Vergleichen von Zeichenketten:<br />
boolean equals(Object<br />
e<strong>in</strong>Objekt)<br />
Liefert true, wenn das aktuelle Objekt und e<strong>in</strong>Objekt<br />
i<strong>de</strong>ntisch s<strong>in</strong>d. „equals“ testet auf <strong>in</strong>haltlliche Gleichheit und<br />
nicht darauf, ob bei<strong>de</strong> Str<strong>in</strong>gs dasselbe Objekt referenzieren.<br />
Neben „equals“ gibt es die Metho<strong>de</strong> equalsIgnoreCase, die<br />
evtl. vorhan<strong>de</strong>ne Unterschie<strong>de</strong> <strong>in</strong> <strong>de</strong>r Groß- und<br />
Kle<strong>in</strong>schreibung bei<strong>de</strong>r Zeichenketten ignoriert.<br />
112
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
boolean<br />
startsWith(Str<strong>in</strong>g s)<br />
boolean endsWith(Str<strong>in</strong>g<br />
s)<br />
<strong>in</strong>t compareTo(Str<strong>in</strong>g s)<br />
boolean regionMatches(<strong>in</strong>t<br />
toffset, Str<strong>in</strong>g other, <strong>in</strong>t<br />
ooffset, <strong>in</strong>t len)<br />
Testet, ob das Str<strong>in</strong>g-Objekt mit <strong>de</strong>r Zeichenkette s beg<strong>in</strong>nt.<br />
Ist dies <strong>de</strong>r Fall, dann gibt die Metho<strong>de</strong> „true“ zurück,<br />
an<strong>de</strong>renfalls „false“.<br />
Führt e<strong>in</strong>en lexikalischen Vergleich <strong>de</strong>r bei<strong>de</strong>n Str<strong>in</strong>gs durch.<br />
Bei e<strong>in</strong>em lexikalischen Vergleich wer<strong>de</strong>n die Zeichen<br />
paarweise von l<strong>in</strong>ks nach rechts verglichen. Tritt e<strong>in</strong><br />
Unterschied auf o<strong>de</strong>r ist e<strong>in</strong>er <strong>de</strong>r bei<strong>de</strong>n Str<strong>in</strong>gs been<strong>de</strong>t,<br />
wird das Ergebnis ermittelt. Ist das aktuelle Str<strong>in</strong>g-Objekt<br />
kle<strong>in</strong>er als s, wird e<strong>in</strong> negativer Wert zurückgegeben. Ist er<br />
größer, wird e<strong>in</strong> positiver Wert zurückgegeben. Bei Gleichheit<br />
liefert die Metho<strong>de</strong> <strong>de</strong>n Rückgabewert 0.<br />
Testet, ob 2 Str<strong>in</strong>g-Abschnitte gleich s<strong>in</strong>d.<br />
Suchen <strong>in</strong> Zeichenketten<br />
<strong>in</strong>t <strong>in</strong><strong>de</strong>xOf(Str<strong>in</strong>g s)<br />
<strong>in</strong>t In<strong>de</strong>xOf(Str<strong>in</strong>g s, <strong>in</strong>t<br />
vonIn<strong>de</strong>x)<br />
<strong>in</strong>t lastIn<strong>de</strong>xOf(Str<strong>in</strong>g s)<br />
Sucht das erste Vorkommen <strong>de</strong>r Zeichenkette s<br />
<strong>in</strong>nerhalb <strong>de</strong>s Str<strong>in</strong>g-Objekts. Wird s gefun<strong>de</strong>n, liefert<br />
die Metho<strong>de</strong> <strong>de</strong>n In<strong>de</strong>x <strong>de</strong>s ersten<br />
übere<strong>in</strong>stimmen<strong>de</strong>n Zeichens zurück, an<strong>de</strong>rnfalls wird<br />
–1 zurückgegeben.<br />
Die Metho<strong>de</strong> gibt es auch <strong>in</strong> e<strong>in</strong>er an<strong>de</strong>ren Version,<br />
die e<strong>in</strong>en Parameter vom Typ char akzeptiert. In<br />
diesem Fall sucht sie nach <strong>de</strong>m Auftreten <strong>de</strong>s ersten<br />
angegebenen Zeichens.<br />
Diese Metho<strong>de</strong> arbeitet wie die vorige, beg<strong>in</strong>nt mit <strong>de</strong>r<br />
Suche aber erst ab Position vonIn<strong>de</strong>x. Wird s<br />
beg<strong>in</strong>nend ab dieser Position gefun<strong>de</strong>n, liefert die<br />
Metho<strong>de</strong> <strong>de</strong>n In<strong>de</strong>x <strong>de</strong>s ersten übere<strong>in</strong>stimmen<strong>de</strong>n<br />
Zeichens, an<strong>de</strong>rnfalls –1.<br />
E<strong>in</strong>e Variante dieser Metho<strong>de</strong> erwartet anstelle e<strong>in</strong>es<br />
Str<strong>in</strong>g-Parameters e<strong>in</strong> Argument vom Typ char.<br />
Sucht nach <strong>de</strong>m letzten Vorkommen <strong>de</strong>s Teilstr<strong>in</strong>gs s<br />
im aktuellen Str<strong>in</strong>g-Objekt- Wird „s“ gefun<strong>de</strong>n, liefert<br />
die Metho<strong>de</strong> <strong>de</strong>n In<strong>de</strong>x <strong>de</strong>s ersten<br />
übere<strong>in</strong>stimmen<strong>de</strong>n Zeichens, an<strong>de</strong>rnfalls –1. E<strong>in</strong>e<br />
Variante dieser Metho<strong>de</strong> erwartet e<strong>in</strong> Argument <strong>de</strong>s<br />
Typs char.<br />
Ersetzen von Zeichenketten<br />
Str<strong>in</strong>g toLowerCase() Liefert <strong>de</strong>n Str<strong>in</strong>g zurück, <strong>de</strong>r entsteht, wenn alle Zeichen <strong>in</strong><br />
Kle<strong>in</strong>buchstaben umgewan<strong>de</strong>lt wer<strong>de</strong>n. Besitzt <strong>de</strong>r Str<strong>in</strong>g ke<strong>in</strong>e<br />
umwan<strong>de</strong>lbaren Zeichen, dann wird <strong>de</strong>r Orig<strong>in</strong>al-str<strong>in</strong>g<br />
zurückgegeben.<br />
Str<strong>in</strong>g toUpperCase() Liefert <strong>de</strong>n Str<strong>in</strong>g zurück, <strong>de</strong>r entsteht, wenn alle Zeichen <strong>in</strong><br />
Großbuchstaben umgewan<strong>de</strong>lt wer<strong>de</strong>n. Besitzt <strong>de</strong>r Str<strong>in</strong>g ke<strong>in</strong>e<br />
umwan<strong>de</strong>lbaren Zeichen, wird <strong>de</strong>r Orig<strong>in</strong>al-Str<strong>in</strong>g zurückgegeben.<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 />
Diese Metho<strong>de</strong> führt e<strong>in</strong>e zeichenweise Konvertierung <strong>de</strong>s<br />
aktuellen Str<strong>in</strong>g-Objekts durch. Je<strong>de</strong>s Auftreten von<br />
altesZeichen wird durch neuesZeichen ersetzt. Es gibt <strong>in</strong><br />
<strong>Java</strong> ke<strong>in</strong>e Metho<strong>de</strong>, die das Ersetzen von Teilstr<strong>in</strong>gs durch<br />
an<strong>de</strong>re 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 />
113
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
Die „valueOf“-Metho<strong>de</strong>n s<strong>in</strong>d als Klassenmetho<strong>de</strong>n implementiert und können ohne<br />
Str<strong>in</strong>g-Objekt aufgerufen wer<strong>de</strong>n. Da sie <strong>in</strong> <strong>de</strong>r Regel zur Erzeugung von Str<strong>in</strong>gs<br />
verwen<strong>de</strong>t wer<strong>de</strong>n, ist das s<strong>in</strong>nvoll. E<strong>in</strong> Aufruf von „valueOf“ wan<strong>de</strong>lt e<strong>in</strong> primitives<br />
Objekt mit Hilfe <strong>de</strong>r Metho<strong>de</strong> „toStr<strong>in</strong>g()“, die von <strong>de</strong>r zugehörigen Wrapper-<br />
Klassen bereitgestellt wird, <strong>in</strong> e<strong>in</strong>e Zeichenkette um.<br />
Formatieren mit format(). Die Klasse f<strong>in</strong>al class java.lang.Str<strong>in</strong>g implements<br />
CharSequence, Comparable, Serializable stellt mit <strong>de</strong>r statischen Funktion<br />
format() e<strong>in</strong>e Metho<strong>de</strong> bereit, Zeichenketten nach e<strong>in</strong>er Vorlage zu formatieren<br />
static Str<strong>in</strong>g format(Locale l, Str<strong>in</strong>g format, Object ... args)<br />
liefert e<strong>in</strong>en formatierten Str<strong>in</strong>g, <strong>de</strong>r aus <strong>de</strong>r gewünschten Sprache, <strong>de</strong>m Str<strong>in</strong>g und Argumenten<br />
hervorgeht.<br />
static Str<strong>in</strong>g format(Str<strong>in</strong>g format,Object ... args)<br />
liefert e<strong>in</strong>en formatierten Str<strong>in</strong>g, <strong>de</strong>r aus <strong>de</strong>m format-Str<strong>in</strong>g und <strong>de</strong>n Argumenten hervorgeht.<br />
Der Str<strong>in</strong>g format nennt sich Format-Str<strong>in</strong>g. Er enthält neben <strong>de</strong>m auszugeben<strong>de</strong>n<br />
Zeichen sogenannte Format-Spezifierer, die <strong>de</strong>m Formatierer darüber Auskunft<br />
geben, wie das Argument formatiert wer<strong>de</strong>n soll. "%s" steht für e<strong>in</strong>e unformatierte<br />
Ausgabe e<strong>in</strong>es Str<strong>in</strong>gs.<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 wer<strong>de</strong>n.<br />
Str<strong>in</strong>g-Objekte s<strong>in</strong>d nicht dynamisch. Es wer<strong>de</strong>n durch die Klasse Str<strong>in</strong>g ke<strong>in</strong>e<br />
dynamischen Zeichenketten implementiert. Nach <strong>de</strong>r Initialisierung e<strong>in</strong>es Str<strong>in</strong>g bleibt<br />
<strong>de</strong>ssen 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“-Metho<strong>de</strong> erzeugt e<strong>in</strong>e Kopie, die mit <strong>de</strong>m gewünschten Inhalt gefüllt<br />
wird. Diese gibt sie an <strong>de</strong>n Aufrufer zurück, <strong>de</strong>r das Ergebnis erneut s zuweist und<br />
damit die Orig<strong>in</strong>al<strong>in</strong>stanz für <strong>de</strong>n Garbage Collector freigibt.<br />
Bsp.: Anwendung von Metho<strong>de</strong>n <strong>de</strong>r 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 Stu<strong>de</strong>nten <strong>de</strong>r 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 <strong>de</strong>s 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 In<strong>de</strong>x zum Zeichen I: " + str.<strong>in</strong><strong>de</strong>xOf('I'));<br />
System.out.pr<strong>in</strong>tln("Der In<strong>de</strong>x zum Anfang von "<br />
+ "Substr<strong>in</strong>g \"beste\": " + str.<strong>in</strong><strong>de</strong>xOf("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 />
114
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
115
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.5.2 Die Klasse Str<strong>in</strong>gBuffer<br />
Die Klasse Str<strong>in</strong>gBuffer dient zur Implementierung verän<strong>de</strong>rlicher Zeichenketten.<br />
Die Metho<strong>de</strong>n <strong>de</strong>r Klasse Str<strong>in</strong>gBuffer dienen hauptsächlich <strong>de</strong>m Anhängen und<br />
E<strong>in</strong>fügen von Texten. Dabei wird <strong>de</strong>r benötigte Speicherplatz automatisch <strong>de</strong>r Größe<br />
angepaßt.<br />
Konstruktoren:<br />
Str<strong>in</strong>gBuffer()<br />
Erzeugt e<strong>in</strong>en leeren Str<strong>in</strong>gBuffer<br />
Str<strong>in</strong>gBuffer(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 <strong>de</strong>r<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 En<strong>de</strong> <strong>de</strong>s 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 Metho<strong>de</strong> 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 <strong>de</strong>r<br />
entsprechen<strong>de</strong> primitive Typ übergeben, <strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g<br />
konvertiert und an das En<strong>de</strong> <strong>de</strong>s 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 <strong>de</strong>n Str<strong>in</strong>g s an die Position offset <strong>in</strong> <strong>de</strong>n<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 Metho<strong>de</strong><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 />
Verän<strong>de</strong>rn von Elementen: „void setCharAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, char c) throws<br />
In<strong>de</strong>xOutOfBoundsException“. Das an Position <strong>in</strong><strong>de</strong>x stehen<strong>de</strong> Zeichen wird<br />
durch c ersetzt. Falls Str<strong>in</strong>gBuffer zu kurz ist, löst die Metho<strong>de</strong> e<strong>in</strong>e Ausnahme<br />
<strong>de</strong>s Typs In<strong>de</strong>xOutOfBoundsException aus.<br />
Länge e<strong>in</strong>es Str<strong>in</strong>g-Objekts: <strong>in</strong>t length() liefert die Länge <strong>de</strong>s Objekts (Anzahl<br />
<strong>de</strong>r Zeichen, die zum Zeitpunkt <strong>de</strong>s Aufrufs <strong>in</strong> <strong>de</strong>m 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(). Nach<strong>de</strong>m die Konstruktion<br />
e<strong>in</strong>es Str<strong>in</strong>gBuffer-Objekts abgeschlossen ist, kann es mit Hilfe dieser Metho<strong>de</strong><br />
<strong>in</strong> e<strong>in</strong>en Str<strong>in</strong>g verwan<strong>de</strong>lt wer<strong>de</strong>n. Die Metho<strong>de</strong> legt dabei ke<strong>in</strong>e Kopie <strong>de</strong>s<br />
Str<strong>in</strong>gBuffer-Objekts an, son<strong>de</strong>rn liefert e<strong>in</strong>en Zeiger auf <strong>de</strong>n <strong>in</strong>ternen Zeichenpuffer.<br />
Erst wenn <strong>de</strong>r Str<strong>in</strong>gBuffer erneut verän<strong>de</strong>rt wer<strong>de</strong>n soll, wird tatsächlich e<strong>in</strong>e Kopie<br />
erzeugt.<br />
116
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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“-Metho<strong>de</strong>: public static double random(). Die<br />
„random“-Metho<strong>de</strong> gibt e<strong>in</strong>e Zahl zwischen 0.0 und 1.0 aus.<br />
4. Run<strong>de</strong>n<br />
Run<strong>de</strong>n e<strong>in</strong>er Zahl vom Typ float: public static <strong>in</strong>t round(float a). Gerun<strong>de</strong>t wird auf<br />
die nächste ganze Zahl (z.B. 5.4 auf 5, 5.5. auf 6)<br />
Run<strong>de</strong>n e<strong>in</strong>er Zahl vom Typ double: public static long round(double a)<br />
Abrun<strong>de</strong>n: public static double floor(double a). Math.floor run<strong>de</strong>t immer ab, z.B.<br />
ergibt Math.floor(4.99) die Zahl 4.0.<br />
Aufrun<strong>de</strong>n: public static double ceil(double a). ceil run<strong>de</strong>r immer auf, z.B.:<br />
Math.ceil(4.01) ergibt 5.0.<br />
Run<strong>de</strong>n auf die nächste ganze Zahl: public static double r<strong>in</strong>t(double a).<br />
5. Exponenten und Logarithmen<br />
x<br />
Bestimmen <strong>de</strong>s Expoentialwerts e : public static double exp(double x)<br />
Bestimmen <strong>de</strong>s natürlichen algorithmus ln(x ) : public static double log(double x)<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. Potenzen, Quadratwurzel<br />
y<br />
Bestimmen vom Wert <strong>de</strong>r Potenz x : public static double pow(double x, double y)<br />
Bestimmen <strong>de</strong>r Quadratwurzel von x: public static double sqrt(double x)<br />
8. Mathematische Konstanten<br />
public static f<strong>in</strong>al double E;<br />
public static f<strong>in</strong>al double PI;<br />
117
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.2.7 Object-Wrapper-Klassen<br />
Die Object-Wrapper-Klassen s<strong>in</strong>d Wrapper für primitive Typen. Zusätzlich besitzen<br />
sie Metho<strong>de</strong>n zur Umwandlung von Zeichenketten <strong>in</strong> die verschie<strong>de</strong>nen Datentypen.<br />
Boolean<br />
Character<br />
public static f<strong>in</strong>al Boolean TRUE<br />
public static f<strong>in</strong>al Boolean FALSE<br />
public static f<strong>in</strong>al char MIN_VALUE<br />
public staic f<strong>in</strong>al char MAX_VALUE<br />
public boolean booleanValue()<br />
public static Boolean valueOf(Str<strong>in</strong>g s)<br />
public static boolean getBoolean(Str<strong>in</strong>g name)<br />
public char charValue()<br />
public Character(char value)<br />
public <strong>in</strong>t hashCo<strong>de</strong>()<br />
public boolean equals(Object obj)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
public static boolean isLowerCase(char ch)<br />
public static boolean isUpperCase(char ch)<br />
public static boolean isDigit(char ch)<br />
public static boolean isLetter(char ch)<br />
public static boolean isLetterOrDigit(char ch)<br />
public static boolean is<strong>Java</strong>Letter(char ch)<br />
public static boolean is<strong>Java</strong>LetterOrDigit(char c)<br />
public static boolean isSpace(char ch)<br />
public static boolean isTitleCase(char ch)<br />
public static char toLowerCase(char ch)<br />
public static char toUpperCase(char ch)<br />
public static <strong>in</strong>t digit(char ch, <strong>in</strong>t radix)<br />
public static <strong>in</strong>t getNumericValue(char ch)<br />
Number<br />
{ abstract }<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 />
public byte byteValue()<br />
public short shortValue()<br />
Byte Short Integer Long Float Double<br />
Abb.: Wrapper-Klassen<br />
118
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klasse Character<br />
Konstruktor:<br />
Ermitteln vom „char“-Wert: public char charValue()<br />
Klassifizieren von Zeichen:<br />
Metho<strong>de</strong><br />
Beschreibung<br />
isDigit E<strong>in</strong>e numerische Zahl zwischen 0 und 9<br />
isLetter<br />
E<strong>in</strong> Buchstabe <strong>de</strong>s Alphabets<br />
isLetterOrDigit<br />
E<strong>in</strong> alphabetischer Buchstabe o<strong>de</strong>r e<strong>in</strong>e numerische Zahl<br />
isLowerCase<br />
isUpperCase<br />
E<strong>in</strong> großgeschriebener alphabetischer Buchstabe<br />
is<strong>Java</strong>Letter<br />
E<strong>in</strong> Buchstabe, ‚$‘ o<strong>de</strong>r ‚_‘<br />
is<strong>Java</strong>LetterOrDigit E<strong>in</strong> Buchstabe, e<strong>in</strong>e Zahl, $ o<strong>de</strong>r _<br />
isSpace<br />
E<strong>in</strong>e Leerstelle, e<strong>in</strong>e neue Zeile, e<strong>in</strong> Return, e<strong>in</strong> Tab o<strong>de</strong>r e<strong>in</strong><br />
Formularvorschub<br />
isTitleCase<br />
Spezielle zweibuchstabige groß- und kle<strong>in</strong>geschriebene Buchstaben<br />
Je<strong>de</strong> dieser Klassifikationsmerkmale gibt „true“ zurück, wenn das betreffen<strong>de</strong><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 />
Konvertierungsmetho<strong>de</strong>n 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 <strong>de</strong>n numerischen Wert e<strong>in</strong>es Zeichens <strong>de</strong>r angegebenen Zahlendarstellung<br />
(„radix“) 121 wie<strong>de</strong>r. Falls e<strong>in</strong> Zeichen ke<strong>in</strong>em Wert <strong>in</strong> <strong>de</strong>r 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 <strong>de</strong>r Objekt-Wrapper für <strong>de</strong>n 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, <strong>de</strong>r <strong>in</strong> e<strong>in</strong>em Objekt abgelegt ist:<br />
public boolean booleanValue()<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 />
121 z.B. 10 für <strong>de</strong>zimal, 8 für oktal, 16 für hexa<strong>de</strong>zimal. Zahlenbasis kann Werte von 2<br />
(Character.MIN_RADIX) bir 32 (Character.MAX_RADIX) umfassen.<br />
119
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Objekt-Wrapper <strong>de</strong>r Typen <strong>in</strong>t, long, float und double s<strong>in</strong>d Subklassen <strong>de</strong>r<br />
abstrakten Klasse Number. Vier Metho<strong>de</strong>n 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 />
Umwan<strong>de</strong>ln 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 bei<strong>de</strong>n Metho<strong>de</strong>n dürfen nicht mit <strong>de</strong>r Instanz-Metho<strong>de</strong> toStr<strong>in</strong>g verwechselt<br />
wer<strong>de</strong>n, die für alle Subklassen von Objekt <strong>de</strong>f<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 <strong>de</strong>r Integer-Klasse i<strong>de</strong>ntisch. Allerd<strong>in</strong>gs dient sie als Wrapper<br />
für long-Werte.<br />
3. Die Klasse Float<br />
Sie enthält e<strong>in</strong>en Objekt-Wrapper für <strong>de</strong>n 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 isInf<strong>in</strong>ite(float f)<br />
public static boolean isNaN(float f) // Instanz-Variante<br />
public boolean isNaN()<br />
// Instanz-Variante<br />
Konstanten:<br />
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 />
120
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4. Die Klasse Double<br />
Sie hat dieselbe Funktionalität wie die Float-Klasse.<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 <strong>de</strong>rartige<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 wer<strong>de</strong>n, wenn e<strong>in</strong>e<br />
Ausnahmebed<strong>in</strong>gung vorliegt. Diese Objekte wer<strong>de</strong>n von <strong>de</strong>r Metho<strong>de</strong> an das<br />
aufrufen<strong>de</strong> Programm zurückgegeben und müssen behan<strong>de</strong>lt wer<strong>de</strong>n. Das<br />
Behan<strong>de</strong>ln 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. 122 :<br />
public <strong>in</strong>t dividiere()<br />
{<br />
// ganzzahlige Division<br />
try {<br />
/* Innerhalb <strong>de</strong>s try-Blocks wer<strong>de</strong>n 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 />
122 pr14103<br />
121
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
In <strong>de</strong>r catch-Klausel wird die Art <strong>de</strong>r aufzufangen<strong>de</strong>n Ausnahme <strong>de</strong>f<strong>in</strong>iert. Dort ist<br />
e<strong>in</strong> formaler Parameter angegeben, <strong>de</strong>r beim Auftreten <strong>de</strong>r Ausnahme e<strong>in</strong><br />
Fehlerobjekt übernehmen soll. Fehlerobjekte s<strong>in</strong>d Instanzen <strong>de</strong>r Klasse Throwable<br />
(o<strong>de</strong>r e<strong>in</strong>e ihrer Unterklassen). Sie wer<strong>de</strong>n vom Aufrufer <strong>de</strong>r Ausnahme erzeugt und<br />
als Parameter an die catch-Klausel übergeben. Das Fehlerobjekt enthält<br />
Informationen über die Art <strong>de</strong>r aufgetretenen Ausnahme. Es kann dort e<strong>in</strong>e <strong>de</strong>r<br />
zahlreichen Standardausnahmen von <strong>Java</strong> stehen o<strong>de</strong>r auch selbst<strong>de</strong>f<strong>in</strong>ierte<br />
Ausnahmen. Das Ausnahme- / Fehlerobjekt besitzt e<strong>in</strong>ige nützliche Metho<strong>de</strong>n, z.B.<br />
public Str<strong>in</strong>g getMessage() 123 . Diese Metho<strong>de</strong> gibt Fehlermeldungen zurück.<br />
public void pr<strong>in</strong>tStackTrace(). Diese Metho<strong>de</strong> druckt e<strong>in</strong>en Auszug aus<br />
<strong>de</strong>m Laufzeit-Stack.<br />
Am En<strong>de</strong> e<strong>in</strong>es try-Blocks können beliebig viele „catch“-Klauseln stehen, so daß<br />
unterschiedliche Arten von Ausnahmen behan<strong>de</strong>lt wer<strong>de</strong>n können.<br />
Mit Hilfe <strong>de</strong>r f<strong>in</strong>ally-Klausel (letzter Bestandteil e<strong>in</strong>er try-catch-Anweisung)<br />
kann e<strong>in</strong> Programmfragment <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n, das immer ausgeführt wird, wenn die<br />
zugehörige try-Klausel betreten wur<strong>de</strong>.<br />
Bsp.: Rückgabe von „Resourcen“ <strong>in</strong> <strong>de</strong>r f<strong>in</strong>ally-Klausel<br />
In <strong>de</strong>m folgen<strong>de</strong>n Programm stellt die f<strong>in</strong>ally-Klausel sicher, daß <strong>de</strong>r Schalter<br />
tatsächlich nach <strong>de</strong>m En<strong>de</strong> <strong>de</strong>r 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 Quellco<strong>de</strong> bef<strong>in</strong><strong>de</strong>n, <strong>de</strong>r<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 />
123 Sie ist <strong>in</strong> <strong>de</strong>r Klasse Throwable <strong>de</strong>f<strong>in</strong>iert und daher allen Exception-Objekten zugänglich.<br />
122
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 Metho<strong>de</strong>n<strong>de</strong>klaration mit <strong>de</strong>r „throws“-Klausel, z.B.:<br />
public class Me<strong>in</strong>eAusnahmenKlasse<br />
{<br />
public void e<strong>in</strong>eAusnahmenMetho<strong>de</strong>() throws Me<strong>in</strong>eAusnahme<br />
{<br />
.........<br />
}<br />
}<br />
Hier wird <strong>de</strong>m Compiler mitgeteilt, daß <strong>de</strong>r vorliegen<strong>de</strong> Co<strong>de</strong> e<strong>in</strong>e Ausnahme<br />
(„Me<strong>in</strong>eAusnahme“) erzeugen könnte.<br />
Falls <strong>in</strong> <strong>de</strong>r mit „throws“ gekennzeichneten Metho<strong>de</strong> e<strong>in</strong>e Ausnahmesituation<br />
auftritt, dann wird die aufrufen<strong>de</strong> Metho<strong>de</strong> nach e<strong>in</strong>er Ausnahmebehandlung<br />
durchsucht. Enthält die aufrufen<strong>de</strong> Metho<strong>de</strong> e<strong>in</strong>e Ausnahmebehandlungsmetho<strong>de</strong>,<br />
wird mit dieser die Ausnahme bearbeitet. Ist ke<strong>in</strong>e Rout<strong>in</strong>e vorhan<strong>de</strong>n, wird <strong>de</strong>ren<br />
aufrufen<strong>de</strong> Metho<strong>de</strong> durchsucht und so fort. Die Ausnahme wird von <strong>de</strong>r<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 <strong>de</strong>r <strong>Java</strong>-<br />
Interpreter normalerweise die Ausführung <strong>de</strong>s 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 Behan<strong>de</strong>ln e<strong>in</strong>er Ausnahme wird „catch<strong>in</strong>g“ genannt.<br />
Das Grundpr<strong>in</strong>zip <strong>de</strong>s Exception-Mechanismus:<br />
- E<strong>in</strong> Laufzeitfehler o<strong>de</strong>r 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 entwe<strong>de</strong>r vom Programmteil, <strong>in</strong> <strong>de</strong>m sie angelegt wur<strong>de</strong>, behan<strong>de</strong>lt wer<strong>de</strong>n, o<strong>de</strong>r sie kann<br />
weitergegeben wer<strong>de</strong>n.<br />
- Wird die Ausnahme weitergegeben, so hat <strong>de</strong>r Empfänger erneut die Möglichkeit sie entwe<strong>de</strong>r zu behan<strong>de</strong>ln<br />
o<strong>de</strong>r selbst weiterzugeben.<br />
- Wird die Ausnahme von ke<strong>in</strong>em Programmteil behan<strong>de</strong>lt, 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 entwe<strong>de</strong>r 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 o<strong>de</strong>r<br />
über die throws-Klausel an <strong>de</strong>n übergeordneten Programmblock weitergeleitet<br />
wer<strong>de</strong>n. Falls we<strong>de</strong>r die „Behandlung vor Ort“ noch e<strong>in</strong>e throws-Klausel verwen<strong>de</strong>t<br />
wird, liefert <strong>de</strong>r Compiler bereits bei <strong>de</strong>r Übersetzung e<strong>in</strong>e Fehlermeldung. E<strong>in</strong>e<br />
Ausnahme bil<strong>de</strong>t die Klasse RuntimeException e<strong>in</strong>schl. ihrer Subklassen. Für sie<br />
ist we<strong>de</strong>r die Fehlerbehandlung noch Weiterleitung mit <strong>de</strong>r 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 bei<strong>de</strong>n Ausnahmeklassen s<strong>in</strong>d<br />
die wichtigsten Ausnahmen und Fehler <strong>de</strong>r <strong>Java</strong>-Laufzeitbibliothek bereits enthalten.<br />
Ausnahmen <strong>de</strong>r Klasse Error und ihrer Klasse RuntimeError (sowie<br />
RuntimeException) müssen nicht extra abgefangen wer<strong>de</strong>n. „Errors“ s<strong>in</strong>d<br />
systembed<strong>in</strong>gt, „Exceptions“ dagegen programmbed<strong>in</strong>gt und müssen behan<strong>de</strong>lt<br />
123
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
wer<strong>de</strong>n. Es gibt fünf Typen von Ausnahmen, die <strong>in</strong> e<strong>in</strong>er throws-Klausel aufgelistet<br />
wer<strong>de</strong>n müssen:<br />
ClassNotFoundException<br />
IllegalAccessException<br />
InstantiationException<br />
InterruptedException<br />
NoSuchMethodException<br />
H<strong>in</strong>zu kommen verschie<strong>de</strong>ne weitere Ausnahmen aus <strong>de</strong>n <strong>Java</strong>-Paketen. So gibt es<br />
spezielle Fehlerklassen für die E<strong>in</strong>- und Ausgabe, die Netzwerkkommunikation o<strong>de</strong>r<br />
<strong>de</strong>n Zugriff auf Datenfel<strong>de</strong>r. Teilweise s<strong>in</strong>d sie <strong>de</strong>r Klasse „Error“ (o<strong>de</strong>r ihrer<br />
Subklasse RuntimeError) zugeordnet und müssen nicht extra abgefangen und<br />
dokumentiert wer<strong>de</strong>n. S<strong>in</strong>d Ausnahmen <strong>de</strong>r Klasse Exception (Ausnahme:<br />
RuntimeException) zugeordnet, dann müssen sie behan<strong>de</strong>lt wer<strong>de</strong>n (z.B. alle<br />
Ausnahmen von java.io).<br />
Die Klasse RuntimeException ist die Superklasse für die Behandlung aller<br />
Laufzeitfehler, die behan<strong>de</strong>lt wer<strong>de</strong>n können aber nicht müssen (die Entscheidung<br />
liegt beim Programmierer).<br />
UnknownError<br />
VirtualMach<strong>in</strong>eError<br />
OutOfMemoryError<br />
InternalError<br />
Error<br />
AWTError<br />
Object<br />
Throwable<br />
L<strong>in</strong>kageError<br />
ClassNotFoundException<br />
Exception<br />
RuntimeException<br />
EOFException<br />
IOException<br />
FileNotFoundException<br />
InterruptedException<br />
UTFDataFormatException<br />
Abb.: Fehlerklassenhierarchie<br />
Auslösen von Ausnahmen<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 <strong>de</strong>r Basis<br />
<strong>de</strong>r IO-Exception). Selbst<strong>de</strong>f<strong>in</strong>ierte Ausnahmen benötigen e<strong>in</strong>e Subklasse von<br />
Exception. Das Auslösen dieser selbst<strong>de</strong>f<strong>in</strong>ierten Ausnahmen erfolgt über die throw-<br />
Anweisung: throw AusnahmeObjekt.<br />
Die Behandlung selbstausgelöseter Ausnahmen erfolgt nach <strong>de</strong>n üblichen Regeln:<br />
124
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- Suche nach e<strong>in</strong>em Ausnahmen-Handler <strong>in</strong> <strong>de</strong>n umgeben<strong>de</strong>n Blöcken<br />
- Bei erfolgloser Suche Weitergabe <strong>de</strong>s Fehlers an <strong>de</strong>n Aufrufer.<br />
Wird die Ausnahme nicht <strong>in</strong>nerhalb <strong>de</strong>rselben Metho<strong>de</strong> behan<strong>de</strong>lt, dann ist sie mit<br />
Hilfe <strong>de</strong>r "throws"-Klausel zu <strong>de</strong>klarieren und „weiter oben“ <strong>in</strong> <strong>de</strong>r Aufrufkette zu<br />
behan<strong>de</strong>ln.<br />
Bsp.:<br />
public class AusnahmeMetho<strong>de</strong>n<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<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 AusnahmeMetho<strong>de</strong>n.ma<strong>in</strong>(AusnahmeMetho<strong>de</strong>n.java)<br />
*/<br />
Die throw-Anweisung besitzt Merkmale e<strong>in</strong>er Sprunganweisung. Sie unterbricht das<br />
Programm und verzweigt unmittelbar zur umgeben<strong>de</strong>n catch-Klausel. Gibt es ke<strong>in</strong>e<br />
catch-Klausel, wird <strong>de</strong>r 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 <strong>de</strong>r<br />
Weitergabe ausgeführt.<br />
Auch das „Wie<strong>de</strong>rauswerfen“ e<strong>in</strong>er Ausnahme ist möglich, <strong>in</strong>sbeson<strong>de</strong>re dann, falls<br />
e<strong>in</strong>e Ausnahme e<strong>in</strong>gefangen wur<strong>de</strong>, sie aber <strong>in</strong> e<strong>in</strong>em größeren Zusammenhang<br />
behan<strong>de</strong>lt wer<strong>de</strong>n soll<br />
catch (Exception a)<br />
{<br />
System.out.pr<strong>in</strong>tln("E<strong>in</strong>e Ausnahme wur<strong>de</strong> e<strong>in</strong>gefangen");<br />
throw a;<br />
}<br />
Eigene, d.h. benutzer<strong>de</strong>f<strong>in</strong>ierte Ausnahmen können direkt von <strong>de</strong>r Klasse<br />
Exception abgeleitet wer<strong>de</strong>n, z.B. 124 :<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 />
124 Vgl. pr14140<br />
125
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
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 { f(); }<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 />
{ a.pr<strong>in</strong>tStackTrace(); }<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 Co<strong>de</strong>)<br />
at java.lang.Exception.(Compiled Co<strong>de</strong>)<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 Co<strong>de</strong>)<br />
at java.lang.Exception.(Compiled Co<strong>de</strong>)<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 Co<strong>de</strong>)<br />
at java.lang.Exception.(Compiled Co<strong>de</strong>)<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 />
126
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
at AuswurfMe<strong>in</strong>eAusnahme.ma<strong>in</strong>(AuswurfMe<strong>in</strong>eAusnahme.java:50)<br />
a.wert() = 13<br />
*/<br />
127
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.4 E<strong>in</strong>-, Ausgaben<br />
Quelle E i n g a b e s t r o m read() Programm<br />
Programm write() A u s g a b e s t r o m Senke<br />
Abb.: Input und Output Stream<br />
E<strong>in</strong>lesen von Daten aus e<strong>in</strong>er externen Quelle (source) o<strong>de</strong>r Ausgabe zu e<strong>in</strong>er<br />
externen Senke (s<strong>in</strong>k).<br />
Daten können aus verschie<strong>de</strong>nen Quellen stammen: Tastatur, Datei, Speicher,<br />
Internet, an<strong>de</strong>res Programm.<br />
Daten können von verschie<strong>de</strong>ner Art se<strong>in</strong>: Zeichen, Objekte, Bil<strong>de</strong>r, ....<br />
Daten können zu verschie<strong>de</strong>nen Ausgabee<strong>in</strong>heiten gehen: Bildschirm, Datei,<br />
Drucker, Speicher, Internet, an<strong>de</strong>res Programm.<br />
Daten wer<strong>de</strong>n generell sequentiell gelesen o<strong>de</strong>r geschrieben<br />
1.4.4.1 E<strong>in</strong>- und Ausgabeströme <strong>de</strong>r Klasse System<br />
Die Klasse System enthält drei Datenströme:<br />
public static InputStream 125 <strong>in</strong><br />
public static Pr<strong>in</strong>tStream 126 out<br />
public static Pr<strong>in</strong>tStream err<br />
// Standar<strong>de</strong><strong>in</strong>gabe<br />
// Standardausgabe<br />
// Standardfehlerausgabe<br />
Diese Datenströme dienen zum Lesen bzw. Schreiben <strong>in</strong> das Fenster von <strong>de</strong>m die<br />
Anwendung gestartet wur<strong>de</strong>. Die Verwendung <strong>de</strong>s Stroms System.<strong>in</strong> <strong>in</strong>nerhalb von<br />
Applets ist aber nicht s<strong>in</strong>nvoll, weil die verschie<strong>de</strong>n Browser diesen Datenstrom<br />
unterschiedlich behan<strong>de</strong>ln. Die Ströme System.out und System.err sen<strong>de</strong>t<br />
Netscape an das Fenster <strong>de</strong>r <strong>Java</strong>-Konsole, <strong>de</strong>r Appletviewer gibt sie <strong>in</strong> das Fenster<br />
weiter, aus <strong>de</strong>m <strong>de</strong>r Appletviewer gestartet wur<strong>de</strong>,<br />
E<strong>in</strong>fache Ausgaben auf das Standard-Ausgabegerät<br />
Mit Hilfe <strong>de</strong>s 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 <strong>de</strong>n Bildschirm geschrieben<br />
wer<strong>de</strong>n. Mit Hilfe <strong>de</strong>s Plus-Operators „+“ können Zeichenketten und numerische<br />
Argumente verknüpft wer<strong>de</strong>n, so daß man neben Text auch Zahlen ausgeben kann.<br />
E<strong>in</strong>fache E<strong>in</strong>gaben vom Standard-E<strong>in</strong>gabegerät<br />
125 Mit <strong>de</strong>r Klasse InputStream können Leseoperationen e<strong>in</strong>es Bytestroms verwirklicht wer<strong>de</strong>n, vgl. 7.1.1<br />
126 Die Klasse Pr<strong>in</strong>tStream bezieht sich auf die I/O von <strong>Java</strong> 1.0<br />
128
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Lei<strong>de</strong>r ist es etwas komplizierter Daten zeichenweise von <strong>de</strong>r Tastatur zu lesen. Es<br />
steht zwar e<strong>in</strong> vor<strong>de</strong>f<strong>in</strong>ierter E<strong>in</strong>gabestrom System.<strong>in</strong> zur Verfügung, <strong>de</strong>r aber nicht<br />
die e<strong>in</strong>gelesenen Zeichen primitiver Typen konvertieren kann. Statt <strong>de</strong>ssen muß e<strong>in</strong>e<br />
Instanz <strong>de</strong>r Klasse „InputStreamRea<strong>de</strong>r“ 127 und daraus e<strong>in</strong> „BufferedRea<strong>de</strong>r“<br />
erzeugt wer<strong>de</strong>n. Dieser kann zum Lesen e<strong>in</strong>er zeilenweisen E<strong>in</strong>gabe mit<br />
Umwandlung <strong>de</strong>s Ergebnisses <strong>in</strong> e<strong>in</strong>en primitiven Typ verwen<strong>de</strong>t wer<strong>de</strong>n, z.B. 128 :<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 />
BufferedRea<strong>de</strong>r e<strong>in</strong> = new BufferedRea<strong>de</strong>r(new<br />
InputStreamRea<strong>de</strong>r(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 />
1.4.4.2 Datenströme<br />
Das grundlegen<strong>de</strong> Mo<strong>de</strong>ll 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-Mo<strong>de</strong>ll 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 <strong>de</strong>n Fähigkeiten <strong>de</strong>s jeweiligen I/O-Geräts 129 organisiert wer<strong>de</strong>n<br />
muß.<br />
Streams können auch verkettet wer<strong>de</strong>n und verschachtelt wer<strong>de</strong>n. Das Schachteln<br />
erlaubt die Konstruktion von Filtern, die bei <strong>de</strong>r E<strong>in</strong>-/Ausgabe bestimmte<br />
Zusatzfunktionen übernehmen, z.B. das Puffern von Zeichen, das Zählen von<br />
Zeichen o<strong>de</strong>r die Interpretation b<strong>in</strong>ärer Dateien.<br />
Alle Klassen zur Datene<strong>in</strong>- bzw. Datenausgabe bef<strong>in</strong><strong>de</strong>n sich im Paket java.io und<br />
s<strong>in</strong>d für Zeichenströme 130 von <strong>de</strong>n abstrakten Klassen Rea<strong>de</strong>r bzw. Writer 131<br />
abgeleitet. Allgeme<strong>in</strong>e Fehlanzeige im Paket java.io ist die Ausnahme<br />
IOException, die <strong>de</strong>shalb auch von e<strong>in</strong>er Vielzahl von Metho<strong>de</strong>n ausgelöst wer<strong>de</strong>n<br />
kann und dabei sehr unterschiedliche Be<strong>de</strong>utung annehmen kann.<br />
127 Das grundlegen<strong>de</strong> 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 />
128 Vgl. pr14150<br />
129 Hauptspeicher, Festplatte, Drucker, Netzwerk<br />
130 Für Byte-Ströme gibt es die Klassen InputStream / OutputStream e<strong>in</strong>schl. zahlreicher Subklassen<br />
131 vgl. 7.6<br />
129
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Rea<strong>de</strong>r<br />
InputStreamRea<strong>de</strong>r BufferedRea<strong>de</strong>r FilterRea<strong>de</strong>r<br />
FileRea<strong>de</strong>r<br />
Writer<br />
OutputStreamWriter BufferedWriter FilterWriter<br />
FileWriter<br />
Abb. Subklassen von Rea<strong>de</strong>r / Writer<br />
Bsp.: Das folgen<strong>de</strong> 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 132<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 />
InputStreamRea<strong>de</strong>r isr = new InputStreamRea<strong>de</strong>r(System.<strong>in</strong>);<br />
BufferedRea<strong>de</strong>r e<strong>in</strong> = new BufferedRea<strong>de</strong>r(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 wur<strong>de</strong> herangezogen:<br />
132 vgl. pr14150<br />
130
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- InputStream <strong>in</strong> <strong>de</strong>r Klasse System aus <strong>de</strong>m Paket java.lang<br />
- die abstrakte Klasse InputStream <strong>de</strong>s Pakets "java.io"<br />
- die Klasse InputStreamRea<strong>de</strong>r <strong>de</strong>s Pakets "java.io"<br />
- die Metho<strong>de</strong> "Str<strong>in</strong>g readL<strong>in</strong>e()" mit <strong>de</strong>r Klasse BufferedRea<strong>de</strong>r <strong>de</strong>s Pakets java.io<br />
Für die Ausgabe kann ebenso verfahren wer<strong>de</strong>n. Man zieht <strong>in</strong> diesem<br />
Zusammenhang zur Ausgabe heran:<br />
- die Klasse Pr<strong>in</strong>tStream (Subklasse <strong>de</strong>r 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 />
1.4.4.3 E<strong>in</strong>gabe und Ausgabe mit Dateien<br />
Dateien dienen zur Ablage von Daten auf externen Speichern. Dateien wer<strong>de</strong>n zur<br />
besseren Übersicht auf externen Speichern <strong>in</strong> sog. Verzeichnissen gespeichert – <strong>de</strong>r<br />
Zugriff auf e<strong>in</strong>e Datei ist somit über e<strong>in</strong>en Verzeichnispfad und über <strong>de</strong>n Date<strong>in</strong>amen<br />
möglich. Unter <strong>de</strong>r Vielzahl verschie<strong>de</strong>ner Dateiformate s<strong>in</strong>d beson<strong>de</strong>rs<br />
hervorzuheben: Text- und B<strong>in</strong>ärdateien.<br />
Byte-weises Schreiben und Lesen von (B<strong>in</strong>är-) Dateien<br />
Zum (Byte-weisen) Schreiben und Lesen von Dateien wer<strong>de</strong>n verwen<strong>de</strong>t: Die<br />
Klassen FileOutputStream und FileInputStream.<br />
1. Bsp.: Ausgabe e<strong>in</strong>er B<strong>in</strong>ärdatei<br />
import java.io.*;<br />
public class pr14444a<br />
{<br />
public static void ma<strong>in</strong> (Str<strong>in</strong>g args[])<br />
{<br />
File f = new File("datei.b<strong>in</strong>");<br />
try {<br />
DataOutputStream raus = new DataOutputStream(<br />
new FileOutputStream(f));<br />
for (<strong>in</strong>t i=1;i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
try {<br />
DataInputStream re<strong>in</strong> = new DataInputStream(<br />
new FileInputStream(f));<br />
for (<strong>in</strong>t i=1;i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
// Freigabe <strong>de</strong>r 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 />
2. Bsp.: Das folgen<strong>de</strong> 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 />
Das Beispiel zeigt: E<strong>in</strong>gabeströme können verschachtelt wer<strong>de</strong>n. Folgen<strong>de</strong> Klassen<br />
stehen dafür zur Verfügung (, die im Konstruktor e<strong>in</strong>en Rea<strong>de</strong>r erwarten):<br />
BufferedRea<strong>de</strong>r, L<strong>in</strong>eNumberRea<strong>de</strong>r, FilterRea<strong>de</strong>r und PushbackRea<strong>de</strong>r.<br />
E<strong>in</strong> BufferedRea<strong>de</strong>r puffert Daten <strong>in</strong> e<strong>in</strong>em 8192 Bytes großen Zwischenspeicher.<br />
Dadurch müssen weniger Zugriffe auf <strong>de</strong>n Datenträger gemacht wer<strong>de</strong>n. Zusätzlich<br />
stellt BufferedRea<strong>de</strong>r die Metho<strong>de</strong> public Str<strong>in</strong>g readL<strong>in</strong>e() zur<br />
Verfügung, die e<strong>in</strong>e komplette Textzeile e<strong>in</strong>liest und als Str<strong>in</strong>g an <strong>de</strong>n Aufrufer<br />
zurückgibt. „null“ wird zurückgegeben, wenn <strong>de</strong>r Stream am En<strong>de</strong> ist.<br />
E<strong>in</strong> L<strong>in</strong>eNumberRea<strong>de</strong>r liest die E<strong>in</strong>gabezeilen und zählt gleichzeitig die Zeilen, die<br />
gelesen wur<strong>de</strong>n. Mit public <strong>in</strong>t getL<strong>in</strong>eNumber() bzw. public void<br />
setL<strong>in</strong>eNumber(<strong>in</strong>t zeilenNummer) läßt sich auf die die Zeilennummern<br />
zugreifen.<br />
Ausgabe mit Dateien<br />
Die Ausgabe <strong>in</strong> Dateien wird unterstützt durch die Klasse FileWriter.<br />
FileWriter ist die e<strong>in</strong>zige Subklasse von OutputStreamWriter. Je<strong>de</strong>r<br />
OutputStreamWriter agiert mir e<strong>in</strong>em CharToByteConverter und konvertiert<br />
so Zeichenströme <strong>in</strong> Byteströme.<br />
import java.io.*;<br />
public class CharArrayWriterDemo<br />
{<br />
133
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g s;<br />
try<br />
{<br />
Pr<strong>in</strong>tWriter pw = new Pr<strong>in</strong>tWriter(new BufferedWriter(<br />
new FileWriter("charArrayWriterDemoPuffer.txt")));<br />
for (<strong>in</strong>t i = 1; i < 1000; i++) pw.pr<strong>in</strong>tln("Zeile " + i);<br />
pw.close();<br />
}<br />
catch (IOException e)<br />
{ System.out.pr<strong>in</strong>tln("Konnte Datei nicht erstellen"); }<br />
}<br />
}<br />
In <strong>Java</strong> gibt es drei Klassen BufferedWriter (mit standardmäßig 8192 Bytes<br />
großen Puffer), Pr<strong>in</strong>tWriter, FilterWriter, die e<strong>in</strong>en Writer im Konstruktor<br />
erlauben und ihre Ausgabe dorth<strong>in</strong> weiterleiten. Zu Beg<strong>in</strong>n <strong>de</strong>s vorliegen<strong>de</strong>n<br />
Programms 133 wird e<strong>in</strong> FileWriter erstellt. Anschließend erzeugt man e<strong>in</strong>en<br />
BufferedWriter, <strong>de</strong>r die Daten, die <strong>in</strong> die Datei geschrieben wer<strong>de</strong>n, sammelt.<br />
Dieser BufferedWriter wird zu e<strong>in</strong>em Pr<strong>in</strong>tWriter erweitert. Da e<strong>in</strong><br />
Pr<strong>in</strong>tWriter Schreibfunktionen besitzt, ist man auf write()-Metho<strong>de</strong>n nicht mehr<br />
angewiesen, son<strong>de</strong>rn kann die komfortablen pr<strong>in</strong>t()-Funktionen nutzen.<br />
Umlenken von Standar<strong>de</strong><strong>in</strong>gabe, Standardausgabe und Standardfehlerausgabe<br />
In <strong>Java</strong> 1.1 ermöglichen die folgen<strong>de</strong>n Metho<strong>de</strong>n das Umlenken:<br />
- setIn(InputStream)<br />
- setOut(Pr<strong>in</strong>tStream)<br />
- setErr(Pr<strong>in</strong>tStream)<br />
Bsp.: Demonstration <strong>de</strong>r Umlenkung von Standar<strong>de</strong><strong>in</strong>gabe und Standardausgabe <strong>in</strong><br />
<strong>Java</strong> 1.1 134<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 "<strong>de</strong>precation"-Nachrichten, System.setOut() und<br />
// System.setErr() erfor<strong>de</strong>rn 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(<br />
new BufferedOutputStream(<br />
new FileOutputStream("test.aus")));<br />
System.setIn(e<strong>in</strong>); System.setOut(aus); System.setErr(aus);<br />
BufferedRea<strong>de</strong>r br =<br />
new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r(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 />
133 vgl. pr14330<br />
134 vgl. pr14150<br />
134
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
catch(IOException a)<br />
{<br />
a.pr<strong>in</strong>tStackTrace();<br />
}<br />
}<br />
}<br />
Random Access Files 135<br />
wer<strong>de</strong>n über die Klasse Random Access File realisiert. Beim Konstruktor<br />
RandomAccessFile(Str<strong>in</strong>g,Zugriffsmodus) wird neben <strong>de</strong>m Date<strong>in</strong>amen<br />
auch die Zugriffsart angegegeben ("r" nur für Lesezugriffe, "rw" zum Lesen und<br />
Schreiben). Mit <strong>de</strong>r Metho<strong>de</strong> seek(long) kann <strong>de</strong>r Dateizeiger (FilePo<strong>in</strong>ter) gesetzt<br />
wer<strong>de</strong>n, getFilePo<strong>in</strong>ter() liefert die aktuelle Position <strong>de</strong>s FilePo<strong>in</strong>ter.<br />
Weiterh<strong>in</strong> stehen zur Verfügung: length(), close(), readL<strong>in</strong>e(), read(), readByte(),<br />
readShort(), readInt(), readLong(), readFloat(), readDouble(), readChar(),<br />
readBoolean() und die analogen write-Metho<strong>de</strong>n.<br />
Bsp.: E<strong>in</strong>- und Ausgabe von und nach Dateien mit wahlfreiem Zugriff 136<br />
1. Erzeugen <strong>de</strong>r Datei rafrw (Datei mit wahlfreiem Zugriff). Auf rafrw wer<strong>de</strong>n ganze Zahlen<br />
geschrieben.<br />
2. Erzeugen <strong>de</strong>r Datei rafr (Datei mit wahlfreiem Zugriff), von <strong>de</strong>r ganze Zahlen gelesen wer<strong>de</strong>n.<br />
import java.io.*;<br />
public class RandomAccessTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
throws java.io.IOException<br />
{<br />
BufferedRea<strong>de</strong>r br = new BufferedRea<strong>de</strong>r<br />
(new InputStreamRea<strong>de</strong>r(System.<strong>in</strong>));<br />
<strong>in</strong>t <strong>in</strong>tLength = 4; // Laenge <strong>de</strong>r Darstellung von ganzen Zahlen<br />
// updat<strong>in</strong>g part<br />
try<br />
{<br />
RandomAccessFile rafrw = new RandomAccessFile("testfile", "rw");<br />
System.out.pr<strong>in</strong>t("\nAen<strong>de</strong>rn e<strong>in</strong>es Datensatzes <strong>de</strong>r Datei\n");<br />
// Datensatznummer erfragen und Dateizeiger setzen und anzeigen<br />
System.out.pr<strong>in</strong>t("Datei geoeffnet. ");<br />
System.out.pr<strong>in</strong>t("Dateizeiger="+rafrw.getFilePo<strong>in</strong>ter()<br />
+" DateiLaenge="+rafrw.length()+" Byte(s)\n");<br />
System.out.pr<strong>in</strong>t("\n? Welchen Datensatz aen<strong>de</strong>rn = ");<br />
long pos = <strong>in</strong>tLength * (new Integer(br.readL<strong>in</strong>e()).<strong>in</strong>tValue());<br />
rafrw.seek(pos);<br />
System.out.pr<strong>in</strong>t( "Dateizeiger="+rafrw.getFilePo<strong>in</strong>ter()+"\n");<br />
// Falls vorhan<strong>de</strong>n, Datensatz anzeigen<br />
if (pos < rafrw.length())<br />
{<br />
// Datensatz anzeigen, Dateizeiger wie<strong>de</strong>rherstellen<br />
System.out.pr<strong>in</strong>t("Datensatz = "+rafrw.readInt()+"\n");<br />
rafrw.seek(pos);<br />
}<br />
else<br />
System.out.pr<strong>in</strong>t("Aha, Datensatz soll angefuegt wer<strong>de</strong>n.\n");<br />
// Neuen Datensatz e<strong>in</strong>lesen<br />
System.out.pr<strong>in</strong>t("\n? Neuer Datensatz = ");<br />
135 vgl. 7.4<br />
136 vgl. pr14444<br />
135
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
<strong>in</strong>t val = new Integer(br.readL<strong>in</strong>e()).<strong>in</strong>tValue();<br />
// Neuen Datensatz <strong>in</strong> die Datei schreiben, Dateizeiger anzeigen<br />
rafrw.writeInt(val);<br />
System.out.pr<strong>in</strong>t( "Nach <strong>de</strong>m Schreiben: Dateizeiger="<br />
+rafrw.getFilePo<strong>in</strong>ter()+"\n");<br />
// test outpout part<br />
RandomAccessFile rafr = new RandomAccessFile("testfile", "r");<br />
System.out.pr<strong>in</strong>t("\nVoila, die geaen<strong>de</strong>rte Datei\n");<br />
// Wie<strong>de</strong>rgabe <strong>de</strong>r Datensaetze aus <strong>de</strong>r Datei<br />
// nach <strong>de</strong>r Veraen<strong>de</strong>rung<br />
<strong>in</strong>t i;<br />
try<br />
{<br />
while (true)<br />
{<br />
i = rafr.readInt();<br />
System.out.pr<strong>in</strong>t(i+" ");<br />
}<br />
} catch (EOFException e) {}<br />
rafrw.close();<br />
rafr.close();<br />
} catch (IOException e)<br />
{<br />
System.err.pr<strong>in</strong>tln("RandomAccessTest: " + e);<br />
}<br />
System.out.pr<strong>in</strong>t("\n");<br />
}<br />
136
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1.4.4.4 Verwalten von Dateien und Verzeichnissen durch die Klasse File<br />
Informationen über e<strong>in</strong>e Datei erhält man über e<strong>in</strong> File-Objekt von class File<br />
java.io.File implements Serializable, Comparable. E<strong>in</strong> File-Objekt<br />
repräsentiert e<strong>in</strong>e Datei o<strong>de</strong>r e<strong>in</strong> Verzeichnis auf <strong>de</strong>m Dateisystem. Der Verweis auf<br />
Datei bzw. Verzeichnis wird durch e<strong>in</strong>en Pfadnamen spezifiziert. Pfadnamen 137<br />
können absolut o<strong>de</strong>r relativ zum aktuellen Verzeichnis angegeben wer<strong>de</strong>n.<br />
Dateieigenschaften und Dateiattribute können über zahlreiche Metho<strong>de</strong>n <strong>de</strong>r Klasse<br />
File 138 gesetzt bzw. wer<strong>de</strong>n.<br />
Bsp.:<br />
import java.io.*;<br />
// import java.nio.charset.*;<br />
public class FileInfo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
File f = new File("./FileInfo.java");<br />
System.out.pr<strong>in</strong>tln("The length of " + f.getName() +<br />
" is " + f.length() + " bytes.");<br />
try {<br />
System.out.pr<strong>in</strong>tln(f.getName() + " is <strong>in</strong> the " +<br />
f.getCanonicalPath() + " directory.");<br />
}<br />
catch (IOException e) { System.out.pr<strong>in</strong>tln("exception");}<br />
}<br />
}<br />
Weitere wichtige Metho<strong>de</strong>n <strong>de</strong>r Klasse File 139 s<strong>in</strong>d: exit(), list(), <strong>de</strong>lete(),<br />
length(), mkdir(), renameTo(File ...), isDirectory(), isFile().<br />
1.4.4.5 Filtern mit <strong>de</strong>n Klasse FilterRea<strong>de</strong>r und FilterWriter<br />
Die abstrakten Filterklassen von java.io erlauben beim Lesen und Schreiben<br />
zusätzliche Operationen auszuführen.<br />
Bsp.: Filtern von Textdateien mit <strong>de</strong>r Extension .java aus <strong>de</strong>m aktuellen Verzeichnis<br />
/*<br />
* Auflisten <strong>de</strong>s Inhalts vom aktuellen Verzeichnis und Filtern<br />
*/<br />
import java.io.*;<br />
class DateiFilter implements FilenameFilter<br />
{<br />
public boolean accept(File f,Str<strong>in</strong>g s)<br />
{<br />
if (s.toLowerCase().endsWith(".java"))<br />
return true;<br />
return false;<br />
}<br />
}<br />
137 Pfadnamen s<strong>in</strong>d plattformabhängig:<br />
Bei W<strong>in</strong>dows-Rechnern trennt e<strong>in</strong> BackSlash die Pfa<strong>de</strong><br />
Bei Unix-Rechnern trennt e<strong>in</strong> Slash die Pfa<strong>de</strong>.<br />
138 vgl. 7.3<br />
139 vgl. 7.3<br />
137
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public class Verzeichnistest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g nameVerz = System.getProperty("user.dir");<br />
File userdir = new File(nameVerz);<br />
// System.out.pr<strong>in</strong>tln(System.getProperty("user.dir"));<br />
Str<strong>in</strong>g e<strong>in</strong>traege [] = userdir.list();<br />
System.out.pr<strong>in</strong>tln("Alle E<strong>in</strong>traege aus <strong>de</strong>m Verzeichnis " + nameVerz);<br />
for (<strong>in</strong>t i = 0;i < e<strong>in</strong>traege.length; i++)<br />
System.out.pr<strong>in</strong>tln(e<strong>in</strong>traege[i]);<br />
System.out.pr<strong>in</strong>tln("Alle E<strong>in</strong>traege aus <strong>de</strong>m Verzeichnis mit Endung .java "<br />
+ nameVerz);<br />
e<strong>in</strong>traege = userdir.list(new DateiFilter());<br />
// Arbeitet wie die Metho<strong>de</strong> list(), nur filtert e<strong>in</strong> spezielles FileName-<br />
// Filter-Objekt bestimmte Namen heraus<br />
for (<strong>in</strong>t i = 0;i < e<strong>in</strong>traege.length; i++)<br />
System.out.pr<strong>in</strong>tln(e<strong>in</strong>traege[i]);<br />
}<br />
}<br />
E<strong>in</strong>gabefilter<br />
Die Klasse FilterRea<strong>de</strong>r erhält <strong>de</strong>n eigentlichen Rea<strong>de</strong>r über <strong>de</strong>n Konstruktor und<br />
speichert ihn als Membervariable.<br />
Bsp. 140 : Die Klasse CaseFilter implementiert e<strong>in</strong>e erweiterte Funktionalität für<br />
read(). Beim E<strong>in</strong>lesen wer<strong>de</strong>n Kle<strong>in</strong>buchstaben <strong>in</strong> Großbuchstaben umgewan<strong>de</strong>lt.<br />
import java.io.*;<br />
public class CaseFilter extends FilterRea<strong>de</strong>r<br />
{<br />
public CaseFilter(Rea<strong>de</strong>r f)<br />
{<br />
super(f);<br />
}<br />
public <strong>in</strong>t read() throws IOException<br />
{<br />
<strong>in</strong>t zeichen = super.read();<br />
if (Character.isLowerCase((char) zeichen))<br />
return Character.toUpperCase((char) zeichen);<br />
else return zeichen;<br />
}<br />
}<br />
In <strong>de</strong>r Klasse DekoStream wird nun das read() e<strong>in</strong>es CaseFilter-Objekts<br />
verwen<strong>de</strong>t. Direkt beim E<strong>in</strong>lesen wird <strong>de</strong>r Text formatiert.<br />
import java.io.*;<br />
public class DekoStream<br />
{<br />
public DekoStream()<br />
{<br />
Str<strong>in</strong>g s = readNormal("DekoStream.java");<br />
System.out.pr<strong>in</strong>tln(s);<br />
s = readFilter("DekoStream.java");<br />
System.out.pr<strong>in</strong>tln(s);<br />
}<br />
140 vgl. pr14341<br />
138
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
private Str<strong>in</strong>g readNormal(Str<strong>in</strong>g fl)<br />
{<br />
Str<strong>in</strong>gBuffer s = new Str<strong>in</strong>gBuffer();<br />
try {<br />
FileRea<strong>de</strong>r fread = new FileRea<strong>de</strong>r(fl);<br />
<strong>in</strong>t zeichen;<br />
while ((zeichen = fread.read()) != -1)<br />
s.append((char) zeichen);<br />
fread.close();<br />
}<br />
catch(IOException e) { System.err.pr<strong>in</strong>tln(e); }<br />
return s.toStr<strong>in</strong>g();<br />
}<br />
private Str<strong>in</strong>g readFilter(Str<strong>in</strong>g fl)<br />
{<br />
Str<strong>in</strong>gBuffer s = new Str<strong>in</strong>gBuffer();<br />
try {<br />
FileRea<strong>de</strong>r fread = new FileRea<strong>de</strong>r(fl);<br />
CaseFilter ff = new CaseFilter(fread);<br />
/* Die CaseFilter-Klasse implementiert e<strong>in</strong>e erweiterte<br />
Funktionalitaet fuer read(). Beim E<strong>in</strong>lesen wer<strong>de</strong>n<br />
Kle<strong>in</strong>buchstaben <strong>in</strong> Grossbuchstaben umgewan<strong>de</strong>lt */<br />
<strong>in</strong>t zeichen;<br />
while ((zeichen = ff.read()) != -1)<br />
s.append((char) zeichen);<br />
ff.close();<br />
}<br />
catch(IOException e) { System.err.pr<strong>in</strong>tln(e); }<br />
return s.toStr<strong>in</strong>g();<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
new DekoStream();<br />
}<br />
}<br />
Ab JDK 1.1 gibt es e<strong>in</strong>en vor<strong>de</strong>f<strong>in</strong>ierten E<strong>in</strong>gabefilter PushBackRea<strong>de</strong>r, <strong>de</strong>r aus<br />
FilterRea<strong>de</strong>r abgeleitet ist. E<strong>in</strong> PushBackRea<strong>de</strong>r erweitert die Klasse<br />
FilterRea<strong>de</strong>r um e<strong>in</strong>en e<strong>in</strong> Byte großen PushBack-Puffer. Dieser erlaubt e<strong>in</strong>er<br />
Anwendung, das zuletzt gelesenen Zeichen wie<strong>de</strong>r <strong>in</strong> <strong>de</strong>n E<strong>in</strong>gabestrom zurück zu<br />
schieben. Der nächste Lesezugriff liest dann nicht das folgen<strong>de</strong> Zeichen im<br />
E<strong>in</strong>gabestrom, son<strong>de</strong>rn das gera<strong>de</strong> zurückgelesene Zeichen.<br />
Ausgabefilter<br />
Die Architektur <strong>de</strong>r Writer-Klassen macht es möglich eigene Filter zu konstruieren.<br />
Das kann bspw. durch Überlagern <strong>de</strong>r Klasse Writer 141 geschehen. Der offizielle<br />
Weg besteht allerd<strong>in</strong>gs <strong>in</strong> <strong>de</strong>r Überlagerung <strong>de</strong>r abstrakten Klasse FilterWriter.<br />
FilterWriter besitzt e<strong>in</strong> <strong>in</strong>ternes Writer-Objekt out, das bei <strong>de</strong>r Initialisierung an<br />
<strong>de</strong>n Konstruktor übergeben wird. Zusätzlich überlagert es drei <strong>de</strong>r vier write-<br />
Metho<strong>de</strong>n, um die Ausgabe auf out umzuleiten.<br />
Damit e<strong>in</strong> eigener FilterWriter erzeugt wer<strong>de</strong>n kann, muß beachtet wer<strong>de</strong>n:<br />
- die eigene Klasse leitet sich von FilterWriter ab<br />
- <strong>de</strong>r Konstruktor bekommt als Parameter e<strong>in</strong> Writer-Objekt und ruft mit super(out) <strong>de</strong>n Konstruktor<br />
<strong>de</strong>r Superklasse auf. Das ist die Klasse FilterWriter.<br />
141 wie es bspw. bei Pr<strong>in</strong>tWriter und BufferedWriter realisier wur<strong>de</strong>.<br />
139
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- Überlagern <strong>de</strong>r drei write() Metho<strong>de</strong>n, Ausführung <strong>de</strong>r Filterfunktionen, Weitergabe <strong>de</strong>r wahren<br />
Daten an <strong>de</strong>n Writer<br />
Bsp. 142 : Konvertieren aller Zeichen <strong>in</strong> Großbuchstaben <strong>in</strong>nerhalb e<strong>in</strong>es Streams.<br />
import java.io.*;<br />
class UpCaseWriter extends FilterWriter<br />
{<br />
public UpCaseWriter(Writer out)<br />
{<br />
super(out);<br />
}<br />
public void write(<strong>in</strong>t c) throws IOException<br />
{<br />
super.write(Character.toUpperCase((char) c));<br />
}<br />
public void write(char cbuff[], <strong>in</strong>t off, <strong>in</strong>t len)<br />
throws IOException<br />
{<br />
for (<strong>in</strong>t i = 0; i < len; i++)<br />
write(cbuff[off + i]);<br />
}<br />
public void write(Str<strong>in</strong>g str, <strong>in</strong>t off, <strong>in</strong>t len)<br />
throws IOException<br />
{<br />
write(str.toCharArray(),off,len);<br />
}<br />
}<br />
Test:<br />
import java.io.*;<br />
public class PR14441<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Pr<strong>in</strong>tWriter f;<br />
Str<strong>in</strong>g s = " und diese Zeichenkette auch";<br />
try {<br />
f = new Pr<strong>in</strong>tWriter(<br />
new UpCaseWriter(new FileWriter("upcase.txt")));<br />
f.pr<strong>in</strong>tln("Diese Zeile wird gross geschrieben");<br />
/* Die drei write() Metho<strong>de</strong>n wer<strong>de</strong>n <strong>in</strong> UpCaseWriter<br />
do überlagert, dass zunächst Ausgabezeichen <strong>in</strong><br />
Grossschrift konvertiert und anschliessend die<br />
passen<strong>de</strong> Superklassen-Metho<strong>de</strong> aufgerufen wird, um<br />
die Datei an <strong>de</strong>n <strong>in</strong>ternen Writer out zu uebergeben<br />
*/<br />
// Test write(<strong>in</strong>t);<br />
f.pr<strong>in</strong>tln();<br />
// Test write(Str<strong>in</strong>g)<br />
f.write(s); f.pr<strong>in</strong>tln();<br />
// Test von write(Str<strong>in</strong>g,<strong>in</strong>t,<strong>in</strong>t)<br />
f.write(s,0,23); f.pr<strong>in</strong>tln();<br />
// Test von write(char[],<strong>in</strong>t,<strong>in</strong>t)<br />
f.write(s.toCharArray(),0,10);<br />
f.pr<strong>in</strong>tln();<br />
f.close();<br />
}<br />
catch(IOException e)<br />
{<br />
System.out.pr<strong>in</strong>tln("Fehler beim Erstellen <strong>de</strong>r Datei");<br />
}<br />
142 vgl. pr14341<br />
140
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
1.4.4.6 Der Dateiauswahl-Dialog<br />
E<strong>in</strong>e spezielle Klasse FileDialog (class java.awt.FileDialog extends<br />
Dialog) zeigt e<strong>in</strong>en vom Betriebssystem unabhängigen Dateiauswahl-Dialog. Er<br />
kann für das Speichern und Öffnen konfiguriert se<strong>in</strong>. Er lassen sich die Pfa<strong>de</strong> und e<strong>in</strong><br />
FilenameFilter setzen. Erst nach <strong>de</strong>m Schließen und Been<strong>de</strong>n mit <strong>de</strong>m OK-<br />
Button stehen ausgewählte Dateien zur Verfügung:<br />
Bsp.:<br />
import java.awt.*;<br />
public class DateiAuswahl extends Frame<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
Frame f = new Frame();<br />
// e<strong>in</strong> Objekt von Frame wird <strong>de</strong>m FileDialog mit auf <strong>de</strong>n<br />
// Weg gegeben<br />
FileDialog d = new FileDialog(f,"oeffne was",FileDialog.LOAD);<br />
d.setFile("*.java");<br />
d.show();<br />
Str<strong>in</strong>g datei = d.getDirectory() + d.getFile();<br />
System.out.pr<strong>in</strong>tln(datei);<br />
}<br />
}<br />
141
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2. Hauptbestandteile <strong>de</strong>r Sprache<br />
2.1 Token<br />
Token be<strong>de</strong>uten <strong>in</strong> <strong>Java</strong> dasselbe wie Worte und Zeichensetzung für die<br />
menschliche Sprache. Wenn <strong>Java</strong> <strong>de</strong>n Quellco<strong>de</strong> mit <strong>de</strong>m <strong>Java</strong>-Compiler (javac)<br />
kompiliert, f<strong>in</strong><strong>de</strong>t e<strong>in</strong>e Zerlegung <strong>de</strong>s Quellco<strong>de</strong>s <strong>in</strong> kle<strong>in</strong>e Bestandteile, Symbole<br />
o<strong>de</strong>r 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 <strong>de</strong>r sog. Parser <strong>de</strong>s javac, <strong>de</strong>r Quelltext <strong>in</strong><br />
Byteco<strong>de</strong> übersetzt und zusätzlich noch Leerzeichen und Kommentare (aus <strong>de</strong>m<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 o<strong>de</strong>r I<strong>de</strong>ntifizierer, Schlüsselwörter, Literale,<br />
Operatoren, Trennzeichen.<br />
Token Beschreibung Bsp.<br />
Schlüsselworte Alle Wörter, die e<strong>in</strong> wesentlicher Teil <strong>de</strong>r Public, class, static, void, Str<strong>in</strong>g,<br />
<strong>Java</strong>-Sprach<strong>de</strong>f<strong>in</strong>ition s<strong>in</strong>d<br />
else, if, this, etc.<br />
Bezeichner, I<strong>de</strong>ntifiziere Namen für Klassen,Objekte, Variablen,<br />
Konstanten, Metho<strong>de</strong>n, etc.; Namen s<strong>in</strong>d<br />
zusammengesetzt aus Unico<strong>de</strong>-Zeichen.<br />
An erster Stelle e<strong>in</strong>es Bezeichners darf<br />
ke<strong>in</strong>e Zahl stehen.<br />
Literal<br />
Mit e<strong>in</strong>em Literal können Variablen und “Hallo <strong>Java</strong>“, 13, false, true<br />
Konstanten bestimmte Werte<br />
zugewiesen wer<strong>de</strong>n. Die können<br />
sämtliche <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Sprach<strong>de</strong>f<strong>in</strong>ition<br />
erlaubte Arten von Werten (numerische<br />
Werte, boolesche Werte, Zeichen,<br />
Zeichenketten) se<strong>in</strong><br />
Trennzeichen<br />
Symbol zum Anzeigen für Trennungen ( ) { } [ ] ; . ,<br />
und Zusammenfassungen von Co<strong>de</strong><br />
Operatoren<br />
Zeichen bzw. Zeichenkomb<strong>in</strong>ationen zur + - * / , >>>
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bei <strong>de</strong>r Kompilierung wird <strong>de</strong>r Quellco<strong>de</strong> automatisch <strong>in</strong> e<strong>in</strong>e Folge von Unico<strong>de</strong>-<br />
Zeichen transformiert. E<strong>in</strong>e ASCII-Kodierung wird e<strong>in</strong>fach mit Voranstellen <strong>de</strong>r<br />
Zeichenfolge „\u00“ und folgen<strong>de</strong>r Hexa<strong>de</strong>zimalzahl <strong>in</strong> das passen<strong>de</strong> Unico<strong>de</strong>-<br />
Zeichen übersetzt. Dies <strong>de</strong>f<strong>in</strong>iert <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e Escape-Sequenz, mit <strong>de</strong>r alle Unico<strong>de</strong>-<br />
Zeichen verschlüsselt wer<strong>de</strong>n können. Durch die „Escape-Sequenz-Darstellung“ <strong>de</strong>s<br />
Quelltextes <strong>in</strong> <strong>Java</strong> ist die Verwendung von Umlauten und an<strong>de</strong>ren Son<strong>de</strong>rzeichen <strong>in</strong><br />
Bezeichnern möglich.<br />
Zwei Bezeichner gelten <strong>in</strong> <strong>Java</strong> als i<strong>de</strong>ntisch, wenn ihre Unico<strong>de</strong>-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 unterschie<strong>de</strong>n wer<strong>de</strong>n.<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 beson<strong>de</strong>re Be<strong>de</strong>utung<br />
haben. Diese Buchstabenfolgen wer<strong>de</strong>n <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 <strong>de</strong>fault<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 />
2.1.2 Bezeichner und Namenskonventionen<br />
Bezeichner bzw. I<strong>de</strong>ntifizierer (i<strong>de</strong>ntifier) s<strong>in</strong>d Worte, die vom Programmierer<br />
gewählt, zu Token wer<strong>de</strong>n und die Variablen, Konstanten, Klassen, Objekte,<br />
Beschriftungen und Metho<strong>de</strong>n darstellen. Bezeichner dürfen nicht mit <strong>Java</strong>-<br />
Schlüsselworten i<strong>de</strong>ntisch 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 wer<strong>de</strong>n<br />
müssen:<br />
- Bezeichner bestehen aus Unico<strong>de</strong>-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, <strong>de</strong>r Unterstrich „_“ o<strong>de</strong>r das Zeichen „$“ se<strong>in</strong>.<br />
Alle folgen<strong>de</strong>n Zeichen s<strong>in</strong>d entwe<strong>de</strong>r Buchstaben o<strong>de</strong>r Zahlen.<br />
- Zwei Token gelten nur dann als <strong>de</strong>rselbe Bezeichner, wenn sie dieselbe Länge haben, und je<strong>de</strong>s Zeichen im<br />
ersten Token genau mit <strong>de</strong>m korrespondieren<strong>de</strong>n Zeichen <strong>de</strong>s zweiten Token übere<strong>in</strong>stimmt, d.h. <strong>de</strong>n<br />
vollkommen i<strong>de</strong>ntischen Unico<strong>de</strong>-Wert hat. <strong>Java</strong> unterschei<strong>de</strong>t 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 „sprechen<strong>de</strong>“ 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) verwen<strong>de</strong>t wird.<br />
- Konstanten (Elemente mit <strong>de</strong>m „Modifizierer“ „f<strong>in</strong>al“) sollten vollständig groß geschrieben wer<strong>de</strong>n.<br />
144
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- I<strong>de</strong>ntifizierer 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 />
wer<strong>de</strong>n. Wenn sich e<strong>in</strong> Bezeichner aus mehreren Wörtern zusammensetzt, dürfen diese nicht getrennt<br />
wer<strong>de</strong>n. Die jeweiligen Anfangsbuchstaben <strong>in</strong>nerhalb <strong>de</strong>s gesamten Bezeichners wer<strong>de</strong>n jedoch groß<br />
geschrieben.<br />
- Die I<strong>de</strong>ntifizierer von Variablen, Metho<strong>de</strong>n und Elementen beg<strong>in</strong>nen mit Kle<strong>in</strong>buchstaben und wer<strong>de</strong>n 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 wer<strong>de</strong>n. Die jeweiligen Anfangsbuchstaben <strong>de</strong>r folgen<strong>de</strong>n Wörter können jedoch<br />
<strong>in</strong>nerhalb <strong>de</strong>s Gesamtbezeichners groß geschrieben wer<strong>de</strong>n.<br />
2.1.3 Literale<br />
Literale s<strong>in</strong>d Token, die für zu speichern<strong>de</strong> Werte <strong>de</strong>r Datentypen byte, short, <strong>in</strong>t,<br />
long, float, double, boolean und char stehen. Literale wer<strong>de</strong>n auch zur<br />
Darstellung von Werten benutzt, die <strong>in</strong> Zeichenketten gespeichert wer<strong>de</strong>n.<br />
Es gibt: Boolesche Literale, Zeichenliterale, Zeichenkettenliterale, Gleitpunktliterale,<br />
ganzzahlige Literale.<br />
2.1.3.1 Ganzzahlige Literale<br />
Die Datentypen „<strong>in</strong>t“ und „long“ können <strong>de</strong>zimal, hexa<strong>de</strong>zimal und oktal<br />
beschrieben wer<strong>de</strong>n. Die Vore<strong>in</strong>stellung ist <strong>de</strong>zimal und gilt immer dann, wenn Werte<br />
ohne weitere Än<strong>de</strong>rung dargestellt wer<strong>de</strong>n. Hexa<strong>de</strong>zimale Darstellung beg<strong>in</strong>nt immer<br />
mit <strong>de</strong>r Sequenz 0x o<strong>de</strong>r 0X 145 . Oktale Darstellungen beg<strong>in</strong>nen mit e<strong>in</strong>er führen<strong>de</strong>n<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 <strong>de</strong>n Typ „<strong>in</strong>t“. Durch Anhängen vom „l“ bzw.<br />
„L“ kann man jedoch explizit <strong>de</strong>n Typ „long“ wählen.<br />
2.1.3.2 Gleitpunktliterale<br />
Gleitpunktliterale bestehen aus mehreren Teilen. Sie ersche<strong>in</strong>en <strong>in</strong> folgen<strong>de</strong>r<br />
Reihenfolge:<br />
Teil Nötig? Beispiele<br />
Ganzzahliger Teil Nicht, wenn <strong>de</strong>r gebrochene Teil 0, 1, 2, ... , 9, 131140<br />
vorhan<strong>de</strong>n ist<br />
Dezimalpunkt<br />
Nicht, wenn e<strong>in</strong> Exponent vorhan<strong>de</strong>n<br />
ist. Muß vorliegen, wenn es e<strong>in</strong>en<br />
Dezimalpunkt gibt<br />
Gebrochener Teil Darf nicht vorhan<strong>de</strong>n se<strong>in</strong>, wenn es 0, 1, 1311, 41421, 9944, 718281828<br />
ke<strong>in</strong>en Dezimalpunkt gibt. Muß<br />
vorhan<strong>de</strong>n se<strong>in</strong>, wenn es ke<strong>in</strong>en<br />
ganzzahligen Teil gibt<br />
Exponent Nur, wenn es ke<strong>in</strong>en Dezimalpunkt gibt E23, E-19, E6, e+307<br />
Typensuffix<br />
Ne<strong>in</strong>. Bei Abwesenheit e<strong>in</strong>es<br />
Typensuffix wird angenommen, daß es<br />
f, F, d, D<br />
145 Die Zahlen 0 bis 15 wer<strong>de</strong>n durch die Buchstaben „A“ bis „F“ bzw. „a“ bis „f“ dargestellt (Groß- o<strong>de</strong>r<br />
Kle<strong>in</strong>schreibung ist hier nicht relevant.<br />
145
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
sich um e<strong>in</strong>e Zahl doppelter<br />
Genauigkeit han<strong>de</strong>lt.<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;<br />
// max. hex. Wert fuer byte<br />
short s = 0x7fff; // max. hex. Wert fuer short<br />
<strong>in</strong>t i1 = 0x2f;<br />
// hexa<strong>de</strong>zimal <strong>in</strong> Kle<strong>in</strong>buchstaben<br />
<strong>in</strong>t i2 = 0X2F;<br />
// hexa<strong>de</strong>zimal <strong>in</strong> Grossbuchstaben<br />
// hexa<strong>de</strong>imale und oktale Werte mit long<br />
long n1 = 200L;<br />
// "long"-Suffix<br />
long n2 = 200l;<br />
// "long"-suffix<br />
long n3 = 200;<br />
// float- und double-Literale<br />
float f1 = 1;<br />
float f2 = 1F;<br />
// "float"-Suffix<br />
float f3 = 1f;<br />
// "float"-Suffix<br />
float f4 = 1e-45f; // wissenschaftl. Schreibweise<br />
float f5 = 1e+9f; // "float"-Suffix<br />
double d1 = 1d;<br />
// "double"-Suffix<br />
double d2 = 1D;<br />
// "double"-Suffix;<br />
double d3 = 47e47d; // wissenschaftl. Schreibweise<br />
}<br />
2.1.3.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 />
2.1.3.4 Zeichenliterale<br />
Sie wer<strong>de</strong>n <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 <strong>de</strong>s B<strong>in</strong><strong>de</strong>strichs „-“ und <strong>de</strong>s<br />
Backslash „\“. Bei Escape-Zeichenliteralen folgen <strong>de</strong>n Anführungszeichen <strong>de</strong>r<br />
Backslash und <strong>de</strong>m Backslash e<strong>in</strong>e <strong>de</strong>r folgen<strong>de</strong>n Zeichen:<br />
- b, t, n, f, r,
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Escape-Literal Unico<strong>de</strong>-Steuersequenz Oktal-Sequenz Be<strong>de</strong>utung<br />
‘\b‘ \u0008 \010 Backspace<br />
‘\t‘ \u0009 \011 Tab<br />
‘\n‘ \u000a \012 Neue Zeile<br />
‘\f‘ \u000c \014 Formularvorschub<br />
‘\r‘ \u000d \015 Return<br />
‘\“ \u0022 \042 Doppeltes Anführungszeichen<br />
‘\‘ \u0027 \047 E<strong>in</strong>faches Anführungszeichen<br />
‘\\‘ \u005c \134 Backslash<br />
Abb.: Escape-Literale<br />
2.1.3.5 Zeichenkettenliterale<br />
Zeichenkettenliterale s<strong>in</strong>d aus mehreren Zeichenliteralen zusammengesetzte Ketten<br />
(Str<strong>in</strong>gs). Bei Zeichenkettenliteralen wer<strong>de</strong>n null o<strong>de</strong>r mehr Zeichen <strong>in</strong> Anführungszeichen<br />
(“)dargestellt. <strong>Java</strong> erzeugt Zeichenketten als Instanz <strong>de</strong>r Klasse Str<strong>in</strong>g.<br />
Damit stehen alle Metho<strong>de</strong>n <strong>de</strong>r Klasse Str<strong>in</strong>g zur Manipulation e<strong>in</strong>er Zeichenkette<br />
zur Verfügung.<br />
Zeichenkettenliterale stehen zwischen zwei Anführungszeichen (“) und können<br />
Steuerzeichen wie Tabulatoren, Zeilenvorschübe, nichtdruckbare Unico<strong>de</strong>-Zeichen<br />
und druckbare Unico<strong>de</strong>-Spezialzeichen enthalten. Es kann sich auch um Escape-<br />
Sequenzen han<strong>de</strong>ln. Bei<strong>de</strong> Anführungszeichen müssen <strong>in</strong> <strong>de</strong>rselben Zeile <strong>de</strong>s<br />
Quellco<strong>de</strong>s stehen.<br />
Je<strong>de</strong>s Str<strong>in</strong>g-Literal ist e<strong>in</strong>e Referenz auf e<strong>in</strong> Objekt <strong>de</strong>r Klasse Str<strong>in</strong>g. Falls <strong>de</strong>r<br />
Compiler beim Übergeben <strong>de</strong>s Quelltextes e<strong>in</strong> str<strong>in</strong>g-Literal f<strong>in</strong><strong>de</strong>t, erzeut er e<strong>in</strong><br />
neues Str<strong>in</strong>g-Objekt und verwen<strong>de</strong>t es anstelle <strong>de</strong>s Literals.<br />
In <strong>Java</strong> ist <strong>de</strong>r Operator + auch auf Str<strong>in</strong>gs <strong>de</strong>f<strong>in</strong>iert. Auf zwei Str<strong>in</strong>g-Objekte angewen<strong>de</strong>t,<br />
liefert er die Verkettung bei<strong>de</strong>r Objekte.<br />
2.1.4 Trennzeichen<br />
Trennnzeichen s<strong>in</strong>d Token, die aus e<strong>in</strong>em e<strong>in</strong>zigen Zeichen bestehen und an<strong>de</strong>re<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 Metho<strong>de</strong> 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 Metho<strong>de</strong> als auch zur Festlegung<br />
e<strong>in</strong>es 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 o<strong>de</strong>r e<strong>in</strong>er Initialisierungsliste gesetzt<br />
} Wird an das En<strong>de</strong> e<strong>in</strong>es Blocks mit Anweisungen o<strong>de</strong>r e<strong>in</strong>er Initialisierungsliste gesetzt<br />
[ Steht vor e<strong>in</strong>em Ausdruck, <strong>de</strong>r als In<strong>de</strong>x für e<strong>in</strong> Datenfeld (Array) steht<br />
] Folgt e<strong>in</strong>em Ausdruck, <strong>de</strong>r als In<strong>de</strong>x für e<strong>in</strong> Datenfeld dient<br />
; Dient sowohl zum Been<strong>de</strong>n e<strong>in</strong>er Ausdrucksanweisung als auch zum Trennen <strong>de</strong>r Teile e<strong>in</strong>er for-<br />
Anweisung.<br />
, wird <strong>in</strong> vielen Zusammenhängen als Begrenzer verwen<strong>de</strong>t<br />
. Wird sowohl als Dezimalpunkt als auch zum Trennen solcher D<strong>in</strong>ge wie Paketnamen von<br />
Klassennamen o<strong>de</strong>r Variablennamen benutzt.<br />
Abb.: Die <strong>Java</strong>-Trennzeichen<br />
147
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.1.5 Operatoren<br />
Operatoren geben an, welche Operation mit e<strong>in</strong>em o<strong>de</strong>r mehreren gegebenen<br />
Operan<strong>de</strong>n durchgeführt wer<strong>de</strong>n soll. Es gibt <strong>in</strong> <strong>Java</strong> 37 Zeichensequenzen, die<br />
Token darstellen, welche als Operatoren benutzt wer<strong>de</strong>n.<br />
2.1.5.1 Arithmetische Operatoren<br />
Arithmetische Operatoren benutzen nur zwei Operan<strong>de</strong>n. Diese s<strong>in</strong>d entwe<strong>de</strong>r<br />
ganzzahlige Werte o<strong>de</strong>r Gleitpunktzahlen. Als Rückgabe e<strong>in</strong>er arithmetischen<br />
Operation erhält man e<strong>in</strong>en neuen Wert, <strong>de</strong>ssen Datentyp sich folgen<strong>de</strong>rmaßen<br />
ergibt:<br />
- Zwei ganzzahlige Datentypen (byte, short, <strong>in</strong>t o<strong>de</strong>r long) als Operan<strong>de</strong>n ergeben immer e<strong>in</strong>en<br />
ganzzahligen Datentyp als Ergebnis. Dabei kann als Datentyp <strong>in</strong>t o<strong>de</strong>r 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 <strong>de</strong>r bei<strong>de</strong>n Operan<strong>de</strong>n<br />
bereits vom Datentyp long war o<strong>de</strong>r das Ergebnis von <strong>de</strong>r Größe her nur als long dargestellt<br />
wer<strong>de</strong>n kann.<br />
- Zwei Gleitpunktzahlentypen als Operan<strong>de</strong>n ergeben immer e<strong>in</strong>en Gleitpunktzahlentyp als Ergebnis.<br />
Die Anzahl <strong>de</strong>r Stellen <strong>de</strong>s Ergebnisses ist immer das Maximum <strong>de</strong>r Stellenanzahl <strong>de</strong>r bei<strong>de</strong>n<br />
Operan<strong>de</strong>n.<br />
- Falls die Operan<strong>de</strong>n e<strong>in</strong> ganzzahliger Typ und e<strong>in</strong>e Gleitpunktzahlentyp s<strong>in</strong>d, dann ist das Ergebnis<br />
immer e<strong>in</strong> Gleitpunktzahlentyp.<br />
Operator Be<strong>de</strong>utung 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 />
2.1.5.1.1 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 Operan<strong>de</strong>n) arithmetische Operatoren <strong>in</strong><br />
<strong>Java</strong>:<br />
- E<strong>in</strong>stellige arithmetische Negierung: -<br />
- Das Gegenteil <strong>de</strong>r arithmetischen Negierung: +<br />
2.1.5.1.2 Arithmetische Zuweisungsoperatoren<br />
Neben <strong>de</strong>m 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 <strong>de</strong>r l<strong>in</strong>ken<br />
Seite.<br />
Operator Be<strong>de</strong>utung<br />
+= Additions- und Zuweisungsoperator<br />
-= Subtraktions- und Zuweisungsoperator<br />
*= Multiplikations- und Zuweisungsoperator<br />
148
<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 />
2.1.5.2 Inkrement- / Dekrement-Operatoren<br />
Inkrement- und Dekrement-Operatoren s<strong>in</strong>d e<strong>in</strong>stellige Operatoren und wer<strong>de</strong>n nur <strong>in</strong><br />
Verb<strong>in</strong>dung mit e<strong>in</strong>em ganzzahligen Wert o<strong>de</strong>r e<strong>in</strong>er Gleitpunktzahl benutzt.<br />
Der Inkrement-Operator (++) erhöht <strong>de</strong>n Wert <strong>de</strong>s Operan<strong>de</strong>n um 1. Steht <strong>de</strong>r<br />
Operator vor <strong>de</strong>m Operan<strong>de</strong>n, erfolgt die Erhöhung <strong>de</strong>s Werts, bevor <strong>de</strong>r Wert <strong>de</strong>m<br />
Operan<strong>de</strong>n zugewiesen wird. Wenn er h<strong>in</strong>ter <strong>de</strong>m Operan<strong>de</strong>n steht, erfolgt die<br />
Erhöhung, nach<strong>de</strong>m <strong>de</strong>r Wert bereits zugewiesen wur<strong>de</strong>.<br />
Der Dekrement-Operator (--) erniedrigt <strong>de</strong>n Wert <strong>de</strong>s Operan<strong>de</strong>n um 1. Steht <strong>de</strong>r<br />
Operator vor <strong>de</strong>m Operan<strong>de</strong>n, erfolgt die Erniedrigung <strong>de</strong>s Werts, bevor <strong>de</strong>r Wert<br />
<strong>de</strong>m Operan<strong>de</strong>n zugewiesen wird. Wenn er h<strong>in</strong>ter <strong>de</strong>m Operan<strong>de</strong>n steht, erfolgt die<br />
Erniedrigung, nach<strong>de</strong>m <strong>de</strong>r Wert bereits zugewiesen wur<strong>de</strong>.<br />
2.1.5.3 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 />
&<br />
Bitweiser AND-Operator<br />
| Bitweiser OR-Operator<br />
^<br />
Bitweiser XOR-Operator<br />
~ Bitweiser Komplement-Operator<br />
Abb.: Bitoperatoren <strong>in</strong> <strong>Java</strong><br />
2.1.5.4 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 147<br />
import java.util.*;<br />
public class BitManipulation<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
147 pr21502<br />
149
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<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 <strong>de</strong>n 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 />
2.1.5.5 Bitweise Zuweisungsoperatoren<br />
Bitweise Zuweisungsoperatoren verwen<strong>de</strong>n e<strong>in</strong>en Wert, führen e<strong>in</strong>e entsprechen<strong>de</strong><br />
bitweise Operation mit <strong>de</strong>m zweiten Operan<strong>de</strong>n durch und legen das Ergebnis als<br />
Inhalt <strong>de</strong>s ersten Operan<strong>de</strong>n ab.<br />
Operator Beschreibung<br />
&=<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 />
151
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.1.5.6 Vergleichsoperatoren<br />
Vergleichsoperatoren haben zwei Operan<strong>de</strong>n und vergleichen diese (zwei<br />
Ganzzahlen o<strong>de</strong>r zwei Gleitpunktzahlen) 1 . Als Rückgabewert <strong>de</strong>r Operation entsteht<br />
e<strong>in</strong> boolescher Wert (true o<strong>de</strong>r false).<br />
Operator Be<strong>de</strong>utung<br />
== Gleichheitsoperator<br />
!= Ungleichheitsoperator<br />
< Kle<strong>in</strong>er-als-Operator<br />
> Größer-als-Operator<br />
= Größer-als-o<strong>de</strong>r-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> „verwirren<strong>de</strong>s Ergebnis“, z.B. 149 :<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 <strong>de</strong>r Objekte ist zwar gleich, die Referenzen auf die Objekte s<strong>in</strong>d nicht<br />
gleich. Falls <strong>de</strong>r aktuelle Infalt auf Gleichheit überprüft wer<strong>de</strong>n soll, steht die Metho<strong>de</strong><br />
equals() 150 bereit, z.B.:<br />
public class EqualsMetho<strong>de</strong><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));<br />
}<br />
}<br />
// true<br />
2.1.5.7 Logische Vergleichsoperatoren<br />
Die logischen Vergleichsoperatoren wer<strong>de</strong>n nur auf boolesche Operatoren<br />
angewandt und erzeugen nur boolesche Ergebnisse.<br />
Operator Beschreibung<br />
&&<br />
Logischer AND-Operator<br />
|| Logischer OR-Operator<br />
148 Die Werte zweier Variablen vom Typ char können ebenfalls mit <strong>de</strong>n Vergleichsoperatoren verglichen<br />
wer<strong>de</strong>n. Es wer<strong>de</strong>n die Variablen vom Typ char bei <strong>de</strong>r Verwendung e<strong>in</strong>es Vergleichsoperators wie ganze 16-<br />
Bit-Zahlen entsprechend ihrer Unico<strong>de</strong>-Codierung behan<strong>de</strong>lt.<br />
149 Vgl. pr21500<br />
150 Viele <strong>in</strong> <strong>de</strong>r <strong>Java</strong>-Bibliorhek bereitgestellte Klassen implementieren die Metho<strong>de</strong> equals()<br />
152
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 en<strong>de</strong>n mit <strong>de</strong>m En<strong>de</strong> <strong>de</strong>r Zeile<br />
- Mehrzeilige Kommentare (Blockkommentare) beg<strong>in</strong>nen mit /* und en<strong>de</strong>n mit */. Sie können sich über<br />
mehrere Zeilen erstrecken.. Blockkommentare dürfen nicht geschachtelt se<strong>in</strong>.<br />
- Dokumentationskommentare beg<strong>in</strong>nen mit /** und en<strong>de</strong>n 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 />
wer<strong>de</strong>n. <strong>Java</strong>doc dient zum Erzeugen von API-Dokumentationen aus an<strong>de</strong>rem <strong>Java</strong>-Quellco<strong>de</strong>.<br />
Das JDK verfügt über das Dokumentations-Tool javadoc, das auf <strong>de</strong>r Basis von<br />
speziellen Kommando-Tags <strong>in</strong>nerhalb e<strong>in</strong>er <strong>Java</strong>-Quelltextdatei e<strong>in</strong>e HTML-Datei als<br />
API-Dokumentation <strong>de</strong>r angegebenen Datei 151 o<strong>de</strong>r <strong>de</strong>s Pakets erzeugt.<br />
Tag<br />
@see [Klassenname]<br />
@see<br />
[Klassenname]#[Metho<strong>de</strong>nname]<br />
@param [Parametername]<br />
[Beschreibung]<br />
@version [Text]<br />
@author [Name]<br />
@return [Beschreibung]<br />
@exception [Klassenname]<br />
@<strong>de</strong>precated [Ausdruck]<br />
@s<strong>in</strong>ce [Text]<br />
Beschreibung<br />
Dieses tag erzeugt e<strong>in</strong>en Verweis <strong>in</strong> <strong>de</strong>r HTML-Datei zu <strong>de</strong>r<br />
Klasse, die von Klassenname spezifiziert wird. Dabei kann <strong>de</strong>r<br />
Klassenname auch e<strong>in</strong>e vollständige Pfadangabe se<strong>in</strong><br />
Dieses Tag erzeugt e<strong>in</strong>en Verweis („See also“-L<strong>in</strong>k) <strong>in</strong> <strong>de</strong>r HTML-<br />
Datei zu <strong>de</strong>r Metho<strong>de</strong> (<strong>in</strong>nerhalb <strong>de</strong>r mit Klassenname<br />
spezifizierten Klasse), die von Metho<strong>de</strong>nname spezifiziert wird<br />
Dieses Tag dient zur Dokumentation <strong>de</strong>r Parameter.<br />
Parametername ist selbsterklärend, und die Beschreibung<br />
spezifizeirt <strong>de</strong>n Parameter. Geht die Beschreibung über e<strong>in</strong>e Zeile<br />
h<strong>in</strong>aus, so wird dies <strong>in</strong> <strong>de</strong>r nächsten Zeile fortgeführt.<br />
Mit diesem Tag kann die Version <strong>de</strong>s Programms spezifiziert<br />
wer<strong>de</strong>n.<br />
Diese Tag fügt <strong>de</strong>n Namen <strong>de</strong>s Autors <strong>in</strong> die HTML-Datei e<strong>in</strong><br />
Mit diesem Tag kann <strong>de</strong>r wert beschrieben wer<strong>de</strong>n, <strong>de</strong>r von e<strong>in</strong>er<br />
Metho<strong>de</strong> zurückgegeben wird<br />
Dieses Tag erzeugt e<strong>in</strong>en L<strong>in</strong>k auf Ausnahmen, die von <strong>de</strong>r<br />
Klasse, die durch Klassenname spezifiziert ist, erzeugt wer<strong>de</strong>n.<br />
Neu seit Version 1.1. Das Tag markiert e<strong>in</strong>e Klasse, e<strong>in</strong> Interface,<br />
e<strong>in</strong> Feld o<strong>de</strong>r e<strong>in</strong>e Metho<strong>de</strong> als nicht verwendbar <strong>in</strong> weiteren<br />
Anwendungen´. Bereits existieren<strong>de</strong>r Co<strong>de</strong> wird trotz dieser<br />
kennzeichnung weiter kompiliert und laufen, aber <strong>de</strong>r Compiler<br />
wird e<strong>in</strong>e Warnung generieren,<br />
Spezifiziert, wann das Release erstellt wur<strong>de</strong>.<br />
Abb.: Die javadoc-Tags<br />
Die Syntax von javadoc:<br />
javadoc [Optionen] [Date<strong>in</strong>ame]<br />
javadoc [Klassenname] [Paketname]<br />
Falls e<strong>in</strong> Paketname angegeben wur<strong>de</strong>, dann dokumentiert javadoc alle <strong>Java</strong>-<br />
Quelldateien <strong>in</strong>nerhalb <strong>de</strong>s aktuellen Verzeichnisses und anschließend das<br />
151 vgl. 1.3.2.2, 3. Aufgabe<br />
153
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
dazugehörige Paketverzeichnis 152 relat<strong>in</strong> zum CLASSPATH. Für je<strong>de</strong> Klasse wird e<strong>in</strong><br />
eigenes HTML-Dokument erzeugt und für die Klassen <strong>in</strong>nerhalb e<strong>in</strong>es Pakets e<strong>in</strong><br />
HTML-In<strong>de</strong>x generiert.<br />
Option<br />
-version<br />
-classpath<br />
[Verzeichnis]<br />
Beschreibung<br />
Diese Option veranlaßt javadoc, die version <strong>de</strong>s JDK anzuzeigen.<br />
Diese Angabe korrespondiert wie bei <strong>de</strong>n an<strong>de</strong>ren JDK-Komponenten mit <strong>de</strong>r<br />
Umgebungsvariablen CLASSPATH und teilt <strong>in</strong> diesem Fall javadoc mit, <strong>in</strong><br />
welchen Verzeichnissen nach <strong>de</strong>n Quelltext-Dateien zu suchen ist. Die<br />
Verzeichnisse wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r Unix-Syntax durch Doppelpunkte getrennt,<br />
W<strong>in</strong>dows benutzt das Semikolon. Die angegebenen Pfa<strong>de</strong> wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r<br />
Reihenfolge ihres Auftretens durchsucht.<br />
-v<br />
-verbose I<strong>de</strong>ntisch mit <strong>de</strong>r Option –y<br />
-d [Verzeichnis] Mit dieser Option wird javadoc gezeigt, <strong>in</strong> welchem Verzeichnis sich das HTML-<br />
Dokument zur Dokumentation nach <strong>de</strong>r Generierung bef<strong>in</strong><strong>de</strong>n soll.<br />
Normalerweise wird das aktuelle Verzeichnis verwen<strong>de</strong>t.<br />
-public<br />
-protected<br />
-private<br />
-package<br />
-Jflag<br />
-notree<br />
-doencod<strong>in</strong>g [Name]<br />
-sourcepath [Pfad]<br />
Abb.: Die javadoc-Optionen<br />
Zeigt nur die öffentlichen elemente an<br />
Zeigt die geschützten und die öffentlichen Klassen und Metho<strong>de</strong>n an<br />
Zeigt alle Klassen und Metho<strong>de</strong>n an<br />
Zeigt die Packages, die geschützten und öffentlichen Klassen und Metho<strong>de</strong>n an<br />
Gibt e<strong>in</strong> Flag direkt an das Runtime-System weiter<br />
Wenn diese Option gesetzt ist, wird ke<strong>in</strong>e Klassenhierarchie generiert.<br />
Gibt <strong>de</strong>n Suchpfad für zu dokumentieren<strong>de</strong> Quelldateien an. Bee<strong>in</strong>flußt das<br />
la<strong>de</strong>n von Klassendateien nicht. Wird die Option nicht verwen<strong>de</strong>t, dokumentiert<br />
javadoc <strong>de</strong>faultmäßig nur die im aktuellen verzeichnis vorhan<strong>de</strong>nen Klassen<br />
und Packages im Tree-Bereich <strong>de</strong>r Dokumentation. Sollen Klassen und<br />
Packages <strong>in</strong> an<strong>de</strong>ren verzeichnissen mit dokumentiert wer<strong>de</strong>n, müssen diese<br />
hier angegeben wer<strong>de</strong>n.<br />
152 als Paketname zu verstehen, nicht als physikalisches Verzeichnis<br />
154
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.2 Typen<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 Speicher<br />
<strong>de</strong>s Rechners dargestellt wird. In <strong>Java</strong> gibt es vier verschie<strong>de</strong>ne Arten von Typen:<br />
„primitive Datentypen“, Datenfel<strong>de</strong>r (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) verwen<strong>de</strong>t.<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) verwen<strong>de</strong>t.<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) verwen<strong>de</strong>t.<br />
long 64 Bits Größter Wertebereich. Wird zum Darstellen von Ganzzahlwerten<br />
(ganzzahliges Zweierkomplement) von (-2 hoch 63) bis (+2 hoch 63)<br />
verwen<strong>de</strong>t.<br />
float 32 Bits Kürzester Wertebereich mit Vorzeichen zur Darstellung von<br />
Gleitpunktzahlenwerten. Dies entspricht Gleitpunktzahlen mit<br />
e<strong>in</strong>facher Genauigkeit, die <strong>de</strong>n IEEE-754-1985-Standard benutzen.<br />
Es existiert e<strong>in</strong> Literal zur Darstellung von plus/m<strong>in</strong>us unendlich sowie<br />
<strong>de</strong>r Wert NaN (Not a Number) zur Darstellung von nicht <strong>de</strong>f<strong>in</strong>ierten<br />
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 <strong>de</strong>n IEEE-754-1985-<br />
Standard. Es existiert wie beim Typ float e<strong>in</strong> Literal zur Darstellung<br />
von plus/m<strong>in</strong>us unendlich sowie <strong>de</strong>r Wert NaN (Not a Number) zur<br />
Darstellung von nicht <strong>de</strong>f<strong>in</strong>ierten Ergebnissen<br />
char 16 Bits Darstellung e<strong>in</strong>es Zeichens <strong>de</strong>s Unico<strong>de</strong>-Zeichensatzes. Zur<br />
Darstellung von alphanumerischen Zeichen wird dieselbe Kodierung<br />
wie beim ASCII-Zeichensatz verwen<strong>de</strong>t, 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 wer<strong>de</strong>n. Die<br />
Umkehrung – also die Zuweisung von char-Zeichen an an<strong>de</strong>re<br />
Datentypen – funktioniert nur für <strong>in</strong>t problemlos. Für an<strong>de</strong>re<br />
Datentypen ist ke<strong>in</strong>e direkte Zuweisung möglich.<br />
boolean 1 Bit Der boolschesche Datentyp umfaßt die Werte: true o<strong>de</strong>r 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 <strong>de</strong>m Datentyp boolean zugeordnet.<br />
Werte vom Typ boolean s<strong>in</strong>d zu allen an<strong>de</strong>ren Datentypen<br />
<strong>in</strong>kompatibel und lassen sich nicht durch Cast<strong>in</strong>g <strong>in</strong> an<strong>de</strong>re Typen<br />
überführen.<br />
Abb.: Primitive Datentypen <strong>de</strong>r <strong>Java</strong>-Sprache<br />
155
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.2.2 Operationen mit primitiven Datentypen<br />
2.2.2.1 Operationen mit booleschen Variablen<br />
Operation Name Be<strong>de</strong>utung<br />
= Zuweisung E<strong>in</strong>er booleschen Variable wird <strong>de</strong>r Wert true o<strong>de</strong>r 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 bei<strong>de</strong> boolesche<br />
Operan<strong>de</strong>n <strong>de</strong>nselben Wert (true o<strong>de</strong>r false) haben.<br />
An<strong>de</strong>renfalls 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 bei<strong>de</strong> boolesche<br />
Operan<strong>de</strong>n unterschiedliche Werte (true o<strong>de</strong>r false)<br />
haben. An<strong>de</strong>renfalls wird false zurückgeben.<br />
! Logisches NOT Falls <strong>de</strong>r Operand false ist, wird true zurückgegeben<br />
& AND Rückgabewert ist true, falls bei<strong>de</strong> Operan<strong>de</strong>n true s<strong>in</strong>d<br />
| OR Rückgabewert ist false, falls bei<strong>de</strong> Operan<strong>de</strong>n false s<strong>in</strong>d.<br />
^ XOR Rückgabewert ist true, falls genau e<strong>in</strong> Operand true ist<br />
(exklusives O<strong>de</strong>r)<br />
&& Logisches AND Rückgabe von true nur dann, wenn die bei<strong>de</strong>n Operan<strong>de</strong>n<br />
true s<strong>in</strong>d.<br />
|| Logisches OR Rückgabe von false nur dann, wenn bei<strong>de</strong> Operan<strong>de</strong>n<br />
false s<strong>in</strong>d.<br />
?: if-then-else Diese Operation benötigt e<strong>in</strong>en booleschen Ausdruck vor <strong>de</strong>m<br />
Fragezeichen. Falls er true ist, wird <strong>de</strong>r Wert vor <strong>de</strong>m<br />
Doppelpunkt zurückgegeben, ansonsten <strong>de</strong>r Wert h<strong>in</strong>ter <strong>de</strong>m<br />
Doppelpunkt.<br />
Abb.: Operationen mit booleschen Variablen<br />
2.2.2.2 Operationen mit Zeichenvariablen<br />
Zeichenvariablen können Operan<strong>de</strong>n <strong>in</strong> je<strong>de</strong>r ganzzahligen Operation se<strong>in</strong> und<br />
wer<strong>de</strong>n wie ganze 16-Bit-Zahlen ohne Vorzeichen behan<strong>de</strong>lt.<br />
Operation Name Be<strong>de</strong>utung<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 bei<strong>de</strong> Operan<strong>de</strong>n<br />
<strong>de</strong>nselben Wert (Unico<strong>de</strong>-Werte stimmen übere<strong>in</strong>) haben.<br />
An<strong>de</strong>renfalls 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 bei<strong>de</strong> boolesche<br />
Operan<strong>de</strong>n unterschiedliche Werte ( Bezogen auf die<br />
Unico<strong>de</strong>-Darstellung) haben. An<strong>de</strong>renfalls 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 Operan<strong>de</strong>n<br />
+,-,*,/ B<strong>in</strong>äre Arithmetik Die Zeichenvariablen gehen <strong>in</strong> die Berechnung mit ihren<br />
Unico<strong>de</strong>-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 <strong>de</strong>n Unico<strong>de</strong>-Wert<br />
von Zeichenvariablen<br />
156
<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<br />
rechts und für das bitweise Verschieben nach rechts mit<br />
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 wer<strong>de</strong>n 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 />
resultieren<strong>de</strong> Zeichen nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn alle<br />
bei<strong>de</strong>n Operan<strong>de</strong>n an <strong>de</strong>r gleichen Stelle Bits mit <strong>de</strong>m 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 />
resultieren<strong>de</strong> Zeichen nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn<br />
e<strong>in</strong>er <strong>de</strong>r Operan<strong>de</strong>n an dieser Position e<strong>in</strong>e 1 hatte<br />
^ Bitweises exklusives<br />
OR<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 />
resultieren<strong>de</strong> Zeichen nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn das<br />
zugehörige Bit <strong>in</strong> genau e<strong>in</strong>em <strong>de</strong>r bei<strong>de</strong>n Operan<strong>de</strong>n gesetzt<br />
ist.<br />
&=,|=,^= Bitweise Zuweisung Bitweise AND-, OR-, exklusive OR (XOR)- und<br />
Zuweisungsoperatoren<br />
Abb.: Operationen mit Zeichenvariablen<br />
2.2.2.3 Operationen mit Gleitpunktzahlen<br />
Operation Name Be<strong>de</strong>utung<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 bei<strong>de</strong> Operan<strong>de</strong>n<br />
<strong>de</strong>nselben Wert haben. An<strong>de</strong>renfalls 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 bei<strong>de</strong> Operan<strong>de</strong>n<br />
unterschiedliche Werte haben. An<strong>de</strong>renfalls 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 Operan<strong>de</strong>n<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 <strong>de</strong>n Wert <strong>de</strong>r<br />
Variablen.<br />
Abb.: Operationen mit <strong>de</strong>n Typen float und double<br />
<strong>Java</strong> erzeugt ke<strong>in</strong>e Ausnahmen bei <strong>de</strong>r Benutzung <strong>de</strong>r Gleitpunktarithmetik. E<strong>in</strong><br />
Überlauf 153 o<strong>de</strong>r 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 />
153 d.h.: Größeres Ergebnis von e<strong>in</strong>er Operation als durch <strong>de</strong>n Wertebereich <strong>de</strong>s jeweiligen Typs ausgedrückt<br />
wer<strong>de</strong>n kann.<br />
157
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
durch Null“ ergibt <strong>de</strong>n Wert „NaN“ (ke<strong>in</strong>e Zahl). E<strong>in</strong> Unterlauf 154 gibt e<strong>in</strong>en speziellen<br />
Wert aus: „positiv o<strong>de</strong>r negativ Null“. Dieser Wert kann mit Vergleichsoperatoren<br />
ausgewertet wer<strong>de</strong>n (bewirkt false).<br />
2.2.2.4 Operationen mit ganzzahligen Variablen (bzw. ganzzahligen Ausdrücken)<br />
Operation Name Be<strong>de</strong>utung<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 bei<strong>de</strong> Operan<strong>de</strong>n<br />
<strong>de</strong>nselben Wert haben. An<strong>de</strong>renfalls 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 bei<strong>de</strong> Operan<strong>de</strong>n<br />
unterschiedliche Werte haben. An<strong>de</strong>renfalls 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 Operan<strong>de</strong>n<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<br />
rechts und für das bitweise Verschieben nach rechts mit<br />
Füllnullen<br />
=,<br />
>>>=<br />
Bitweise Verschiebungs- und Zuweisungsoperatoren (nach<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 />
resultieren<strong>de</strong> Ganzzahl nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn<br />
alle bei<strong>de</strong>n Operan<strong>de</strong>n an <strong>de</strong>r gleichen Stelle Bits mit <strong>de</strong>m<br />
Wert 1 hatten<br />
| Bitweises OR 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 />
resultieren<strong>de</strong> Ganzzahl nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn<br />
e<strong>in</strong>er <strong>de</strong>r Operan<strong>de</strong>n an dieser Position e<strong>in</strong>e 1 hatte<br />
^ Biweises exklusives<br />
OR<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 resultieren<strong>de</strong><br />
Ganzzahl nur für die Bits <strong>de</strong>n E<strong>in</strong>trag 1, wenn das zugehörige<br />
Bit <strong>in</strong> genau e<strong>in</strong>em <strong>de</strong>r bei<strong>de</strong>n Operan<strong>de</strong>n gesetzt ist.<br />
&=,|=,^= Bitweise Zuweisung Inkrement- und Dekrementoperatoren für <strong>de</strong>n Wert <strong>de</strong>r<br />
Variablen<br />
Abb.: Operationen mit ganzzahligen Variablen<br />
Ganzzahlige Variable wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> als „Zweierkomplement“-Zahlen mit Vorzeichen<br />
verwen<strong>de</strong>t.<br />
154 d.h.: kle<strong>in</strong>eres Ergebnis (- außer Null -) von e<strong>in</strong>er Operation als durch <strong>de</strong>n Wertebereich <strong>de</strong>s jeweiligen Typs<br />
ausgedrückt wer<strong>de</strong>n kann.<br />
158
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.2.3 Datenfel<strong>de</strong>r (Arrays)<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 laufen<strong>de</strong>n In<strong>de</strong>x 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 <strong>de</strong>ssen wird <strong>de</strong>r Operator new mit spezieller Syntax<br />
aufgerufen.<br />
2. Es können ke<strong>in</strong>e Subklassen e<strong>in</strong>es Datenfelds <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n.<br />
Datenfel<strong>de</strong>r gehören zu <strong>de</strong>n Referenzvariablen 1 . Arrays können je<strong>de</strong>n Wertetyp<br />
(primitiver Typ o<strong>de</strong>r Objekt) enthalten, jedoch können <strong>in</strong> e<strong>in</strong>em Array ke<strong>in</strong>e<br />
unterschiedlichen Typen gespeichert wer<strong>de</strong>n.<br />
Arrays <strong>in</strong> <strong>Java</strong> s<strong>in</strong>d Objekte und unterschei<strong>de</strong>n sich von Datenfel<strong>de</strong>rn <strong>in</strong> an<strong>de</strong>ren<br />
Programmiersprachen durch folgen<strong>de</strong> Merkmale:<br />
- Array-Variable s<strong>in</strong>d Referenzen<br />
- Arrays besitzen Metho<strong>de</strong>n und Instanz-Variable<br />
- Arrays wer<strong>de</strong>n 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 <strong>de</strong>n Objekttyp an, <strong>de</strong>n das Datenfeld aufnimmt und <strong>de</strong>n namen<br />
<strong>de</strong>s Arrays, gefolgt von leeren eckigen Klammern „[]“, z.B: <strong>in</strong>t x[]. Alternativ<br />
dazu kann e<strong>in</strong>e Array-Variable auch so (Klammern nach <strong>de</strong>m Typ) festgelegt se<strong>in</strong>,<br />
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 <strong>de</strong>s Array wer<strong>de</strong>n automatisch <strong>in</strong>itialisiert (0 für<br />
numerische Datenfel<strong>de</strong>r, false für boolesche, ‘\0‘ für Zeichen-Arrays und „null“<br />
für alles an<strong>de</strong>re.<br />
Bsp.: Erzeugen von Datenfel<strong>de</strong>rn 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 />
155 Es kann sich dabei um primitive Variablentypen (byte, char, short, <strong>in</strong>t, long, float, double, boolean), aber<br />
auch um an<strong>de</strong>re Datenfel<strong>de</strong>r (verschachtelte Arrays) o<strong>de</strong>r Objekte han<strong>de</strong>ln.<br />
156 Es gibt drei Arten von Referenzvariablen: Klassen, Schnittstellen und Datenfel<strong>de</strong>r<br />
159
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
<strong>in</strong>t[] a;<br />
// Die Groesse <strong>de</strong>s 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, <strong>de</strong>ssen Komponenten ke<strong>in</strong>e primitiven Typen aufnehmen<br />
sollen, muß immer mit „new“ gefüllt wer<strong>de</strong>n.<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 <strong>de</strong>s 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> <strong>de</strong>r Feld<strong>in</strong>itialisierung bestimmt e<strong>in</strong>e bequeme<br />
syntaktische Form für <strong>de</strong>n „Aufruf von Metho<strong>de</strong>n“, die <strong>de</strong>n 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 />
behan<strong>de</strong>lt wer<strong>de</strong>n. Da alle Klassen von <strong>de</strong>r Klasse Object abstammen,<br />
kann e<strong>in</strong>e Metho<strong>de</strong> mit e<strong>in</strong>em Datenfeld als Argument verwen<strong>de</strong>t wer<strong>de</strong>n,<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 />
160
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<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 <strong>de</strong>s 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 <strong>de</strong>r <strong>in</strong> <strong>de</strong>r geschweiften Klammer stehen<strong>de</strong>n 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 <strong>de</strong>r Array-Ausdruck „subscript“<br />
benutzt, z.B.: x[subscript] . „subscript“ ist die Stelle (Position) für <strong>de</strong>n 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 <strong>de</strong>r<br />
vom Compiler vorgenommenen automatischen Typenkonvertierungen s<strong>in</strong>d auch<br />
short, byte, char zulässig. In<strong>de</strong>xausdrücke wer<strong>de</strong>n vom Laufzeitsystem auf<br />
E<strong>in</strong>haltung <strong>de</strong>r Array-Grenzen überprüft.<br />
2.2.3.2 Zugriff auf Datenfeld-Elemente, Än<strong>de</strong>rn von Datenfeld-Elementen<br />
Datenfeld-Subskripte beg<strong>in</strong>nen mit 0. Alle Array-Subskripte wer<strong>de</strong>n beim Kompilieren<br />
geprüft, ob sie sich <strong>in</strong>nerhalb <strong>de</strong>r Grenzem <strong>de</strong>s Array bef<strong>in</strong><strong>de</strong>n (Größer als 0, kle<strong>in</strong>er<br />
als die Länge <strong>de</strong>s 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 <strong>de</strong>r Array-Grenzen, dann erzeugt <strong>de</strong>r <strong>Java</strong>-Interpreter e<strong>in</strong>en Fehler 157 . Die<br />
Länge e<strong>in</strong>es Datenfelds kann mit <strong>de</strong>r Instanzvariablen length getestet wer<strong>de</strong>n, 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 <strong>de</strong>m 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 betreffen<strong>de</strong> Objekt e<strong>in</strong>e Referenz erzeugt. Datenfel<strong>de</strong>r 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 />
an<strong>de</strong>res.<br />
157 Er weist auf e<strong>in</strong>e „Ausnahme“ h<strong>in</strong>.<br />
161
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.2.3.3 Anwendungen mit e<strong>in</strong>dimensionaler Datenfel<strong>de</strong>rn<br />
1. Sammeln<br />
Datenfel<strong>de</strong>r s<strong>in</strong>d die wohl nützlichsten Objekte <strong>in</strong> <strong>Java</strong>, mit <strong>de</strong>nen Objekte <strong>in</strong> leicht<br />
zugänglichen Listen gesammelt wer<strong>de</strong>n können.<br />
2. Suchen<br />
a) sequentielle Suche<br />
Aufgabenstellung: Gegeben ist e<strong>in</strong>e ganze Zahl (Schlüssel schl) und e<strong>in</strong> Feld (Array) mit<br />
ganzzahligen Werten, die <strong>in</strong> diesem Array beliebig verteilt s<strong>in</strong>d. Such die In<strong>de</strong>xposition, für die gilt<br />
„a[i] == schl“. Ist die Suche ergebnislos, dann gib „Nicht Gefun<strong>de</strong>n“ zurück.<br />
b) b<strong>in</strong>äre Suche<br />
Aufgabenstellung: Gegeben ist e<strong>in</strong>e ganze Zahl (Schlüssel schl) und e<strong>in</strong> Array a mit ganzzahligen<br />
Werten, die <strong>in</strong> diesem Feld <strong>in</strong> aufsteigen<strong>de</strong>r Folge vorliegen. Suche die In<strong>de</strong>xposition, für die gilt:<br />
a[i] == schl“. Ist die Suche ergebnislos, dann gib „Nicht Gefun<strong>de</strong>n“ zurück.<br />
Lösungsverfahren: Es wird geprüft, ob <strong>de</strong>r gesuchte Schlüssel sich <strong>in</strong> <strong>de</strong>r Mitte <strong>de</strong>s Array bef<strong>in</strong><strong>de</strong>t.<br />
Falls dies nicht <strong>de</strong>r Fall ist, wird „schl < a[mitte]“ im l<strong>in</strong>ken Teil (von <strong>de</strong>r Mitte aus gesehen) und<br />
für „schl > a[mitte]“ im rechten Teil <strong>de</strong>s Array gesucht. Diese Strategie kann fortgesetzt wer<strong>de</strong>n,<br />
bis die Suche erfolgreich war o<strong>de</strong>r <strong>de</strong>r Schlüssel nicht gefun<strong>de</strong>n wur<strong>de</strong>.<br />
3. Sortieren 158<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 />
aufsteigen<strong>de</strong> Sortierreihenfolge br<strong>in</strong>gt.<br />
Lösungsverfahren (Algorithmus): Man kann jeweils <strong>de</strong>n ersten Schlüssel gegen alle weiteren<br />
Schlüssel im Arbeitsspeicherfeld vergleichen und so an <strong>de</strong>r ersten Position <strong>de</strong>n kle<strong>in</strong>sten Schlüssel<br />
nach (N-1) Vergleichen ermitteln. Danach vergleicht man jeweils <strong>de</strong>n Schlüssel aus <strong>de</strong>r zweiten<br />
Position mit allen nachfolgen<strong>de</strong>n Schlüsslwerten. Nach (N-2) Vergleichen steht <strong>de</strong>r zweitkle<strong>in</strong>ste<br />
Sachlüssel an <strong>de</strong>r zweiten Position. Bei Fortsetzung dieser Verfahrensweise ist schließlich nur noch<br />
e<strong>in</strong> e<strong>in</strong>ziger Schlüssel vorhan<strong>de</strong>n, <strong>de</strong>r dann auf <strong>de</strong>r richtigen, <strong>de</strong>r 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 <strong>de</strong>s Bubble-Sort<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 />
158 pr22301<br />
162
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Random zufallsZahl = new Random();<br />
// Initialisieren <strong>de</strong>s Array x<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
{<br />
x[i] = zufallsZahl.nextInt();<br />
}<br />
// Ausgabe <strong>de</strong>s noch nicht sortierten x<br />
System.out.pr<strong>in</strong>tln("Vor <strong>de</strong>m 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 <strong>de</strong>m 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 />
163
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.2.3.4 Mehrdimensionale Datenfel<strong>de</strong>r<br />
<strong>Java</strong> <strong>de</strong>f<strong>in</strong>iert mehrdimensionale Arrays durch Arrays von Arrays.<br />
Zweidimensionale Datenfel<strong>de</strong>r<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 vorliegen<strong>de</strong> Datenfeld umfaßt 5 Zeilen und 4 Spalten. E<strong>in</strong> Datenfeld „M“ mit 4<br />
Zeilen und 5 Spalten ist folgen<strong>de</strong>rmaß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 Datenfel<strong>de</strong>r wer<strong>de</strong>n, wie das folgen<strong>de</strong> Beispiel zeigt, auf gleiche<br />
Weise erstellt und <strong>in</strong>itialisiert wie e<strong>in</strong>dimensionale Fel<strong>de</strong>r.<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 />
Da mehrdimensionale Arrays als geschachtelte Arrays gespeichert wer<strong>de</strong>n, 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 />
164
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
Beispiele<br />
1. Das 8-Damen-Problem 159<br />
Aufgabenstellung: Acht Damen sollen so auf e<strong>in</strong>em Schachbrett positioniert wer<strong>de</strong>n, daß sie sich nicht<br />
schlagen können, d.h.: Zwei Damen stehen nie <strong>in</strong> <strong>de</strong>rselben Zeile o<strong>de</strong>r Spalte o<strong>de</strong>r 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 <strong>de</strong>r 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 9 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 />
Durch das Positionieren <strong>de</strong>r Dame s<strong>in</strong>d Positionierungen von weiteren Damen <strong>in</strong> <strong>de</strong>rselben Zeile und<br />
Spalte wie die soeben positionierte Dame, aber auch <strong>in</strong> <strong>de</strong>n zugehörigen Diagonalen nicht erlaubt.<br />
Die nicht mehr zulässigen Positionen wer<strong>de</strong>n mit 1 markiert.<br />
0 0 1 0 0 1 0 0<br />
1 0 1 0 1 0 0 0<br />
0 1 1 1 0 0 0 0<br />
1 1 9 1 1 1 1 1<br />
0 1 1 1 0 0 0 0<br />
1 0 1 0 1 0 0 0<br />
0 0 1 0 0 1 0 0<br />
0 0 1 0 0 0 1 0<br />
159 vgl. pr22305<br />
165
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Damen dürfen jetzt nur noch auf die mit 0 markierten Komponenten <strong>de</strong>s zweidimensionalen Felds<br />
gebracht wer<strong>de</strong>n. Das geschieht solange bis alle Komponenten <strong>de</strong>s zweidimensionalen Felds mit 1<br />
o<strong>de</strong>r 9 gefüllt s<strong>in</strong>d. Wur<strong>de</strong>n beim Füllen <strong>de</strong>s Felds <strong>in</strong>sgesamt 8 Damen positioniert, dann wur<strong>de</strong> 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 1 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 />
// Metho<strong>de</strong>n<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 />
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 />
166
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r nach l<strong>in</strong>ks laufen<strong>de</strong>n 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 <strong>de</strong>r nach rechts laufen<strong>de</strong>n 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 />
{<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 />
167
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
2. Pascal’sches Dreieck<br />
1<br />
1 1<br />
1 2 1<br />
1 3 3 1<br />
1 4 6 4 1<br />
1 5 10 10 5 1<br />
1 6 15 20 15 6 1<br />
Das Pascal'sche Dreieck wird mit Hilfe e<strong>in</strong>es nicht rechteckigen Arrays abgebil<strong>de</strong>t.<br />
Für die ersten Elemente kann geschrieben wer<strong>de</strong>n:<br />
<strong>in</strong>t element[][] = {<br />
{1},<br />
{1,1},<br />
{1,2,1}<br />
};<br />
In <strong>de</strong>r folgen<strong>de</strong>n Implementierung wird zu je<strong>de</strong>r Ebene dynamisch e<strong>in</strong> Feld mit <strong>de</strong>r<br />
passen<strong>de</strong>n Länge h<strong>in</strong>zugefügt.<br />
Bsp: 160<br />
public class Pascal<br />
160 vgl. pr22331, Pascal.java<br />
168
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
<strong>in</strong>t dreieck[][] = new <strong>in</strong>t[7][];<br />
for (<strong>in</strong>t i = 0; i < dreieck.length; i++)<br />
{<br />
dreieck[i] = new <strong>in</strong>t[i+1];<br />
for (<strong>in</strong>t j = 0; j
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r 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 />
2.2.3.5 Die Klasse Arrays<br />
Seit <strong>de</strong>m JDK1.2 gibt es die Klasse Arrays im Paket java.util mit nützlichen<br />
Metho<strong>de</strong>n zum Zugriff auf Arrays:<br />
public static void fill(<strong>in</strong>t[] a, <strong>in</strong>t wert)<br />
public static <strong>in</strong>t 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 />
Diese Metho<strong>de</strong>n stehen auch <strong>in</strong> vergleichbaren Versionen für an<strong>de</strong>re primitive<br />
Datentypen zur Verfügung.<br />
170
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.3 Ausdrücke<br />
E<strong>in</strong> Ausdruck ist das Ergebnis e<strong>in</strong>er Verknüpfung von Operan<strong>de</strong>n und Operatoren<br />
nach <strong>de</strong>n syntaktischen Regeln <strong>de</strong>r Sprache. Ausdrücke wer<strong>de</strong>n üblicherweise zur<br />
Durchführung von Operationen (Manipulationen) an Variablen o<strong>de</strong>r Werten<br />
verwen<strong>de</strong>t.<br />
Ausdrücke gehören zu <strong>de</strong>n 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><strong>de</strong>stens e<strong>in</strong>em Operan<strong>de</strong>n, auf <strong>de</strong>m <strong>de</strong>r<br />
Operator angewandt wird. Nach <strong>de</strong>m Typ <strong>de</strong>r Operan<strong>de</strong>n unterschei<strong>de</strong>t man<br />
numerische, relationale, logische, bitweise Operatoren. Je<strong>de</strong>r Ausdruck hat e<strong>in</strong>en<br />
Rückgabewert, <strong>de</strong>r durch die Anwendung <strong>de</strong>s Operators auf die Operan<strong>de</strong>n entsteht.<br />
Der Typ <strong>de</strong>s Rückgabewerts bestimmt sich aus <strong>de</strong>n Typen <strong>de</strong>r Operan<strong>de</strong>n und <strong>de</strong>r<br />
Art <strong>de</strong>s verwen<strong>de</strong>ten Operators.<br />
2.3.1 Arithmetische Ausdrücke<br />
Je<strong>de</strong> Programmiersprache hat e<strong>in</strong>en Mechanismus für arithmetische Berechnungen.<br />
In <strong>Java</strong> wer<strong>de</strong>n solche Berechnungen <strong>in</strong> arithmetischen Ausdrücken durchgeführt.<br />
2.3.2 Bewertung von Ausdrücken<br />
Bei <strong>de</strong>r 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 <strong>de</strong>rselbe<br />
Operator <strong>in</strong> e<strong>in</strong>em Ausdruck mehr als e<strong>in</strong>mal vorkommt, dann wird <strong>de</strong>r am weitesten<br />
l<strong>in</strong>ks stehen<strong>de</strong> zuerst bewertet, gefolgt von <strong>de</strong>m rechts daneben stehen<strong>de</strong>n, usw. Die<br />
Assoziativitätsregel bestimmt, wie Komb<strong>in</strong>ationen <strong>de</strong>s gleichen Operators bewertet<br />
wer<strong>de</strong>n können.<br />
Priorität<br />
<strong>Java</strong> hält sich, wie die grundlegen<strong>de</strong> Arithmetik, strikt an die Reglen <strong>de</strong>r<br />
Vorrangigkeit. Die multiplikativen Operatoren (*, / und %) haben Vorrang vor <strong>de</strong>n<br />
additiven Operatoren (+ und -). Immer wenn die Bewertungsreihenfolge von<br />
Operatoren <strong>in</strong> e<strong>in</strong>em Ausdruck geän<strong>de</strong>rt wer<strong>de</strong>n soll, müssen Klammern benutzt<br />
wer<strong>de</strong>n. Je<strong>de</strong>r Ausdruck <strong>in</strong> Klammern wird zuerst bewertet. Der Vorrang <strong>de</strong>r<br />
e<strong>in</strong>stelligen arithmetischen Operatoren steht über allen an<strong>de</strong>ren arithmetischen<br />
Operatoren.<br />
171
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bewertungsreihenfolge<br />
Die Vorrangregeln helfen bei <strong>de</strong>r Bewertung, welche Operatoren <strong>in</strong> e<strong>in</strong>em Ausdruck<br />
zuerst benutzt wer<strong>de</strong>n und welche Operan<strong>de</strong>n zu welchen Operatoren gehören. Die<br />
Regeln für die Bewertungsreihenfolge helfen festzulegen, wann welche Operan<strong>de</strong>n<br />
bewertet wer<strong>de</strong>n. Die drei folgen<strong>de</strong>n Regeln bestimmen, wie e<strong>in</strong> Ausdruck bewertet<br />
wird:<br />
- Bei allen b<strong>in</strong>ären Operatoren wird <strong>de</strong>r l<strong>in</strong>ke Operand vor <strong>de</strong>m rechten bewertet.<br />
- Zuerst wer<strong>de</strong>n die Operan<strong>de</strong>n, danach die Operatoren bewertet.<br />
- Falls mehrere Parameter, die durch Kommata vone<strong>in</strong>an<strong>de</strong>r getrennt s<strong>in</strong>d, durch e<strong>in</strong>en Metho<strong>de</strong>naufruf zur<br />
Verfügung gestellt wer<strong>de</strong>n, wer<strong>de</strong>n diese Parameter von l<strong>in</strong>ks nach rechts bewertet.<br />
2.3.3 Typkonvertierungen<br />
<strong>Java</strong> ist e<strong>in</strong>e typisierte Sprache. Es f<strong>in</strong><strong>de</strong>n 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 an<strong>de</strong>ren. 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 an<strong>de</strong>ren.<br />
<strong>Java</strong> unterstützt explizite Konvertierungen und „ad hoc“-Konvertierungen.<br />
Ad-hoc-Konvertierungen. Hier gibt es folgen<strong>de</strong> Regeln für numerische Datentypen:<br />
- Bei Operationen mit ausschl. ganzzahligen Operan<strong>de</strong>n wird, falls e<strong>in</strong>er <strong>de</strong>r bei<strong>de</strong>n Operan<strong>de</strong>n <strong>de</strong>n<br />
Datentyp long hat, <strong>de</strong>r an<strong>de</strong>re ebenfalls zu long konvertiert; ansonsten wer<strong>de</strong>n bei<strong>de</strong> Operan<strong>de</strong>n<br />
zu <strong>in</strong>t konvertiert. Das Ergebnis ist dann ebenfalls vom Typ <strong>in</strong>t. Ist allerd<strong>in</strong>gs <strong>de</strong>r ausgegebene<br />
Wert zu groß, um im Wertebereich von <strong>in</strong>t dargestellt zu wer<strong>de</strong>n, wird <strong>de</strong>r Typ long verwen<strong>de</strong>t.<br />
- Bei Operationen mit wenigstens e<strong>in</strong>em Gleitpunkt-Operan<strong>de</strong>n wird, wenn e<strong>in</strong>er <strong>de</strong>r Operan<strong>de</strong>n <strong>de</strong>n<br />
Datentyp double hat, <strong>de</strong>r an<strong>de</strong>re ebenfalls zu double konvertiert. Das Ergebnis ist dann ebenfalls<br />
vom Datentyp double, an<strong>de</strong>renfalls wer<strong>de</strong>n bei<strong>de</strong> Operan<strong>de</strong>n 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 />
an<strong>de</strong>ren Datentyp gewünscht wird und diese nicht „ad hoc“ e<strong>in</strong>tritt. „Cast<strong>in</strong>g“ muß<br />
dann angewen<strong>de</strong>t wer<strong>de</strong>n. Der zugehörige (Festlegungs-)Operator besteht aus<br />
e<strong>in</strong>em Typnamen <strong>in</strong> run<strong>de</strong>n 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 Operan<strong>de</strong>n. Er hat immer die folgen<strong>de</strong> Form:<br />
„(Datentyp) Wert“. Der (Festlegungs-)Operator bestimmt <strong>de</strong>n Wert se<strong>in</strong>es<br />
Operan<strong>de</strong>n, <strong>de</strong>r auf <strong>de</strong>n <strong>in</strong> Klammern bezeichneten Typ festgelegt wird. Es gibt<br />
folgen<strong>de</strong> Cast<strong>in</strong>g-Operatoren:<br />
Operator Beispiel Erläuterung<br />
(byte)<br />
(byte) (x/y) Wan<strong>de</strong>lt das Errgebnis von x/y <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp byte<br />
um<br />
(short) (short) x Wan<strong>de</strong>lt 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) Wan<strong>de</strong>lt das Ergebnis von x/y <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp <strong>in</strong>t<br />
(long) (long) x Wan<strong>de</strong>lt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp long um<br />
(float) (float) x Wan<strong>de</strong>lt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp float um<br />
(double) (double) x Wan<strong>de</strong>lt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp double um<br />
(char) (char) x Wan<strong>de</strong>lt x <strong>in</strong> e<strong>in</strong>en Wert vom Datentyp char um<br />
(boolean) (boolean) 0 Wan<strong>de</strong>lt 0 <strong>in</strong> e<strong>in</strong>en booleschen Datentyp um<br />
Abb.: Cast<strong>in</strong>g-Operatoren<br />
172
<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 wer<strong>de</strong>n<br />
Nicht alle Konvertierungen s<strong>in</strong>d möglich. Variable e<strong>in</strong>es arithmetischen Typs können<br />
auf je<strong>de</strong>n an<strong>de</strong>ren arithmetischen Typ festgelegt wer<strong>de</strong>n. Boolesche Werte können<br />
nicht auf irgen<strong>de</strong><strong>in</strong>en an<strong>de</strong>ren Wert festgelegt wer<strong>de</strong>n. Die Umkehrung funktioniert<br />
mit E<strong>in</strong>schränkungen: 0 und 1 lassen sich <strong>in</strong> boolesche Werte konvertieren.<br />
Bsp. 162 : 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("Unico<strong>de</strong> 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 an<strong>de</strong>rer Klassen konvertieren. Die Klassen müssen allerd<strong>in</strong>gs durch<br />
Vererbung mite<strong>in</strong>an<strong>de</strong>r verbun<strong>de</strong>n 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 wer<strong>de</strong>n. Spezifische Informationen <strong>de</strong>r Subklasse<br />
gehen dabei verloren. Das Konvertieren erfolgt immer nach folgen<strong>de</strong>r Form:<br />
(Klassenname) Objekt.<br />
162 vgl. pr23301<br />
173
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp. 163 : Konvertieren Datentyp Object<br />
import java.applet.Applet;<br />
import java.awt.*;<br />
import java.util.Vector;<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 <strong>de</strong>n L<strong>in</strong>ien<br />
schnei<strong>de</strong>ausSegment();<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 schnei<strong>de</strong>ausSegment()<br />
{<br />
<strong>in</strong>t <strong>in</strong><strong>de</strong>x = 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 />
schnei<strong>de</strong>ausMittleresDrittel(<strong>in</strong><strong>de</strong>x,<strong>in</strong><strong>de</strong>x+1);<br />
<strong>in</strong><strong>de</strong>x += 4;<br />
}<br />
}<br />
163 pr23302<br />
174
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void schnei<strong>de</strong>ausMittleresDrittel(<strong>in</strong>t l<strong>in</strong>ks, <strong>in</strong>t rechts)<br />
{<br />
float luecke;<br />
float x1, x2;<br />
Float tempFloat1, tempFloat2;<br />
// Zugriff an <strong>de</strong>r 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 <strong>de</strong>r angegebenen Stelle <strong>in</strong> <strong>de</strong>r 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 o<strong>de</strong>r 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 o<strong>de</strong>r<br />
kle<strong>in</strong>er als e<strong>in</strong> an<strong>de</strong>rer 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 verschie<strong>de</strong>ne Arten ausgeführt wer<strong>de</strong>n:<br />
- Short-turn-Operatoren (logisches AND && und logisches OR ||). Sie operieren nur mit booleschen<br />
Variablen.<br />
- Bitweise Operatoren. Sie operieren mit je<strong>de</strong>m Bit zweier ganzzahliger Operan<strong>de</strong>n.<br />
175
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.4 Anweisungen<br />
2.4.1 Blöcke und Anweisungen<br />
Metho<strong>de</strong>n und statische Initialisatoren wer<strong>de</strong>n <strong>in</strong> <strong>Java</strong> durch Anweisungsblöcke<br />
<strong>de</strong>f<strong>in</strong>iert. E<strong>in</strong> Anweisungsblock besteht <strong>in</strong> <strong>de</strong>r Regel aus e<strong>in</strong>er Reihe von<br />
Anweisungen, die <strong>in</strong> geschweiften Klammern stehen. Das be<strong>de</strong>utet: Es können <strong>in</strong><br />
diesem Block lokale Variablen <strong>de</strong>klariert wer<strong>de</strong>n, die außerhalb <strong>de</strong>s Blocks nicht<br />
verfügbar s<strong>in</strong>d, und <strong>de</strong>ren Existenz erlischt, wenn <strong>de</strong>r Block ausgeführt wur<strong>de</strong>.<br />
2.4.2 Leere Anweisungen<br />
In <strong>Java</strong> können leere Anweisungen erstellt wer<strong>de</strong>n. Für <strong>de</strong>n 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 />
Je<strong>de</strong> Anweisung darf <strong>in</strong> <strong>Java</strong> e<strong>in</strong>e „Benennung“ haben. Die „Benennung“ hat die<br />
gleichen Eigenschaften wie je<strong>de</strong>r an<strong>de</strong>re Bezeichner. Die Reichweite <strong>de</strong>r<br />
„Benennung“ erstreckt sich über <strong>de</strong>n ganzen Block. Der Benennung folgt e<strong>in</strong><br />
Doppelpunkt.<br />
„Benennungen“ wer<strong>de</strong>n nur von <strong>de</strong>n Sprunganweisungen break und cont<strong>in</strong>ue<br />
benutzt.<br />
2.4.4 Deklarationen<br />
E<strong>in</strong>e Deklarationsanweisung <strong>de</strong>f<strong>in</strong>iert e<strong>in</strong>e Variable, egal ob Klasse, Schnittstelle,<br />
Datenfeld, Objekt o<strong>de</strong>r primitiver Typ. Das Format e<strong>in</strong>er solchen Anweisung hängt<br />
davon ab, welcher <strong>de</strong>r 5 verschie<strong>de</strong>nen Formen <strong>de</strong>klariert wird.<br />
Typname variablenName;<br />
bzw.<br />
Typname variablenName = <strong>in</strong>itialerWert;<br />
2.4.5 Ausdrucksanweisungen<br />
In <strong>Java</strong> gibt es sieben verschie<strong>de</strong>ne Arten von Ausdrucksanweisungen:<br />
Ausdrucksanweisung<br />
Zuordnung<br />
Prä-Inkrement<br />
Prae-Dekrement<br />
Beispiel<br />
x=13;<br />
++wert;<br />
--wert;<br />
176
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Post-Inkrement<br />
Post-Dekrement<br />
Metho<strong>de</strong>naufruf<br />
Zuweisungsausdruck<br />
wert++;<br />
wert--;<br />
System.out.pr<strong>in</strong>tln("Aller Anfang ist schwer!");<br />
byte x = new byte;<br />
Abb.: Die sieben Ausdrucksanweisungen <strong>in</strong> <strong>Java</strong><br />
Bsp.: Demonstrationsprogramm zur Wirkungsweise <strong>de</strong>r Inkrement- und Dekrement-<br />
Operatoren 164<br />
// Demonstration <strong>de</strong>r Operatoren ++ und --<br />
public 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 />
2.4.6 Auswahlanweisungen<br />
2.4.6.1 if-Anweisungen<br />
E<strong>in</strong>e if-Anweisung testet e<strong>in</strong>e boolesche Variable o<strong>de</strong>r e<strong>in</strong>en Ausdruck zur<br />
Feststellung, ob e<strong>in</strong>e Anweisung o<strong>de</strong>r e<strong>in</strong> Anweisungsblock ausgeführt wer<strong>de</strong>n soll.<br />
Hat die boolesche Variable <strong>de</strong>n Wert true, wird <strong>de</strong>r Block ausgeführt. Falls nicht,<br />
spr<strong>in</strong>gt die Programmkontrolle zur nächsten Anweísung h<strong>in</strong>ter <strong>de</strong>m Block.<br />
if (boolscher_Ausdruck)<br />
anweisung 165<br />
2.4.6.2 if-else-Anweisungen<br />
164 vgl. pr24500<br />
165 „anweisung“ be<strong>de</strong>utet: 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 />
177
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 o<strong>de</strong>r Block weiter, wenn <strong>de</strong>r boolesche Wert im if-Teil <strong>de</strong>r Anweisung<br />
false war.<br />
if (boolscher_Ausdruck)<br />
anweisung<br />
else<br />
anweisung<br />
Bsp.: Demonstrationsprogramm zur if-Anweisung 166<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 />
// 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 />
166 Vgl. pr24601<br />
178
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
2.4.6.3 switch-Anweisungen<br />
E<strong>in</strong>e switch-Anweisung ermöglicht die Weitergabe <strong>de</strong>s Kontrollflusses an e<strong>in</strong>e von<br />
vielen Anweisungen <strong>in</strong> ihrem Block mit Unteranweisungen (ist abhängig vom Wert<br />
<strong>de</strong>s Ausdrucks <strong>in</strong> <strong>de</strong>r 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 />
<strong>de</strong>fault: 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 167 .<br />
„switch“ vergleicht das Ergebnis e<strong>in</strong>er Auswertung vom <strong>in</strong>tegralen Selektor mit je<strong>de</strong>m<br />
<strong>in</strong>tegralen Wert. Falls e<strong>in</strong> passen<strong>de</strong>r Wert gefun<strong>de</strong>n wird, wird die zugehörige<br />
Anweisung (e<strong>in</strong>fach o<strong>de</strong>r zusammengesetzt) ausgeführt. An<strong>de</strong>renfalls kommt es zur<br />
Ausführung <strong>de</strong>r bei „<strong>de</strong>fault“ angegebenen Anweisung. Die „break“-Anweisung ist<br />
optional. Fehlt sie, dann wer<strong>de</strong>n die folgen<strong>de</strong>n Anweisungen ausgeführt, bis e<strong>in</strong><br />
„break“ auftritt.<br />
Bsp.: Demonstrationsprogramm zur switch-Anweisung 168<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 <strong>de</strong>zimal = 10;<br />
System.out.pr<strong>in</strong>t("<strong>de</strong>zimal = " + <strong>de</strong>zimal + " hex: ");<br />
switch (<strong>de</strong>zimal)<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("" + <strong>de</strong>zimal);<br />
break;<br />
case 10:<br />
167 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 />
168 vgl. pr24601<br />
179
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
<strong>de</strong>fault:<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 />
2.4.7.1 while-Anweisung<br />
Die while-Anweisung testet e<strong>in</strong>e boolesche Variable o<strong>de</strong>r e<strong>in</strong>en Ausdruck. Ist er<br />
true, wird die Unteranweisung o<strong>de</strong>r <strong>de</strong>r Block solange ausgeführt, bis sich <strong>de</strong>r Wert<br />
false e<strong>in</strong>stellt. Ist die Variable o<strong>de</strong>r <strong>de</strong>r Ausdruck false, wird die Kontrolle an die<br />
nächste Anweisung nach <strong>de</strong>r Unteranweisung o<strong>de</strong>r nach <strong>de</strong>m Block <strong>de</strong>r while-<br />
Anweisung weitergegeben.<br />
while (boolescher_Ausdruck)<br />
anweisung<br />
Bsp. 169 :<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 />
aHochn = 1.0 / aHochn;<br />
}<br />
System.out.pr<strong>in</strong>tln("aHochn = " + aHochn);<br />
}<br />
}<br />
2.4.7.2 do-Anweisung<br />
Die do-Anweisung testet e<strong>in</strong>e boolesche Variable o<strong>de</strong>r e<strong>in</strong>en Ausdruck. Solange<br />
dieser <strong>de</strong>n Wert true hat, wird die Unteranweisung o<strong>de</strong>r <strong>de</strong>r Block ausgeführt. Erst<br />
wenn die boolesche Variable o<strong>de</strong>r <strong>de</strong>r Ausdruck <strong>de</strong>n Wert false hat, wird die<br />
Wie<strong>de</strong>rholung e<strong>in</strong>gestellt und die Schleife verlassen. Der Co<strong>de</strong>-Block <strong>in</strong>nerhalb <strong>de</strong>r<br />
do-Anweisung wird auf je<strong>de</strong>n Fall m<strong>in</strong><strong>de</strong>stens e<strong>in</strong>mal ausgeführt.<br />
do<br />
anweisung<br />
while (boolescher_Ausdruck)<br />
Bsp. 170 :<br />
public class DoDemo 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 />
do<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 />
2.4.7.3 for-Anweisung<br />
Sie besteht aus<br />
- for, gefolgt von optionalem Leerraum, gefolgt von e<strong>in</strong>er öffnen<strong>de</strong>n Klammer.<br />
- Initialisierungsteil. Er enthält e<strong>in</strong>e durch Kommata getrente Reihe von<br />
Deklarations- und Zuweisungsanweisungen, die durch e<strong>in</strong> Semikolon been<strong>de</strong>t<br />
wird. Die Deklarationen haben nur Gültigkeit für <strong>de</strong>n Bereich <strong>de</strong>r for-Anweisung<br />
und ihrer Unteranweisungen. Die Zuweisungen wer<strong>de</strong>n nur e<strong>in</strong>mal vor <strong>de</strong>r esrten<br />
Wie<strong>de</strong>rholung <strong>de</strong>r Unteranweisung o<strong>de</strong>r <strong>de</strong>s Blocks gemacht.<br />
- Testteil. Enthält e<strong>in</strong>e boolesche Variable o<strong>de</strong>r e<strong>in</strong>en Ausdruck, <strong>de</strong>r e<strong>in</strong>mal je<br />
Schleife neu bewertet wird. Falls <strong>de</strong>r Ausdruck false wird, geht die Kontrolle zur<br />
nächsten Anweisung nach <strong>de</strong>r for-Anweisung und ihrer Unteranweisung o<strong>de</strong>r<br />
ihrem Block weiter. Die Zuweisungen wer<strong>de</strong>n nur e<strong>in</strong>mal vor <strong>de</strong>r ersten<br />
Wie<strong>de</strong>rholung <strong>de</strong>r Unteranweisung o<strong>de</strong>r <strong>de</strong>s Blocks gemacht.<br />
- Inkrementteil. Enthält e<strong>in</strong>e durch Kommata getrennte Reihe von Ausdrücken, die<br />
e<strong>in</strong>mal je Durchlauf <strong>de</strong>r Schleife bewertet wer<strong>de</strong>n. Dieser Teil wird gewöhnlich<br />
dazu verwen<strong>de</strong>t, e<strong>in</strong>en In<strong>de</strong>x, <strong>de</strong>r im Testteil überprüft wird, zu <strong>in</strong>krementieren.<br />
Am En<strong>de</strong> <strong>de</strong>s Teils steht e<strong>in</strong> Semikolon.<br />
Je<strong>de</strong>r <strong>de</strong>r drei Ausdrücke kann entfallen.<br />
for (<strong>in</strong>itialisierung; boolescher_Ausdruck; naechster_Schritt)<br />
anweisung<br />
Bsp.: 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 />
2.4.7.4 Die erweiterte Form <strong>de</strong>r for-Schleife <strong>in</strong> <strong>Java</strong> 1.5<br />
for (Type i<strong>de</strong>ntifier : expr) { body }<br />
Dieser Konstrukt wird so gelesen: "Für je<strong>de</strong>s i<strong>de</strong>ntifier <strong>de</strong>s Typs Type <strong>in</strong> expr<br />
führe aus".<br />
Das erweiterte for möchte l<strong>in</strong>ks vom Doppelpunkt e<strong>in</strong> Feld (Array) o<strong>de</strong>r Objekt, das<br />
vom Typ Iterable ist. Das Interface Iterable schreibt nur die Existenz e<strong>in</strong>er<br />
Funktion iterator() vor, die e<strong>in</strong>en java.lang.SimpleIterator liefert. Der<br />
konkrete SimpleIterator muß nur die Metho<strong>de</strong>n hasNext() und next()<br />
implementieren, um das nächste Element <strong>in</strong> <strong>de</strong>r Aufzählung zu beschaffen und das<br />
En<strong>de</strong> anzuzeigen. E<strong>in</strong> SimpleIterator ist e<strong>in</strong> Iterator 171 ohne remove().<br />
Bsp.:<br />
import java.util.ArrayList;<br />
import java.util.Iterator;<br />
public class ForLoopTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
double[] array = {2.5, 5.2, 7.9, 4.3, 2.0, 4.1, 7.3, 0.1, 2.6};<br />
// E<strong>in</strong>fache Iteration vorwaerts durch die Schleife<br />
for(double d: array) { System.out.pr<strong>in</strong>tln(d); }<br />
System.out.pr<strong>in</strong>tln("---------------------");<br />
// Das folgen<strong>de</strong> arbeitet mit allem, das das Interface Iterable<br />
// implementiert, z.B mit Collections wie ArrayList<br />
ArrayList list = new ArrayList();<br />
list.add(7); list.add(15); list.add(-67);<br />
for(Integer number : list) { System.out.pr<strong>in</strong>tln(number); }<br />
System.out.pr<strong>in</strong>tln("---------------------");<br />
// Es unterstuetzt auch Autobox<strong>in</strong>g<br />
for(<strong>in</strong>t item: list) { System.out.pr<strong>in</strong>tln(item); }<br />
System.out.pr<strong>in</strong>tln("---------------------");<br />
}<br />
}<br />
Test:<br />
Abb.:<br />
171 vgl. 6.2.1<br />
183
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.4.8 Sprung-Anweisungen<br />
2.4.8.1 break-Anweisung<br />
Unteranweisungsblöcke von Schleifen und switch-Anweisungen können durch<br />
Verwendung e<strong>in</strong>er break-Anweisung verlassen wer<strong>de</strong>n. E<strong>in</strong>e unbezeichnete break-<br />
Anweisung spr<strong>in</strong>gt zur nächsten Zeile nach <strong>de</strong>r aktuellen (<strong>in</strong>nersten) Wie<strong>de</strong>rholungsund<br />
switch-Anweisung. Mit e<strong>in</strong>er bezeichneten break-Anweisung am Anfang e<strong>in</strong>er<br />
Schleife kann an e<strong>in</strong>e Anweisung mit dieser Bezeichnung <strong>in</strong> <strong>de</strong>r <strong>de</strong>rzeitigen Metho<strong>de</strong><br />
gesprungen wer<strong>de</strong>n. Am Anfangsteil <strong>de</strong>r Schleife muß e<strong>in</strong> Label (e<strong>in</strong>e Bezeichnung)<br />
mit e<strong>in</strong>em Doppelpunkt stehen, z.B.: „label1:“.<br />
2.4.8.2 cont<strong>in</strong>ue-Anweisung<br />
Der aktuelle Schleifendurchlauf wird unterbrochen. Es wird zum Anfang <strong>de</strong>r Schleife<br />
zurückgekehrt, falls h<strong>in</strong>ter cont<strong>in</strong>ue ke<strong>in</strong> „Bezeichner“ steht. An<strong>de</strong>renfalls wird zu<br />
e<strong>in</strong>er äußeren Schleife zurückgekehrt, die e<strong>in</strong>e Markierung (label) gleichen<br />
Namens enthält.<br />
E<strong>in</strong>e cont<strong>in</strong>ue-Anweisung darf nur <strong>in</strong> e<strong>in</strong>em Unterweisungsblock e<strong>in</strong>er<br />
Iterationsanweisung stehen (while, do o<strong>de</strong>r for).<br />
Bsp. 172 : „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 <strong>de</strong>r 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 <strong>de</strong>r Schleife<br />
if (i % 10 != 0) cont<strong>in</strong>ue; // zurueck an <strong>de</strong>n Anfang <strong>de</strong>r Schleife<br />
System.out.pr<strong>in</strong>tln(i);<br />
}<br />
}<br />
}<br />
172 pr24800<br />
184
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.4.8.3 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 <strong>de</strong>r „break“- bzw.<br />
„cont<strong>in</strong>ue“-Anweisung e<strong>in</strong>e Unterbrechnug <strong>de</strong>s Schleifendurchgangs und e<strong>in</strong>en<br />
Sprung zu <strong>de</strong>r <strong>de</strong>m „label“ folgen<strong>de</strong>n Anweisung. S<strong>in</strong>nvollerweise steht dann e<strong>in</strong><br />
„label“ am Anfang <strong>de</strong>r Schleifen, z.B.:<br />
label1:<br />
äußere_Iteration<br />
{<br />
<strong>in</strong>nere_Iteration<br />
{<br />
// ...<br />
break;<br />
// ...<br />
cont<strong>in</strong>ue;<br />
// ...<br />
}<br />
}<br />
cont<strong>in</strong>ue label1;<br />
// ...<br />
break label1;<br />
// 1. Fall<br />
// 2. Fall<br />
// 3. Fall<br />
// 4. Fall<br />
Im 1. Fall bricht „break“ aus <strong>de</strong>r <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 <strong>de</strong>n Anfang <strong>de</strong>r <strong>in</strong>neren Iteration. Im 3.<br />
Fall führt „cont<strong>in</strong>ue label1“ aus <strong>de</strong>r <strong>in</strong>neren und äußeren Iteration heraus auf<br />
„label1“. Die Iteration wird mit <strong>de</strong>m Anfang <strong>de</strong>r äußeren Iteration fortgesetzt. Im 4.<br />
Fall bricht „break label1“ aus <strong>de</strong>r <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, son<strong>de</strong>rn zu e<strong>in</strong>em Ausbruch<br />
aus bei<strong>de</strong>n Iterationen.<br />
Bsp. 173 : Marken im Zusammenhang mit „for“- bzw. „while“-Schleifen<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:<br />
// hier soll ke<strong>in</strong>e Anweisung stehen<br />
for (; true; )<br />
// Endlos-Schleife<br />
{<br />
<strong>in</strong>nen:<br />
// 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 />
173 pr24800<br />
185
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
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 />
186
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
2.4.8.4 return-Anweisung<br />
Alle Funktionen haben e<strong>in</strong>en e<strong>in</strong><strong>de</strong>utigen Typ, <strong>de</strong>r gleichzeitig Typ <strong>de</strong>s<br />
Rückgabewerts ist. Mögliche Typen für die Rückgabe s<strong>in</strong>d primitive Typen,<br />
Datenfel<strong>de</strong>r (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 <strong>de</strong>r Wert e<strong>in</strong>er return-Anweisung.<br />
2.4.8.5 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 <strong>de</strong>n Umgang mit „Multithread<strong>in</strong>g“ benutzt.<br />
187
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.4.10 Schutzanweisungen<br />
<strong>Java</strong> kennt drei Schutzanweisungen: try, catch, f<strong>in</strong>ally. Sie wer<strong>de</strong>n zur<br />
Handhabung von Ausnahmen <strong>in</strong> e<strong>in</strong>er Metho<strong>de</strong> 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 Metho<strong>de</strong> mit Co<strong>de</strong>zeilen möglich, die nie erreicht wer<strong>de</strong>n<br />
können, z.B. Zeilen zwischen e<strong>in</strong>er bed<strong>in</strong>gungslosen return-Anweisung und <strong>de</strong>r<br />
nächsten Bezeichnung o<strong>de</strong>r <strong>de</strong>m En<strong>de</strong> e<strong>in</strong>es Blocks. Solche Anweisungen erzeugen<br />
e<strong>in</strong>en Fehler beim Kompilieren.<br />
2.5 Klassen<br />
2.5.1 Deklaration<br />
Klassen <strong>de</strong>f<strong>in</strong>ieren Zustand und Verhalten von Objekten. Je<strong>de</strong>s <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 <strong>de</strong>m JDK frei verfügbar<br />
s<strong>in</strong>d. Das eigentliche RUNTIME-Modul besteht aus <strong>de</strong>r Datei <strong>Java</strong> Core Classes<br />
(classes.zip), die normalerweise nicht entpackt wird und im Unterverzeichnis<br />
\lib <strong>de</strong>s JDK vohan<strong>de</strong>n ist. Die Datei enthält <strong>de</strong>n vollständigen kompilierten Co<strong>de</strong><br />
von <strong>Java</strong>.<br />
Je<strong>de</strong> Klasse besteht formal aus zwei Teilen: <strong>de</strong>r Deklaration und <strong>de</strong>m Body (Körper).<br />
Generell haben Klassen<strong>de</strong>klarationen folgen<strong>de</strong>s 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 <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n<br />
können: Modifizierer, Klassenname, Superklasse, Schnittstellen<br />
Modifizierer<br />
Sie stehen am Beg<strong>in</strong>n <strong>de</strong>r Klassen<strong>de</strong>klaration und legen fest, wie die Klasse<br />
während <strong>de</strong>r weiteren Entwicklung gehandhabt wer<strong>de</strong>n kann. Klassen haben e<strong>in</strong>en<br />
vore<strong>in</strong>gestellten, „freundlichen“ Defaultstatus. Er wird immer dann verwen<strong>de</strong>t, wenn<br />
ke<strong>in</strong> Modifizierer am Anfang e<strong>in</strong>er Klassen<strong>de</strong>f<strong>in</strong>ition steht. „Freundlich“ be<strong>de</strong>utet: Die<br />
Klasse darf erweitert und von an<strong>de</strong>ren Klassen benutzt wer<strong>de</strong>n, aber nur von<br />
Objekten <strong>in</strong>nerhalb <strong>de</strong>sselben Pakets. Die Grun<strong>de</strong><strong>in</strong>stellung bezieht sich also auf die<br />
Sichtbarkeit von an<strong>de</strong>ren Klassen und <strong>de</strong>ren Objekten. Falls davon abgewichen<br />
wer<strong>de</strong>n soll, ist e<strong>in</strong>er <strong>de</strong>r folgen<strong>de</strong>n Modifizierer zu verwen<strong>de</strong>n: public , f<strong>in</strong>al,<br />
abstract.<br />
188
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Öffentliche Klassen – <strong>de</strong>r Modifizierer public. E<strong>in</strong>e Klasse wird als öffentlich<br />
<strong>de</strong>klariert, wenn man <strong>de</strong>n Modifizierer public vor die Klassen<strong>de</strong>klaration setzt. Alle<br />
Objekte dürfen auf public-Klassen zugreifen, d.h.: Sie können von allen Objekten<br />
benutzt und erweitert wer<strong>de</strong>n, ganz egal zu welchem Paket sie gehören.. Die<br />
Deklaration e<strong>in</strong>er öffentlichen Klasse muß immer i<strong>de</strong>ntisch se<strong>in</strong> mit <strong>de</strong>m Namen,<br />
unter <strong>de</strong>m die Quelle dieser Datei gespeichert ist.<br />
F<strong>in</strong>ale Klassen – <strong>de</strong>r 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 <strong>de</strong>r Klassen<strong>de</strong>klaration gesetzt se<strong>in</strong>.<br />
Abstrakte Klassen – <strong>de</strong>r Modifizierer abstract. Von e<strong>in</strong>er <strong>de</strong>rartig beschriebenen<br />
Klasse wird nie e<strong>in</strong>e direkte Instanz benötigt und kann auch nie e<strong>in</strong>e Instanz gebil<strong>de</strong>t<br />
wer<strong>de</strong>n. Sie darf ke<strong>in</strong>e Implementierung e<strong>in</strong>er Metho<strong>de</strong> enthalten. In e<strong>in</strong>er abstrakten<br />
Klasse gibt es m<strong>in</strong><strong>de</strong>stens e<strong>in</strong>e nicht vollständig angegebene Metho<strong>de</strong>.<br />
2.5.2 Generische Klassen und generische Schnittstellen<br />
2.5.2.1 Generische Typen<br />
2.5.2.1.1 Typvariable<br />
Mit <strong>Java</strong> 1.5 wird das Typsystem auf generische Typen erweitert. Die I<strong>de</strong>e für<br />
generische Typen ist es e<strong>in</strong>e Klasse zu schreiben, die für verschie<strong>de</strong>ne Typen als<br />
Inhalt zu benutzen ist. Die Speicherung beliebiger Objekte kann <strong>Java</strong> bis zur Version<br />
1.4 nur <strong>in</strong> Fel<strong>de</strong>rn vom Typ Object vollziehen. Allerd<strong>in</strong>gs geht damit die typische<br />
statische Typ<strong>in</strong>formation verloren. Dynamische Typzusicherung ist <strong>in</strong> diesem Fall für<br />
weitere s<strong>in</strong>nvolle Nutzung <strong>de</strong>r Objekte unerläßich. Dynamische Typzusicherung kann<br />
aber zu Laufzeitfehlern führen:<br />
Bsp. 174 :<br />
class AlteSchachtel<br />
{<br />
Object <strong>in</strong>halt;<br />
AlteSchachtel(Object <strong>in</strong>halt)<br />
{<br />
this.<strong>in</strong>halt = <strong>in</strong>halt;<br />
}<br />
}<br />
public class AnwAlteSchachtel<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
AlteSchachtel b = new AlteSchachtel("Hallo");<br />
Str<strong>in</strong>g s = (Str<strong>in</strong>g) b.<strong>in</strong>halt;<br />
System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
System.out.pr<strong>in</strong>tln(((Str<strong>in</strong>g) s).toUpperCase());<br />
}<br />
}<br />
Wann auch immer mit <strong>in</strong>halt gearbeitet wird, e<strong>in</strong>e Typzusicherung während <strong>de</strong>r Laufzeit ist<br />
durchzuführen. Das kann zu Laufzeitfehlern führen. So übersetzt das folgen<strong>de</strong> Programm fehlerfrei<br />
gibt aber e<strong>in</strong>en Laufzeitfehler.<br />
174 pr25210<br />
189
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public class AnwAlteSchachtelFehler<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
AlteSchachtel b = new AlteSchachtel(new Integer(42));<br />
Str<strong>in</strong>g s = (Str<strong>in</strong>g) b.<strong>in</strong>halt;<br />
System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
}<br />
}<br />
Das vorliegen<strong>de</strong> Bsp. zeigt: Sobald <strong>de</strong>r Typ Object benutzt wird gibt es e<strong>in</strong>en<br />
Verlust an Typsicherheit, sobald <strong>de</strong>r Typ Object benutzt wird.<br />
Wie kann man Klassen schreiben, die statische Typsicherheit garantieren? Im<br />
vorliegen<strong>de</strong>n Beispiel braucht man nur je<strong>de</strong>s Auftreten <strong>de</strong>s Typs Object durch e<strong>in</strong>en<br />
Variablennamen zu ersetzen. Die Variable ist e<strong>in</strong>e Typvariable, sie steht für e<strong>in</strong>en<br />
beliebigen Typ. Dem Klassennamen wird zusätzlich <strong>in</strong> <strong>de</strong>r Klassen<strong>de</strong>f<strong>in</strong>ition, <strong>in</strong><br />
spitzen Klammern e<strong>in</strong>geschlossen, h<strong>in</strong>zugefügt, dass diese Klasse e<strong>in</strong>e Typvariable<br />
benutzt.<br />
class Schachtel <br />
{<br />
elementType <strong>in</strong>halt;<br />
Schachtel(elementType <strong>in</strong>halt)<br />
{<br />
this.<strong>in</strong>halt = <strong>in</strong>halt;<br />
}<br />
}<br />
Die Typvariable elementType ist allqualifiziert. Für je<strong>de</strong>n Typ elementType kann die<br />
Klasse Schachtel verwen<strong>de</strong>t wer<strong>de</strong>n, z.B.:<br />
Schachtel zur Speicherung von Str<strong>in</strong>gs<br />
Schachtel zur Speicherung von Integer-Objekte<br />
Bsp. 175 :<br />
public class AnwSchachtel<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Schachtel b1 = new Schachtel("Hallo");<br />
Str<strong>in</strong>g s = b1.<strong>in</strong>halt;<br />
System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
System.out.pr<strong>in</strong>tln(b1.<strong>in</strong>halt.toUpperCase());<br />
Schachtel b2 = new Schachtel(new Integer(42));<br />
System.out.pr<strong>in</strong>tln(b2.<strong>in</strong>halt.<strong>in</strong>tValue());<br />
}<br />
}<br />
175 pr25210<br />
190
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Da mit generischen Typen ke<strong>in</strong>e Typzusicherungen mehr vorzunehmen s<strong>in</strong>d, gibt es<br />
hier auch ke<strong>in</strong>e dynamischen Typfehler mehr. Laufzeitfehler, wie sie ohne die<br />
"generische Schachtel" aufgetreten s<strong>in</strong>d, wer<strong>de</strong>n jetzt bereits zur Übersetzungszeit<br />
ent<strong>de</strong>ckt.<br />
Bsp. 176 :<br />
public class AnwSchachtelFehler<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Schachtel b = new Schachtel(new Integer(42));<br />
Str<strong>in</strong>g s = b.<strong>in</strong>halt;<br />
System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
}<br />
}<br />
AnwSchachtelFehler.java: 5 cannot f<strong>in</strong>d symbol<br />
Kovarianz gegen Kontravarianz: Das folgen<strong>de</strong> Programm führt auf e<strong>in</strong>en Fehler<br />
class Kontra<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Schachtel s = new Schachtel("Hallo");<br />
}<br />
}<br />
E<strong>in</strong>e Schachtel ist ke<strong>in</strong>e Schachtel. Der Grund dafür ist,<br />
dass bestimmte Laufzeitfehler vermie<strong>de</strong>n wer<strong>de</strong>n sollen. Betrachtet man e<strong>in</strong> Objekt<br />
<strong>de</strong>s Typs Schachtel über e<strong>in</strong>e Referenz <strong>de</strong>s Typs<br />
Schachtel, dann können <strong>in</strong> <strong>de</strong>m Feld <strong>in</strong>halt beliebige Objekte<br />
gespeichert wer<strong>de</strong>n. Die Referenz über <strong>de</strong>n Typ Box geht davon aus,<br />
dass <strong>in</strong> <strong>in</strong>halt nur Str<strong>in</strong>gobjekte gespeichert wer<strong>de</strong>n.<br />
Reihungen (arrays) verhalten sich <strong>in</strong> <strong>Java</strong> an<strong>de</strong>rs. Bei Reihungen ist die<br />
entsprechen<strong>de</strong> Zuweisung erlaubt. E<strong>in</strong>e Reihung von Str<strong>in</strong>gobjekten darf e<strong>in</strong>er<br />
Reihung beliebiger Objekte zugewiesen wer<strong>de</strong>n. Dann kann es bei <strong>de</strong>r Benutzung<br />
e<strong>in</strong>er Reihung von Objekten zu e<strong>in</strong>em Laufzeitfehler kommen.<br />
176 pr25210<br />
191
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.5.2.1.2 Vererbung<br />
Von generischen Klassen lassen sich Subklassen <strong>de</strong>f<strong>in</strong>ieren. Diese Subklassen<br />
können, müssen aber nicht selbst generische Klassen se<strong>in</strong>.<br />
Bsp. 177 : Erweiterung <strong>de</strong>r Schachtelklasse, so dass 2 Objekte gespeichert wer<strong>de</strong>n<br />
können.<br />
class Paar extends Schachtel<br />
{<br />
bt zweites;<br />
Paar(at x , bt y)<br />
{<br />
super(x); public class AnwPaar<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
Paar p =<br />
new Paar("Hallo",new Integer(40));<br />
System.out.pr<strong>in</strong>tln(p);<br />
System.out.pr<strong>in</strong>tln(p.<strong>in</strong>halt.toUpperCase());<br />
System.out.pr<strong>in</strong>tln(p.zweites.<strong>in</strong>tValue() + 2);<br />
}<br />
}<br />
Die Klasse Paar hat zwei Typvariablen. Instanzen von Paar müssen angeben von welchem Typ die<br />
bei<strong>de</strong>n zu speichern<strong>de</strong>n Objekte se<strong>in</strong> sollen.<br />
public class AnwPaar<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
Paar p =<br />
new Paar("Hallo",new Integer(40));<br />
System.out.pr<strong>in</strong>tln(p);<br />
System.out.pr<strong>in</strong>tln(p.<strong>in</strong>halt.toUpperCase());<br />
System.out.pr<strong>in</strong>tln(p.zweites.<strong>in</strong>tValue() + 2);<br />
}<br />
}<br />
Es können auch Subklassen durch Zusammenfassen mehrerer Typvariablen gebil<strong>de</strong>t<br />
wer<strong>de</strong>n, z.B. 178 :<br />
class UniPaar extends Paar<br />
{<br />
UniPaar(at x,at y)<br />
{<br />
super(x,y);<br />
}<br />
void tausch()<br />
{<br />
f<strong>in</strong>al at z = zweites;<br />
zweites = <strong>in</strong>halt;<br />
<strong>in</strong>halt = z;<br />
}<br />
}<br />
Wie man sieht, s<strong>in</strong>d Typvariablen wie bisherige Typen zu benutzen. Sie können als Typ für lokale<br />
Variable o<strong>de</strong>r Parameter genutzt wer<strong>de</strong>n.<br />
177 pr25210<br />
178 pr25210<br />
192
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public class AnwUniPaar<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
UniPaar p = new UniPaar("welt","hallo");<br />
System.out.pr<strong>in</strong>tln(p);<br />
p.tausch();<br />
System.out.pr<strong>in</strong>tln(p);<br />
}<br />
}<br />
Man kann auch Subklassen e<strong>in</strong>er generischen Klasse bil<strong>de</strong>n, die nicht mehr<br />
generisch ist. So lässt sich bspw. 179 die Klasse Schachtel zu e<strong>in</strong>er Klasse erweitern,<br />
<strong>in</strong> <strong>de</strong>r nur noch Str<strong>in</strong>gobjekte verpackt wer<strong>de</strong>n dürfen:<br />
class Str<strong>in</strong>gSchachtel extends Schachtel<br />
{<br />
Str<strong>in</strong>gSchachtel(Str<strong>in</strong>g x)<br />
{<br />
super(x);<br />
}<br />
}<br />
Diese Klasse kann nun vollkommen ohne spitze Klammern benutzt wer<strong>de</strong>n:<br />
public class AnwStr<strong>in</strong>gSchachtel<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
Schachtel b = new Str<strong>in</strong>gSchachtel("Hallo");<br />
System.out.pr<strong>in</strong>tln(b.<strong>in</strong>halt);<br />
}<br />
}<br />
2.5.2.1.3 E<strong>in</strong>schränkung <strong>de</strong>r Typvariablen<br />
Bei <strong>de</strong>r Def<strong>in</strong>ition e<strong>in</strong>er Schablone können Typen e<strong>in</strong>geschränkt wer<strong>de</strong>n. Es kann<br />
e<strong>in</strong>geschränkt wer<strong>de</strong>n, dass e<strong>in</strong>e Typvariable nicht für alle Typen ersetzt wer<strong>de</strong>n<br />
darf, son<strong>de</strong>r nur für bestimmte Typen. Somit kann bspw. vorgeschrieben wer<strong>de</strong>n,<br />
dass <strong>de</strong>r Typ e<strong>in</strong>e konkrete Schnittstelle verwen<strong>de</strong>n muß.<br />
Bsp. 180 : Erweiterung <strong>de</strong>r Klasse Schachtel mit e<strong>in</strong>er set()-Metho<strong>de</strong>, die nur e<strong>in</strong>en<br />
neuen Wert <strong>in</strong> das entsprechen<strong>de</strong> Objekt speichert, wenn es größer ist als das<br />
bereits gespeicherte Objekt.<br />
Hierzu müssen die zu speichern<strong>de</strong>n Objekte <strong>in</strong> e<strong>in</strong>er Ordnungsrelation vergleichbar se<strong>in</strong>, was <strong>in</strong> <strong>Java</strong><br />
über die Implementierung <strong>de</strong>r Schnittstelle Comparable ausgedrückt wird.<br />
class SammleMaxAlt<br />
{<br />
private Comparable wert;<br />
SammleMaxAlt(Comparable x)<br />
{ wert = x; }<br />
void setWert(Comparable x)<br />
{ if (wert.compareTo(x) < 40) wert = x; }<br />
Comparable getWert() { return wert; }<br />
179 pr25210<br />
180 pr25210<br />
193
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
Die Klasse SammleMaxAlt ist <strong>in</strong> <strong>de</strong>r Lage beliebige Objekte, die die Schnittstelle Comparable<br />
implementieren, zu speichern. Es besteht aber folgen<strong>de</strong>s Problem: Greift man auf das gespeicherte<br />
Objekt mit <strong>de</strong>r Metho<strong>de</strong> getWert() erneut zu, dann ist <strong>de</strong>r genaue Wert dieses Objekts nicht mehr<br />
bekannt. Evtl. ist e<strong>in</strong>e dynmische Typzusicherung notwendig, die zu Laufzeitfehlern führen kann.<br />
Die generischen Typen von <strong>Java</strong> 1.5 können dieses Problem beheben, <strong>in</strong><strong>de</strong>m man <strong>de</strong>n allgeme<strong>in</strong>en<br />
Typ Object durch e<strong>in</strong>e Typvariable ersetzt, die Subtypen <strong>de</strong>r Schnittstelle Comparable s<strong>in</strong>d. Dies<br />
wird durch e<strong>in</strong>e zusätzliche extends-Klausel für die Typvariable angegeben.<br />
class SammleMax <br />
{<br />
private elementType wert;<br />
SammleMax(elementType x) { wert = x; }<br />
void setWert(elementType x)<br />
{<br />
if (wert.compareTo(x) < 0) wert = x;<br />
}<br />
elementType getWert() { return wert; }<br />
}<br />
Für die Benutzung <strong>de</strong>r Klasse ist jetzt für je<strong>de</strong> konkrete Instanz <strong>de</strong>r konkrete Typ <strong>de</strong>s gespeicherten<br />
Objekts anzugeben. Die Metho<strong>de</strong> getWert() liefert als Rückgabetyp nicht e<strong>in</strong> allgeme<strong>in</strong>es Objekt<br />
<strong>de</strong>s Typs Comparable, son<strong>de</strong>rn exakt e<strong>in</strong> Typ <strong>de</strong>s Instanztyps.<br />
class AnwSammleMax<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
SammleMax sm = new SammleMax("Brecht");<br />
sm.setWert("Cal<strong>de</strong>ron");<br />
sm.setWert("Shakespeare");<br />
sm.setWert("Goethe");<br />
sm.setWert("Schiller");<br />
System.out.pr<strong>in</strong>tln(sm.getWert().toUpperCase());<br />
}<br />
}<br />
Wie man <strong>in</strong> <strong>de</strong>r letzten Zeile sieht, entfällt wie<strong>de</strong>r die dynamische Typzusicherung.<br />
2.5.2.2 Generische Schnittstellen<br />
Generische Typen erlauben es, <strong>de</strong>n Typ Object <strong>in</strong> Typsignaturen zu elim<strong>in</strong>ieren.<br />
Der Typ Object ist als schlecht anzusehen, <strong>de</strong>nn er ist gleichbe<strong>de</strong>utend damit, dass<br />
ke<strong>in</strong>e Information über e<strong>in</strong>en konkreten Typ während <strong>de</strong>r Übersetzungszeit zur<br />
Verfügung steht. In herkömmlichen <strong>Java</strong> ist <strong>in</strong> APIs von Bibliotheken <strong>de</strong>r Typ Object<br />
allgegenwärtig. Sogar <strong>in</strong> <strong>de</strong>r Klasse Object selbst f<strong>in</strong><strong>de</strong>t man diesen Typ <strong>in</strong><br />
Signaturen, z.B. <strong>in</strong> <strong>de</strong>r Metho<strong>de</strong> equals(). Pr<strong>in</strong>zipiell kann <strong>de</strong>shalb e<strong>in</strong> Objekt mit<br />
Objekten je<strong>de</strong>s beliebigen Typs verglichen wer<strong>de</strong>n. Häufig will man aber nur gleiche<br />
Typen mite<strong>in</strong>an<strong>de</strong>r vergleichen. Generische Typen erlauben es, allgeme<strong>in</strong> e<strong>in</strong>e<br />
Gleichheitsmetho<strong>de</strong> zu <strong>de</strong>f<strong>in</strong>ieren, <strong>in</strong> <strong>de</strong>r nur Objekte gleichen Typs mite<strong>in</strong>an<strong>de</strong>r<br />
verglichen wer<strong>de</strong>n können.<br />
Generische Typen erweitern sich ohne Umstän<strong>de</strong> auf Schnittstellen. Speziell für<br />
Gleichheit könnte e<strong>in</strong>e <strong>de</strong>rartige Schnittstelle so aussehen:<br />
<strong>in</strong>terface EQ<br />
{ public boolean eq(otherType other); }<br />
194
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp.: Äpfel mit Äpfel vergleichen<br />
Dazu <strong>de</strong>f<strong>in</strong>iert man <strong>in</strong> <strong>de</strong>r implements-Klausel, dass EQ implementiert wird.<br />
class Apfel implements EQ<br />
{<br />
Str<strong>in</strong>g typ;<br />
Apfel(Str<strong>in</strong>g typ)<br />
{<br />
this.typ=typ;<br />
}<br />
public boolean eq(Apfel other)<br />
{<br />
return this.typ.equals(other.typ);<br />
}<br />
}<br />
Jetzt können erst e<strong>in</strong>mal "Äpfel" mit "Äpfel" verglichen wer<strong>de</strong>n.<br />
class TestEq<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Apfel a1 = new Apfel("Gol<strong>de</strong>n Delicious");<br />
Apfel a2 = new Apfel("Mac<strong>in</strong>tosh");<br />
System.out.pr<strong>in</strong>tln(a1.eq(a2));<br />
System.out.pr<strong>in</strong>tln(a1.eq(a1));<br />
}<br />
}<br />
Der folgen<strong>de</strong> Vergleich führt zu e<strong>in</strong>em Fehler beim Übersetzen 181 :<br />
class TesteEqError<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g []args)<br />
{<br />
Apfel a = new Apfel("Gol<strong>de</strong>n Delicious");<br />
Birne b = new Birne("williams");<br />
System.out.pr<strong>in</strong>tln(a.equals(b));<br />
System.out.pr<strong>in</strong>tln(a.eq(b));<br />
}<br />
}<br />
Die Schnittstelle EQ wird nun auch für die Klasse Birne implementiert<br />
class Birne implements EQ<br />
{<br />
Str<strong>in</strong>g typ;<br />
Birne(Str<strong>in</strong>g typ)<br />
{<br />
this.typ=typ;<br />
}<br />
public boolean eq(Birne other)<br />
{<br />
return this.typ.equals(other.typ);<br />
}<br />
}<br />
Während <strong>de</strong>s statischen Typchecks wird überprüft, ob Äpfel mit Äpfeln und Birne mit Birnen<br />
verglichen wer<strong>de</strong>n. Der Versuch Äpfel mit Birnen zu vergleichen, führt zu e<strong>in</strong>em Typfehler.<br />
181 eq(Apfel) <strong>in</strong> Apfel cannot be applied to (Birne)<br />
195
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Der statische TypCheck stellt auch sicher, dass e<strong>in</strong>e generische Schnittstelle mit <strong>de</strong>r korrekten<br />
Typsignatur implementiert wird. Der Versuch e<strong>in</strong>e "Birnenklasse" zu schreiben, die e<strong>in</strong>e Gleichheit mit<br />
Äpfeln implementieren soll, dann aber die Metho<strong>de</strong> "eq" mit <strong>de</strong>m Parametertyp "Birne" zu<br />
implemntieren, führt zu e<strong>in</strong>er Fehlermeldung 182 :<br />
class BirneError implements EQ<br />
{<br />
Str<strong>in</strong>g typ;<br />
BirneError(Str<strong>in</strong>g typ)<br />
{<br />
this.typ=typ;<br />
}<br />
public boolean eq(Birne other)<br />
{<br />
return this.typ.equals(other.typ);<br />
}<br />
}<br />
2.6 Metho<strong>de</strong>n<br />
2.6.1 Die Deklaration<br />
Die Deklarationen von Metho<strong>de</strong>n haben folgen<strong>de</strong>s Aussehen 183 :<br />
Zugriffsspezifizierer Modifizierer Returnwert NameMetho<strong>de</strong>(Parameter)<br />
throws Exceptionliste<br />
Metho<strong>de</strong>nunterschrift 184 . Unter Unterschrift e<strong>in</strong>er Metho<strong>de</strong> versteht man e<strong>in</strong>e<br />
Komb<strong>in</strong>ation aus Teilen <strong>de</strong>r Def<strong>in</strong>ition: <strong>de</strong>m Namen <strong>de</strong>r Metho<strong>de</strong>, <strong>de</strong>m Rückgabetyp<br />
und <strong>de</strong>n verschie<strong>de</strong>nen Parametern.<br />
2.6.2 Die Zugriffsspezifizierung<br />
Freundliche Metho<strong>de</strong>n – <strong>de</strong>r vore<strong>in</strong>gestellte Defaultstatus.<br />
Öffentliche Metho<strong>de</strong>n – <strong>de</strong>r Zugriffsspezifizierer public.<br />
Geschützt Metho<strong>de</strong>n – <strong>de</strong>r Zugriffsspezifizierer protected.<br />
Prvate Metho<strong>de</strong>n – <strong>de</strong>r Zugriffsspezifizierer private.<br />
Privat geschützt – die Zugriffsspezifizierer private und protected <strong>in</strong> Komb<strong>in</strong>ation.<br />
Metho<strong>de</strong>n, die als private protected <strong>de</strong>klariert wur<strong>de</strong>n, s<strong>in</strong>d sowohl für e<strong>in</strong>e<br />
Klasse als auch für e<strong>in</strong>e Subklasse vefügbar, aber nicht für <strong>de</strong>n Rest <strong>de</strong>s Pakets<br />
o<strong>de</strong>r auch für Klassen außerhalb <strong>de</strong>s Pakets. Das be<strong>de</strong>utet: Subklassen e<strong>in</strong>er<br />
182 BirneFehler is not abstract and does not overri<strong>de</strong> abstract method<br />
eq(Apfel) <strong>in</strong> EQ<br />
183 Kursiv Geschriebenes ist optional<br />
184 Oft wird für <strong>de</strong>nselben Zusammenhang <strong>de</strong>r Begriff „Metho<strong>de</strong>nsignatur“ verwen<strong>de</strong>t.<br />
196
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
gegebenen Klasse können Metho<strong>de</strong>n, die private protected <strong>de</strong>klariert wur<strong>de</strong>n<br />
aufrufen. Instanzen <strong>de</strong>r Subklasse können dies aber nicht.<br />
2.6.3 Die Metho<strong>de</strong>nmodifizierer<br />
Klassenmetho<strong>de</strong>n – <strong>de</strong>r Modifizierer static.<br />
Abstrakte Metho<strong>de</strong>n – <strong>de</strong>r Modifizierer abstract<br />
F<strong>in</strong>ale Metho<strong>de</strong>n – <strong>de</strong>r Modifizierer f<strong>in</strong>al. Das Schlüsselwort f<strong>in</strong>al vor e<strong>in</strong>er<br />
Metho<strong>de</strong>n<strong>de</strong>klaration verh<strong>in</strong><strong>de</strong>rt, daß irgendwelche Subklassen die <strong>de</strong>rzeitige Klasse<br />
dieser Metho<strong>de</strong> überschreiben. Metho<strong>de</strong>n, die auf ke<strong>in</strong>em Fall geän<strong>de</strong>rt wer<strong>de</strong>n<br />
sollen, sollten <strong>de</strong>shalb immer als f<strong>in</strong>al <strong>de</strong>klariert wer<strong>de</strong>n.<br />
Native Metho<strong>de</strong>n – <strong>de</strong>r Modifizierer native. Native Metho<strong>de</strong>n s<strong>in</strong>d Metho<strong>de</strong>n, die<br />
nicht <strong>in</strong> <strong>Java</strong> geschrieben s<strong>in</strong>d, aber <strong>de</strong>nnoch <strong>in</strong>nerhalb von <strong>Java</strong> verwen<strong>de</strong>t wer<strong>de</strong>n<br />
sollen. Der Modifizierer native wird vor <strong>de</strong>r Metho<strong>de</strong> <strong>de</strong>klariert, <strong>de</strong>r Body (Körper) <strong>de</strong>r<br />
Metho<strong>de</strong> wird durch e<strong>in</strong> Semikolon ersetzt.<br />
Metho<strong>de</strong>n synchronisieren – <strong>de</strong>r Modifizierer synchronized. Wird das<br />
Schlüsselwort sychronized vor e<strong>in</strong>e Metho<strong>de</strong>n<strong>de</strong>klaration gesetzt, dann wer<strong>de</strong>n<br />
Datenverletzungen verh<strong>in</strong><strong>de</strong>rt, die entstehen können, wenn zwei Metho<strong>de</strong>n<br />
gleichzeitig versuchen auf dieselben Daten zuzugreifen.<br />
2.6.4 Rückgabewerte von Metho<strong>de</strong>n<br />
Rückgabewerte von<strong>Java</strong>-Metho<strong>de</strong>n können von je<strong>de</strong>m erlaubten Datentyp 185 se<strong>in</strong>.<br />
E<strong>in</strong>e Metho<strong>de</strong> muß immer e<strong>in</strong>en Wert zurückgeben (und zwar genau <strong>de</strong>n Datentyp,<br />
<strong>de</strong>r <strong>in</strong> <strong>de</strong>r Deklaration angegeben wur<strong>de</strong>), es sei <strong>de</strong>nn, sie wur<strong>de</strong> mit void <strong>de</strong>klariert.<br />
Die Metho<strong>de</strong> hat dann ke<strong>in</strong>en Rückgabewert.<br />
2.6.5 Metho<strong>de</strong>nname und Parameterliste<br />
Bzgl. <strong>de</strong>r Metho<strong>de</strong>nnamen gelten die gleichen Regeln wie bei allen Token.<br />
E<strong>in</strong>e Parameterliste hat folgen<strong>de</strong> Struktur: Datentyp variablenname, Datentyp<br />
variablenname, .... . Die Anzahl <strong>de</strong>r Parameter ist beliebig und kann Null se<strong>in</strong>.<br />
185 Nicht nur primitive Datentypen, son<strong>de</strong>rn auch komplexe Objekte.<br />
197
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.6.6 Variable Parameteranzahl<br />
Mit <strong>Java</strong> 1.5 können Metho<strong>de</strong>n mit e<strong>in</strong>er variablen Anzahl von Parametern <strong>de</strong>f<strong>in</strong>iert<br />
wer<strong>de</strong>n. Sie wer<strong>de</strong>n durch Punkte nach <strong>de</strong>m Paramtertyp <strong>in</strong> <strong>de</strong>r Signatur<br />
gekennzeichnet. Damit wird angezeigt: Es kann e<strong>in</strong>e beliebige Anzahl dieser<br />
Parameter bei e<strong>in</strong>em Metho<strong>de</strong>naufruf geben.<br />
Bsp.:<br />
public class VarParams<br />
{<br />
public static Str<strong>in</strong>g append(Str<strong>in</strong>g ... argumente)<br />
{<br />
Str<strong>in</strong>g result = "";<br />
for (Str<strong>in</strong>g a : argumente)<br />
result += a;<br />
return result;<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
System.out.pr<strong>in</strong>tln(append("Hallo"," ","Welt"));<br />
}<br />
}<br />
2.6.7 Rekursion<br />
2.6.7.1 Rekursive Funktionen<br />
E<strong>in</strong>e Funktion ist rekursiv, falls die Ausführung <strong>de</strong>s Rumpfs <strong>de</strong>r Funktion wie<strong>de</strong>rum<br />
zum Aufruf <strong>de</strong>r Funktion führt. Man unterschei<strong>de</strong>t<br />
Direkte Rekursion (E<strong>in</strong>e Funktion ruft sich selbst im Rumpf auf)<br />
und<br />
Indirekte Rekursion (Der rekursive Aufruf befi<strong>de</strong>t sich nicht im Funktionsrumpf. So ruft bspw. e<strong>in</strong>e<br />
Funktion A e<strong>in</strong>e Funktion B auf und diese startet <strong>in</strong> ihrem Rumpf die Funktion A).<br />
Wie Wie<strong>de</strong>rholungsanweisungen neigen auch rekursive Funktionen zur Gefahr nicht<br />
abbrechbarer Berechnungen. E<strong>in</strong>e Term<strong>in</strong>ierung ist unbed<strong>in</strong>gt erfor<strong>de</strong>rlich. Das<br />
geschieht über e<strong>in</strong>e Bed<strong>in</strong>gung von <strong>de</strong>r <strong>de</strong>r rekursive Aufruf abhängt..<br />
Bei je<strong>de</strong>r rekursiven Anwendung wird e<strong>in</strong> Satz lokaler, gebun<strong>de</strong>ner Variablen kreiert.<br />
Sie haben zwar <strong>de</strong>nselben Namen wie Objekte <strong>de</strong>s vorangegengenen Aufrufs <strong>de</strong>r<br />
Prozedur, besitzen aber verschie<strong>de</strong>ne Werte. Die Namen beziehen sich immer auf<br />
die zuletzt erzeugten Variablen.<br />
198
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2.6.7.2 Rekursion und Iteration<br />
Man kann zeigen, daß sich je<strong>de</strong>r rekursive Algorithmus <strong>in</strong> e<strong>in</strong>en iterativen<br />
umwan<strong>de</strong>ln läßt. Da die Iteration <strong>in</strong> <strong>de</strong>n meisten Fällen wesentlich effizienter ist als<br />
die die Rekursion, ist die Frage berechtigt, weshalb man überhaupt die Rekusion<br />
verwen<strong>de</strong>t. Für die Rekursion spricht:<br />
1. Es gibt bestimmte rekursiv formulierte Algorithmen, die schneller o<strong>de</strong>r wenigstens gleich<br />
schnell<br />
arbeiten als vergleichbare iterative.<br />
2. Es lassen sich viele Probleme rekursiv „sehr e<strong>in</strong>fach“ lösen.<br />
Rekursiv formulierte Algorithmen bieten sich <strong>in</strong>sbeson<strong>de</strong>re an, wenn das<br />
zugrun<strong>de</strong>liegen<strong>de</strong> Problem o<strong>de</strong>r die zu behan<strong>de</strong>ln<strong>de</strong>n Daten rekursiv <strong>de</strong>f<strong>in</strong>iert s<strong>in</strong>d.<br />
Das ist aber noch ke<strong>in</strong>e Garantie dafür, daß e<strong>in</strong> rekursiver Algorithmus auch <strong>de</strong>r<br />
beste Weg zur Lösung <strong>de</strong>s Problems ist.<br />
199
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3. Grafische Benutzeroberflächen und Applets<br />
3.1 Ereignisse <strong>in</strong> grafischen Benutzeroberflächen<br />
Mit Hilfe e<strong>in</strong>facher Benutzerschnittstellen <strong>de</strong>s Graphical User Interface (GUI))<br />
lassen sich E<strong>in</strong>- und Ausgaben 186 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 <strong>de</strong>n vom Betriebssystem registrierten<br />
Ereignisarten und Zustandsän<strong>de</strong>rungen erfolgen.<br />
3.1.1 Gestaltung von GUI mit Hilfe <strong>de</strong>r AWT-Klassen<br />
<strong>Java</strong> enthält e<strong>in</strong> e<strong>in</strong>fach zu bedienen<strong>de</strong>s System für Gestaltung grafische<br />
Benutzeroberflächen: das Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit (AWT). Die Fähigkeiten<br />
<strong>de</strong>s AWT umfassen:<br />
- Grafische Operationen zum Zeichnen von L<strong>in</strong>ien o<strong>de</strong>r Füllen von Flächen und zur Ausgabe von<br />
Text<br />
- Metho<strong>de</strong> zur Steuerung <strong>de</strong>s Programmablaufs auf <strong>de</strong>r Basis von Nachrichten für Tatstatur-,<br />
Maus- und Fensterereignisse.<br />
- Dialogelemente zur Kommunikation mit <strong>de</strong>m Anwen<strong>de</strong>r und Funktion zum Design von<br />
Dialogboxen.<br />
- Grafikfunktionen zur Darstellung von Bitmaps und Ausgabe von "Sound".<br />
Zum E<strong>in</strong>b<strong>in</strong><strong>de</strong>n <strong>de</strong>r Grafikfähigkeiten dient die Anweisung<br />
import java.awt.*;<br />
zu Beg<strong>in</strong>n <strong>de</strong>r Klassen<strong>de</strong>f<strong>in</strong>ition. Danach stehen alle Klassen aus <strong>de</strong>m 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 verschie<strong>de</strong>ne Fensterklassen:<br />
Panel<br />
Applet<br />
Component<br />
Conta<strong>in</strong>er<br />
W<strong>in</strong>dow Dialog FileDialog<br />
Frame<br />
Component<br />
Conta<strong>in</strong>er<br />
Abstrakte Klasse mit <strong>de</strong>r 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<br />
reagieren können bzw. Ereignisse sen<strong>de</strong>n können<br />
Abstrakte Klasse mit <strong>de</strong>r Aufgabe: Aufnahme von Komponenten <strong>in</strong>nerhalb an<strong>de</strong>rer<br />
Komponenten. Conta<strong>in</strong>er stellt für das H<strong>in</strong>zufügen bzw. Entfernen von<br />
Komponenten Metho<strong>de</strong>n bereit und realisiert mit Hilfe von "Layout-Manager"-<br />
186 Standar<strong>de</strong><strong>in</strong>- und Standardausgabe spielen <strong>in</strong> <strong>Java</strong> nur im Rahmen <strong>de</strong>s „Debugg<strong>in</strong>g“ e<strong>in</strong>e Rolle.<br />
201
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Klassen Positionierung und Anordnung von Komponenten.<br />
Panel<br />
Ist die konkrete Klasse mit <strong>de</strong>n Eigenschaften von Component und Conta<strong>in</strong>er. Sie<br />
erbt alle Eigenschaften von Conta<strong>in</strong>er, kann Komponenten aufnehmen und mit<br />
Hilfe <strong>de</strong>s Layoutmanagers auf <strong>de</strong>m Bildschirm anordnen.<br />
Applet Erweitert die Funktionalität <strong>de</strong>r Klasse Applet um Metho<strong>de</strong>n, die für das Ausführen<br />
von Applets von Be<strong>de</strong>utung 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> <strong>de</strong>r 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 o<strong>de</strong>r 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<br />
Menü.<br />
Dialog Realisiert modale und nicht modale Dialoge.<br />
FileDialog Stellt e<strong>in</strong> Standard-Dateidialog <strong>de</strong>s jeweiligen Systems bereit. Dieser kann beim<br />
La<strong>de</strong>n o<strong>de</strong>r Speichern e<strong>in</strong>er datei zur E<strong>in</strong>gabe o<strong>de</strong>r zur Auswahl e<strong>in</strong>es<br />
Date<strong>in</strong>amens verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Abb. Fensterklassen-Hierarchie<br />
Alle Fensterklassen s<strong>in</strong>d von e<strong>in</strong>er geme<strong>in</strong>samen abstrakten Basisklasse abgeleitet,<br />
die die Funktionalität für Aussehen, Positionierung, Ausgabe und Laufzeitverhalten(<br />
Fokus, Mauszeiger, Sichtbarkeit) bereitstellt.<br />
Component<br />
{ abstract }<br />
public Str<strong>in</strong>g getName()<br />
public void setName(Str<strong>in</strong>g name)<br />
public Conta<strong>in</strong>er getParent()<br />
public boolean conta<strong>in</strong>s(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public boolean isVisible()<br />
public void setVisible(boolean b)<br />
public boolean isEnabled()<br />
public void setEnabled(boolean b)<br />
public boolean isShow<strong>in</strong>g()<br />
public Color getForeground()<br />
public void setForeground(Color c)<br />
public Color getBackground()<br />
public void setBackground(Color c)<br />
public Font getFont()<br />
public void setFont(Font f)<br />
public Po<strong>in</strong>t getLocation()<br />
public Po<strong>in</strong>t getLocationOnScreen()<br />
public void setLocation(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public void setLocation(Po<strong>in</strong>t p)<br />
public Dimension getSize()<br />
public void setSize(<strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
public void setSize(Dimension d)<br />
public Rectangle getBounds()<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 />
public void setBounds(Rectangle r)<br />
public Graphics getGraphics()<br />
public FontMetrics getFontMetrics(Font font)<br />
public void pa<strong>in</strong>tAll(Graphics g)<br />
public void repa<strong>in</strong>t()<br />
public boolean imageUpdate(Image bild, <strong>in</strong>t flags, <strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
public Image createImage(ImageProducer erz)<br />
public Image createImage(<strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
public boolean prepareImage(Image bild, ImageObserver obs)<br />
public boolean prepareImage(Image bild, <strong>in</strong>t breite, <strong>in</strong>t hoehe, ImageObserver obs)<br />
202
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public <strong>in</strong>t checkImage(Image bild, ImageObserver obs)<br />
public <strong>in</strong>t checkImage(Image bild, <strong>in</strong>t breite, <strong>in</strong>t hoehe, ImageObserver obs)<br />
public void addComponentListener(ComponentListener l)<br />
public void removeComponentListener(ComponentListener l)<br />
public void addFocusListener(FocusListener l)<br />
public void removeFocusListener(FocusListener l)<br />
public void addKeyListener(KeyListener l)<br />
public void removeKeyListener(KeyListener l)<br />
public void addMouseListener(MouseListener l)<br />
public void removeMouseListener(MouseListener l)<br />
public void addMouseMotionListener(MouseMotionListener l)<br />
public void removeMouseMotionListener(MouseMotionListener l)<br />
public f<strong>in</strong>al void enableEvents(long eventsToEnable)<br />
public f<strong>in</strong>al void disableEvents(long eventsToDisable)<br />
protected void processComponentEvent(ComponentEvent e)<br />
protected void processFocusEvent(FocusEvent e)<br />
protected void processKeyEvent(KeyEvent e)<br />
protected void processMouseEvent(MouseEvent e<br />
protected void processMouseMotionEvent(MouseEvent e)<br />
public boolean gotFocus(Event evt) //<strong>de</strong>precated, -> processFocusEvent(FocusEvent e)<br />
public boolean lostFocus(Event evt, Object was)<br />
public void requestFocus()<br />
public void add(PopupMenu popup)<br />
public void remove(MenuComponent popup)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
……<br />
…….<br />
…….<br />
…….<br />
…….<br />
Abb.: Die Klasse Component<br />
Conta<strong>in</strong>er s<strong>in</strong>d Fenster o<strong>de</strong>r Fensterbereiche, <strong>in</strong> <strong>de</strong>nen an<strong>de</strong>re Kontrollelemente<br />
platziert wer<strong>de</strong>n können.<br />
Component<br />
Conta<strong>in</strong>er<br />
{abstract}<br />
public <strong>in</strong>t countComponents()<br />
public Component getComponent(<strong>in</strong>t n)<br />
public Components[] getComponents()<br />
public Insets getInsets()<br />
public Component add(Component comp)<br />
public void remove(Component comp)<br />
public void removeAll()<br />
public LayoutManager getLayout()<br />
public void setLayout(LayoutManager mgr)<br />
public Dimension getPreferredSize()<br />
public Dimension getM<strong>in</strong>imumSize()<br />
public Dimension getMaximumSize()<br />
public void <strong>in</strong>validate()<br />
public void pa<strong>in</strong>t(Graphics g) //conta<strong>in</strong>er<br />
public void update(Graphics g) //conta<strong>in</strong>er<br />
protected void processEvent(AWTEvent e) //conta<strong>in</strong>er<br />
public void addNotify() //conta<strong>in</strong>er<br />
203
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void removeNotify() //conta<strong>in</strong>er<br />
Abb.: Die Klasse Conta<strong>in</strong>er<br />
Zur Anzeige e<strong>in</strong>es Fensters auf <strong>de</strong>m Bildschirm muß e<strong>in</strong>e <strong>de</strong>r Fensterklassen,<br />
W<strong>in</strong>dow, Frame, Dialog, Applet, FileDialog <strong>in</strong>stanziert wer<strong>de</strong>n. Zum Ableiten<br />
e<strong>in</strong>er eigenen Fensterklasse wird <strong>in</strong> <strong>de</strong>r Regel die Klasse Frame o<strong>de</strong>r Dialog<br />
verwen<strong>de</strong>t, die beibe aus <strong>de</strong>r Klasse W<strong>in</strong>dow abgeleitet s<strong>in</strong>d.<br />
Conta<strong>in</strong>er<br />
W<strong>in</strong>dow<br />
><br />
public void show()<br />
public boolean isShow<strong>in</strong>g()<br />
public void dispose()<br />
public void pack()<br />
public void toFront()<br />
public void toBack()<br />
public void addW<strong>in</strong>dowListener(W<strong>in</strong>dowListener l)<br />
Frame<br />
Dialog<br />
public static f<strong>in</strong>al <strong>in</strong>t DEFAULT_CURSOR<br />
> ><br />
public Frame()<br />
public Dialog(Frame eltern)<br />
public Frame(Str<strong>in</strong>g titel)<br />
public Dialog(Frame eltern, boolean modal)<br />
> ><br />
public Str<strong>in</strong>g getTitle()<br />
public boolean isModal()<br />
public void setTitle(Str<strong>in</strong>g titel) public void setModal(boolean b)<br />
public MenuBar getMenuBar()<br />
public void show()<br />
public void setmenuBar(MenuBar mb)<br />
public boolean isResizable()<br />
public boolean isResizable() public void setResizable(boolean b)<br />
public void setResizable(boolean b)<br />
public void remove(MenuComponent m)<br />
Abb.: Die Klassen Frame und Dialog<br />
Bsp. 187 : E<strong>in</strong>-, Ausgabe über Textfel<strong>de</strong>r <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 bei<strong>de</strong>n Textfel<strong>de</strong>rn soll jeweils e<strong>in</strong> Label mit <strong>de</strong>r 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 wer<strong>de</strong>n <strong>in</strong> e<strong>in</strong>em Panel, das selbst wie<strong>de</strong>rum<br />
e<strong>in</strong>ziges Objekt <strong>in</strong> e<strong>in</strong>em Fenster (Frame) mit <strong>de</strong>m Titel „Echo“ ist.<br />
187 pr14160<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 />
204
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>s vorliegen<strong>de</strong>n Programms zeigt das folgen<strong>de</strong><br />
Ausgabefenster:<br />
Abb.:<br />
Das vorliegen<strong>de</strong> 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 wer<strong>de</strong>n, das zweite<br />
Textfeld ist allerd<strong>in</strong>gs nicht zugänglich. Es passiert somit nicht gera<strong>de</strong> viel. Es wer<strong>de</strong>n noch ke<strong>in</strong>e<br />
Ereignisse aufgefangen und behan<strong>de</strong>lt.<br />
- Noch nicht e<strong>in</strong>mal kann das Fenster geschlossen wer<strong>de</strong>n, und die Applikation muß (nach <strong>de</strong>m<br />
Schließen <strong>de</strong>s Frame) mit "CTRL-C" explizit abgebrochen wer<strong>de</strong>n.<br />
3.1.2 Ereignisbehandlung unter grafischen Benutzeroberflächen<br />
Im Mittelpunkt <strong>de</strong>r 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än<strong>de</strong>rungen vom System durch Versen<strong>de</strong>n von<br />
Nachrichten (z.B. über Mausklick, Tastature<strong>in</strong>gaben, Verän<strong>de</strong>rungen an Größe und<br />
Lage <strong>de</strong>r Fenster) <strong>in</strong>formiert. Die Reaktion auf die Nachrichten erfolgt <strong>in</strong> spezielllen<br />
Ereignisempfängern (EventListeners), die das zum Ereignis passen<strong>de</strong> 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 <strong>de</strong>r Quelle registrieren lassen, d.h.:<br />
Es muß e<strong>in</strong>e EventListener-Klasse geschrieben, <strong>in</strong>stanziert und bei <strong>de</strong>r<br />
Ereignisquelle registriert wer<strong>de</strong>n. Zum Empfang von Nachrichten muß e<strong>in</strong> Objekt<br />
e<strong>in</strong>e Reihe von Metho<strong>de</strong>n implementieren, die von <strong>de</strong>r Nachrichtenquelle, bei <strong>de</strong>r es<br />
sich registriert hat, aufgerufen wer<strong>de</strong>n können. Die Ereignisempfänger stellen diese<br />
Metho<strong>de</strong>n durch Implementierung von Interfaces bereit, die aus <strong>de</strong>r Klasse<br />
EventListener <strong>de</strong>s Pakets java.util abgeleitet s<strong>in</strong>d.<br />
205
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Ereignistypen. Im JDK 1.1 wer<strong>de</strong>n Ereignistypen durch e<strong>in</strong>e Hierarchie von<br />
Ereignisklassen repräsentiert, die alle aus <strong>de</strong>r Klasse java.util.EventObject 188<br />
abgeleitet s<strong>in</strong>d.<br />
188 Speichert das Objekt, das die Nachricht ausgelöst hat und gibt durch Aufruf von "public Object getSource()"<br />
das Objekt an.<br />
206
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
EventObject<br />
AWTEvent<br />
ComponentEvent ActionEvent AdjustmentEvent ItemEvent TextEvent<br />
FocusEvent InputEvent Conta<strong>in</strong>erEvent W<strong>in</strong>dowEvent<br />
KeyEvent<br />
MouseEvent<br />
Abb.: Spezifische Ereignisklassen<br />
Die Hierarchie <strong>de</strong>r AWT-spezifischen Ereignisklassen beg<strong>in</strong>nt mit <strong>de</strong>r Klasse<br />
AWTEvent und bef<strong>in</strong><strong>de</strong>t sich im Paket java.awt. AWTEvent ist Superklasse aller<br />
Ereignisklassen <strong>de</strong>s AWT, die sich im Paket java.awt.event bef<strong>in</strong><strong>de</strong>n. Dieses<br />
Paket ist <strong>in</strong> je<strong>de</strong> Klasse e<strong>in</strong>zubeziehen, die sich mit <strong>de</strong>m 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 />
<strong>de</strong>f<strong>in</strong>iert e<strong>in</strong>e seperate Metho<strong>de</strong> für je<strong>de</strong> Ereignisart <strong>de</strong>r Ereignisklasse. So besitzt<br />
bspw. das Interface MouseListener die Metho<strong>de</strong>n mouseClicked,<br />
mouseEntered, mouseExited, mousePressed und mouseReleased, die beim<br />
E<strong>in</strong>treffen <strong>de</strong>s jeweiligen Ereignis aufgerufen wer<strong>de</strong>n.<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 <strong>de</strong>r EventListener-Interfaces<br />
Je<strong>de</strong> <strong>de</strong>r Metho<strong>de</strong>n 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 Metho<strong>de</strong>n s<strong>in</strong>d vom Typ void.<br />
207
<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 <strong>de</strong>s passen<strong>de</strong>n Interface angegeben. Lokale Klassen wer<strong>de</strong>n lokal<br />
zu e<strong>in</strong>er an<strong>de</strong>ren Klasse erzeugt. Sie s<strong>in</strong>d nur <strong>in</strong>nerhalb dieser Klasse <strong>de</strong>f<strong>in</strong>iert und<br />
sichtbar. Objekte <strong>de</strong>r lokalen Klasse können nur aus <strong>de</strong>r erzeugen<strong>de</strong>n Klasse<br />
produziert wer<strong>de</strong>n. Die lokale Klasse kann aber auf alle Instanzmerkmale <strong>de</strong>r<br />
erzeugen<strong>de</strong>n Klasse zugreifen.<br />
E<strong>in</strong>e Variante lokale Klassen s<strong>in</strong>d anonyme Klassen. Sie wer<strong>de</strong>n ebenfalls lokal zu<br />
e<strong>in</strong>er an<strong>de</strong>ren Klasse erzeugt, kommen aber ohne Klassennamen aus. Dazu wer<strong>de</strong>n<br />
sie bei <strong>de</strong>r Übergabe e<strong>in</strong>es Objekts an e<strong>in</strong>e Metho<strong>de</strong> o<strong>de</strong>r als Rückgabewert e<strong>in</strong>er<br />
Metho<strong>de</strong> <strong>in</strong>nerhalb e<strong>in</strong>er e<strong>in</strong>zigen Anwendung <strong>de</strong>f<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 wer<strong>de</strong>n kann, muß sie<br />
aus e<strong>in</strong>er an<strong>de</strong>ren Klasse abgeleitet se<strong>in</strong> o<strong>de</strong>r e<strong>in</strong> bestehen<strong>de</strong>s 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 <strong>de</strong>n im Textfeld für die E<strong>in</strong>gabe angegebenen Text<br />
wie<strong>de</strong>rgeben soll, muß e<strong>in</strong> ActionListener (e<strong>in</strong>e zusätzlich <strong>in</strong>nere, anonyme Klasse) mit <strong>de</strong>r<br />
Metho<strong>de</strong> public void actionPerformed (ActionEvent a) <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n. Diese<br />
Metho<strong>de</strong> umfaßt Aufrufe <strong>de</strong>r Metho<strong>de</strong>n getText() und setText() <strong>de</strong>r 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 />
wer<strong>de</strong>n. Da die "Metho<strong>de</strong> actionPerformed" <strong>de</strong>r 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 <strong>de</strong>s 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 <strong>de</strong>r Metho<strong>de</strong> "public void<br />
w<strong>in</strong>dowClos<strong>in</strong>g(W<strong>in</strong>dowEvent e)" <strong>de</strong>f<strong>in</strong>iert und an <strong>de</strong>n "Frame" e<strong>in</strong>gekettet.<br />
Wird <strong>de</strong>r Frame geschlossen, dann wird diese Metho<strong>de</strong> aufgerufen, die über<br />
System.exit(0) die Applikation been<strong>de</strong>t.<br />
E<strong>in</strong>e Adapterklasse implementiert e<strong>in</strong> Interface mit mehreren Meho<strong>de</strong>n und erlaubt<br />
es somit abgeleiteten Klassen, nur noch die Metho<strong>de</strong>n zu überlagern, die tatsächlich<br />
von Interesse s<strong>in</strong>d. Passen<strong>de</strong> 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 <strong>de</strong>r Metho<strong>de</strong> addW<strong>in</strong>dowListener, die <strong>in</strong> <strong>de</strong>n Klassen Dialog und<br />
Frame zur Verfügung steht.<br />
Bsp. 189 : 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 />
private static TextField e<strong>in</strong>gabeTextFeld = new TextField(20);<br />
private static TextField ausgabeTextFeld = new TextField(20);<br />
189 pr14160<br />
208
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 vorliegen<strong>de</strong>n Realisierung <strong>de</strong>r 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 wer<strong>de</strong>n.<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 />
class TFL implements ActionListener<br />
209
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 wer<strong>de</strong>n.<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); panel.add(e<strong>in</strong>gabeTextFeld);<br />
panel.add(ausgabeTextFeldLabel); 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 />
210
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
211
<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 wer<strong>de</strong>n<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 <strong>de</strong>r elementaren Datentypen byte, short, <strong>in</strong>t, long,<br />
float o<strong>de</strong>r double o<strong>de</strong>r als Objekte von e<strong>in</strong>em <strong>de</strong>r Referenzdatentypen (Wrapper-<br />
Klassen) Byte, Short, Integer, Long o<strong>de</strong>r Double. Diese Klassen stellen<br />
Metho<strong>de</strong>n zur Umwandlung von numerischen Werten <strong>in</strong> Zeichenketten und<br />
umgekehrt zur Verfügung. Da nicht je<strong>de</strong> beliebige Zeichenkette als <strong>in</strong>terne<br />
Darstellung e<strong>in</strong>er Zahl <strong>in</strong>terpretiert wer<strong>de</strong>n kann, kann beim Versuch <strong>de</strong>r<br />
Umwandlung e<strong>in</strong>e NumberFormatExpression auftreten, die normalerweise mit<br />
e<strong>in</strong>er try-catch-Anweisung entsprechend behan<strong>de</strong>lt wer<strong>de</strong>n sollte.<br />
Bsp. 190 : 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 />
Label ausgabeTextFeldLabel = new Label("Ausgabestr<strong>in</strong>g:");<br />
190 pr14160<br />
212
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r Klasse ComponenEvent s<strong>in</strong>d Event-Klassen für "Low-Level"-Ereignisse<br />
abgeleitet. Sie s<strong>in</strong>d für <strong>de</strong>n Transfer von elementaren Nachrichten zuständig, die von<br />
Fenstern und Dialogelementen stammen.<br />
3.1.5.1 Component-Events<br />
Wird e<strong>in</strong>e Komponente verschoben o<strong>de</strong>r ihre Größe bzw. ihr Anzeigezustand<br />
verän<strong>de</strong>rt, dann wird e<strong>in</strong> Componen-Event generiert. Da Fenster und alle<br />
Dialogelemente aus <strong>de</strong>r 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 <strong>de</strong>s Typs ComponentEvent übergeben.<br />
ComponentEvent erweiter AWTEvent und stellt neben getID, getSource die<br />
Metho<strong>de</strong> public Component getComponent() bereit, mit <strong>de</strong>r die Komponente<br />
ermittelt wer<strong>de</strong>n kann, die die Nachricht ausgelöst hat. Die Registrierung <strong>de</strong>r<br />
Empfängerklasse erfolgt mit<br />
public void addComponentListener(ComponentListener l).<br />
Ereignismetho<strong>de</strong><br />
componentShown<br />
componentHid<strong>de</strong>n<br />
componentMoved<br />
componentResized<br />
Be<strong>de</strong>utung<br />
E<strong>in</strong>e Komponente wur<strong>de</strong> sichtbar<br />
E<strong>in</strong>e Komponente wur<strong>de</strong> unsichtbar<br />
E<strong>in</strong>e Komponente wur<strong>de</strong> verschoben<br />
Die Größe <strong>de</strong>r Komponente hat sich verän<strong>de</strong>rt<br />
Abb.: Übersicht zu <strong>de</strong>n Metho<strong>de</strong>n von ComponentListener<br />
3.1.5.2 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 Än<strong>de</strong>rung<br />
ergeben hat, die für das Anwen<strong>de</strong>rprogramm <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 Metho<strong>de</strong> public W<strong>in</strong>dow<br />
getW<strong>in</strong>dow() zur Verfügung, mit <strong>de</strong>r das Fenster ermittelt wer<strong>de</strong>n kann, das die<br />
Nachricht ausgelöst hat. Die Registrierung <strong>de</strong>r Empfängerklasse erfolgt über die<br />
213
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Metho<strong>de</strong> public void addW<strong>in</strong>dowListener(W<strong>in</strong>dowListener l) , die <strong>in</strong> <strong>de</strong>n<br />
Klassen Dialog und Frame zur Verfügung steht.<br />
Ereignismetho<strong>de</strong> Be<strong>de</strong>utung<br />
w<strong>in</strong>dowActivated Das Fenster wur<strong>de</strong> aktiviert. Die Metho<strong>de</strong> wird nach <strong>de</strong>m Erstellen <strong>de</strong>s<br />
Fensters aufgerufen und wenn e<strong>in</strong> Fenster, das im H<strong>in</strong>tergrund stand,<br />
erneut <strong>in</strong> <strong>de</strong>n Vor<strong>de</strong>rgrund gelangt.<br />
w<strong>in</strong>dowClosed<br />
Das Fenster wur<strong>de</strong> geschlossen<br />
w<strong>in</strong>dowClos<strong>in</strong>g Das Fenster soll geschlossen wer<strong>de</strong>n. Diese Metho<strong>de</strong> wird aufgerufen,<br />
wenn <strong>de</strong>r Anwen<strong>de</strong>r das Fenster über die TitelLeiste, das Systemmenü<br />
o<strong>de</strong>r die Tastenkomb<strong>in</strong>ation ALT+F4 schließen will. Die Anwendung hat<br />
<strong>de</strong>n Co<strong>de</strong> bereit zu stellen, <strong>de</strong>r das Fenster schließt. Standardmäßig<br />
reagiert das Programm nicht auf diese Benutzeraktionen<br />
w<strong>in</strong>dowDeactivated Das Fenster wur<strong>de</strong> <strong>de</strong>aktiviert, also <strong>in</strong> <strong>de</strong>n H<strong>in</strong>tergrung gestellt<br />
w<strong>in</strong>dowDeiconified Das Fenster wur<strong>de</strong> wie<strong>de</strong>rhergestellt, nach<strong>de</strong>m es zuvor auf<br />
Symbolgröße verkle<strong>in</strong>ert wur<strong>de</strong><br />
w<strong>in</strong>dowIconified Das Fenster wur<strong>de</strong> auf Symbolgröße verkle<strong>in</strong>ert<br />
w<strong>in</strong>dowOpened<br />
Das Fenster wur<strong>de</strong> geöffnet.<br />
Abb.: Übersicht zu <strong>de</strong>n Metho<strong>de</strong>n von W<strong>in</strong>dowListener<br />
3.1.5.3 Mouse-Events<br />
E<strong>in</strong> Mouse-Event entsteht, wenn <strong>de</strong>r Anwen<strong>de</strong>r (<strong>in</strong>nerhalb <strong>de</strong>r Client-Area <strong>de</strong>s<br />
Fensters) e<strong>in</strong>e <strong>de</strong>r Maustasten drückt o<strong>de</strong>r losläßt. Dabei reagiert das Programm<br />
sowohl auf Klicks <strong>de</strong>r l<strong>in</strong>ken als auch <strong>de</strong>r ( - falls vorhan<strong>de</strong>n -) <strong>de</strong>r rechten Maustaste<br />
und zeigt an, welche <strong>de</strong>r Umschalttasten STRG, ALT, UMSCHALT o<strong>de</strong>r META<br />
während <strong>de</strong>s Mausklicks gedrückt waren. Es ist möglich zwischen e<strong>in</strong>fachen o<strong>de</strong>r<br />
doppelten Mausklicks zu unterschei<strong>de</strong>n. 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 Metho<strong>de</strong>n bereit. Die Registrierung <strong>de</strong>r 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 />
Ereignismetho<strong>de</strong> Be<strong>de</strong>utung<br />
mousePressed Die Maustaste wur<strong>de</strong> gedrückt<br />
mouseReleased Die gedrückte Maustaste wur<strong>de</strong> losgelassen<br />
mouseClicked E<strong>in</strong>e Maustaste wur<strong>de</strong> gedrückt und wie<strong>de</strong>r losgelassen. Die Metho<strong>de</strong> wird<br />
nach mouseReleased aufgerufen.<br />
mouseEntered Der Mauszeiger wur<strong>de</strong> <strong>in</strong> <strong>de</strong>n Client-Bereich <strong>de</strong>r auslösen<strong>de</strong>n<br />
Komponente h<strong>in</strong>e<strong>in</strong>bewegt<br />
mouseExited<br />
Der Mauszeiger wur<strong>de</strong> aus <strong>de</strong>m Client-Bereich <strong>de</strong>r auslösen<strong>de</strong>n<br />
Komponente herausbewegt.<br />
Abb.: Übersicht zu <strong>de</strong>n Metho<strong>de</strong>n von MouseListener<br />
Die Ermittlung <strong>de</strong>r Position <strong>de</strong>s 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 <strong>de</strong>s Punkts, an <strong>de</strong>m<br />
sich <strong>de</strong>r Mauszeiger beim Auftreten <strong>de</strong>s Ereignisses bef<strong>in</strong><strong>de</strong>t */<br />
ermittelt wer<strong>de</strong>n. Koord<strong>in</strong>atenwerte wer<strong>de</strong>n relativ zum Ursprung <strong>de</strong>r auslösen<strong>de</strong>n<br />
Komponente angegeben.<br />
214
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Weiterh<strong>in</strong> gibt es <strong>in</strong> MouseEvent die Metho<strong>de</strong> public boolean<br />
isPopupTrigger(). Darüber kann abgefragt wer<strong>de</strong>n, ob das Klickereignis <strong>de</strong>n<br />
Ausruf e<strong>in</strong>es Popup-Menüs anzeigen soll. Die Metho<strong>de</strong> public <strong>in</strong>t<br />
getClickCount() liefert die Anzahl <strong>de</strong>r Mausklicks.<br />
Für die Beabeitung von Mouse-Events stehen außer<strong>de</strong>m die aus InputEvent<br />
191 geerbten Metho<strong>de</strong>n<br />
public boolean isShiftDown();<br />
public boolean isControlDown();<br />
public boolean isMetaDown();<br />
public boolean isAltDown();<br />
zur Verfügung.<br />
3.1.5.4 MouseMotion-Events<br />
Sie geben Auskunft über die Bewegung <strong>de</strong>s 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 Metho<strong>de</strong> steht allen Objekten <strong>de</strong>r Klasse Component o<strong>de</strong>r daraus<br />
abgeleiteteter Klassen zur Verfügung. Die Metho<strong>de</strong>n von MouseMotionListener<br />
bekommen Events <strong>de</strong>s Typs MouseEvent übergeben. Damit stehen diesselben<br />
Metho<strong>de</strong>n wie bei MouseEvent zur Verfügung.<br />
Das Interface MouseMotionListener <strong>de</strong>f<strong>in</strong>iert<br />
public abstract void mouseMoved(MouseEvent e);<br />
// Aufruf bei Bewegung e<strong>in</strong>er Maus ohne Drücken <strong>de</strong>r Maustaste<br />
public abstract void mouseDragged(MouseEvent e);<br />
/* Aufruf bei Bewegung <strong>de</strong>r Maus und gedrückter rechter o<strong>de</strong>r l<strong>in</strong>ker<br />
Maustaste */<br />
3.1.5.5 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 <strong>de</strong>n 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 <strong>de</strong>n Fokus erhalten, <strong>de</strong>nn je<strong>de</strong>s 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 <strong>de</strong>s Typs FocusEvent übergeben.<br />
FocusEvent erweitert ComponentEvent und stellt neben getID(), getSource()<br />
die Metho<strong>de</strong> public boolean isTemporary() bereit. Sie zeigt an, ob <strong>de</strong>r<br />
Fokuswechsel temporär o<strong>de</strong>r permanent ist. Die Registrierung von Focus-Events<br />
erfolgt über public void addFocusListener(FocusListener l), die allen<br />
Objekten <strong>de</strong>s Typs Component o<strong>de</strong>r daraus abgeleiteten Objekten zur Verfügung<br />
191 InputEvent ist Basisklasse von MouseEvent und KeyEvent. Sie stellt Metho<strong>de</strong>n bereit, die<br />
allgeme<strong>in</strong>e Informationen über <strong>de</strong>n Zustand <strong>de</strong>r Umschalttasten STRG, ALT, UMSCHALT o<strong>de</strong>r META zum<br />
Zeitpunkt <strong>de</strong>s Ereignisses liefern<br />
215
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
steht, Das Interface FocusListener enthält zwei unterschiedliche Metho<strong>de</strong>n:<br />
public abstract void focusGa<strong>in</strong>ed(FocusEvent e)<br />
// Aufruf, wenn die Komponente <strong>de</strong>n Fokus erhält<br />
public abstract void focusLost(FocusEvent e)<br />
// Aufruf, wenn die Komponente <strong>de</strong>n Fokus abgibt<br />
Über die Metho<strong>de</strong> public void requestFocus() kann e<strong>in</strong>e Komponente <strong>de</strong>n<br />
Fokus für sich selbst beanspruchen bzw. ihn e<strong>in</strong>er an<strong>de</strong>ren Komponenten zuweisen.<br />
3.1.5.6 Key-Events<br />
E<strong>in</strong> Empfänger für Key-Events muß das Interface KeyListener implementieren und<br />
bekommt Events <strong>de</strong>s Typs KeyEvent übergeben. KeyEvent erweitert die Klasse<br />
InputEvent, die aus ComponentEvent abgeleitet ist, und stellt neben getID,<br />
getSource e<strong>in</strong>e Reihe von Metho<strong>de</strong>n zur Erkennung und Berabeitung von<br />
Tastaturco<strong>de</strong>s zur Verfügung. Die Registrierung erfolgt mit <strong>de</strong>r Metho<strong>de</strong> public<br />
void addKeyListener (KeyListener l), die auf allen Objekten <strong>de</strong>s Typs<br />
Component o<strong>de</strong>r daraus abgeleiteter Klassen zur Verfügung steht. Das Interface<br />
KeyListener <strong>de</strong>f<strong>in</strong>iert drei unterschiedliche Metho<strong>de</strong>n:<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 wur<strong>de</strong>, erhält man über die folgen<strong>de</strong>n Metho<strong>de</strong>n <strong>de</strong>r Klasse<br />
KeyEvent bereitgestellt:<br />
public <strong>in</strong>t getKeyCo<strong>de</strong>()<br />
liefert virtuelle Tastenco<strong>de</strong>s, die <strong>in</strong> KeyEvent als symbolische Konstanten <strong>de</strong>f<strong>in</strong>iert wur<strong>de</strong>n.Hier wird<br />
beim Drücken <strong>de</strong>r Taste A immer <strong>de</strong>r Co<strong>de</strong> VK_A geliefert, unabhängig davon, ob UMSCHALT<br />
gedrückt wur<strong>de</strong> o<strong>de</strong>r nicht.<br />
Symbolischer Name<br />
Be<strong>de</strong>utung<br />
VK_0..VK_9 0..9<br />
VK_A..VK_Z<br />
A..Z<br />
VK_ENTER<br />
Enter<br />
VK_SPACE<br />
Leertaste<br />
VK_TAB<br />
Tabulator<br />
VK_ESCAPE<br />
Escape<br />
VK_BACK_SPACE<br />
Rückschritt<br />
VK_F1..VK_F12<br />
Die Funktionstasten F1 .. F12<br />
VK_HOME, VK_END<br />
Home, End<br />
VK_PAGE_UP, VK_PAGE_DOWN<br />
Bild hoch, Bild runter<br />
VK_DOWN, VK_UP<br />
Cursor hoch, Cursor runter<br />
VK_LEFT, VK_RIGHT<br />
Cursor l<strong>in</strong>ks, Cursor rechts<br />
VK_INSERT, VK_DELETE<br />
E<strong>in</strong>fg, Entf<br />
Abb.: Tabelle <strong>de</strong>r virtuellen Key-Co<strong>de</strong>s<br />
public char getKeyChar()<br />
liefert das Zeichen, das <strong>de</strong>r gedrückten Zeichentste entspricht, z.B. "a", wenn Taste A gedrückt wur<strong>de</strong>,<br />
und "A", wenn die Tastenkomb<strong>in</strong>ation UMSCHALT + A gedrückt wur<strong>de</strong>. Funktionstasten wer<strong>de</strong>n nicht<br />
übertragen. Der Rückgabewert ist hier KeyEvent.CHAR_UNDEFINED.<br />
216
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
getKeyCo<strong>de</strong>()<br />
keyTyped 192 Zeichentaste 193 : VK_UNDEFINED<br />
Funktionstaste 194 : -<br />
keyPressed 195 Zeichentaste: VK_...<br />
Funktionstaste: VK_...<br />
getKeyChar()<br />
Zeichentaste: Taste als char<br />
Funktionstaste: -<br />
Zeichentaste: Taste als char<br />
Funktionstaste: CHAR_UNDEFINED<br />
Rückgabeco<strong>de</strong> bei Tastatur-Ereignissen<br />
Zusätzlich stehen fogen<strong>de</strong> aus InputEvent geerbten Metho<strong>de</strong>n zur Verfügung:<br />
public boolean isShiftDown();<br />
public boolean isControlDown();<br />
public boolean isMetaDown();<br />
public boolean isAltDown();<br />
Bsp.: Das folgen<strong>de</strong> Programm 196 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 componentHid<strong>de</strong>n(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 />
192 zeigt das Verhalten beim Aufruf <strong>de</strong>r Listener-Metho<strong>de</strong> keyTyped<br />
193 Tasten, mit <strong>de</strong>nen Buchstaben, Ziffern o<strong>de</strong>r sonst. Unico<strong>de</strong>-Zeichen e<strong>in</strong>gegeben wer<strong>de</strong>n, wie z.B. a, A, 1, 2,<br />
% aber auch ESC, SPACE, TAB<br />
194 Dazu gehören bspw. F1, F2, Pos 1 aber auch die Umschalttasten: STRG, ALT, UMSCHALT<br />
195 zeigt das Verhalten beim Aufruf von keyPressed<br />
196 vgl. pr14160<br />
217
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
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 />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
public void mouseReleased(MouseEvent e)<br />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
public void mouseEntered(MouseEvent e)<br />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
public void mouseExited(MouseEvent e)<br />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
}<br />
class MML implements MouseMotionListener<br />
{<br />
public void mouseDragged(MouseEvent e)<br />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
public void mouseMoved(MouseEvent e)<br />
{ System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<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 />
218
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.1.6 Der Weg e<strong>in</strong>es Ereignisses<br />
Je<strong>de</strong> Ereignisquelle besitzt e<strong>in</strong>e Reihe von Metho<strong>de</strong>n, die für das Aufbereiten und<br />
Verteilen <strong>de</strong>r Nachricht zuständig s<strong>in</strong>d. Beim Weiterreichen e<strong>in</strong>er Nachricht wird<br />
<strong>in</strong>nerhalb <strong>de</strong>r Nachrichtenquelle die Metho<strong>de</strong> processEvent aufgerufen. Diese<br />
verteilt die Nachricht anhand ihres Typs an spezialisierte Metho<strong>de</strong>n, <strong>de</strong>ren Name<br />
sich nach <strong>de</strong>m Typ <strong>de</strong>r zugehörigen Ereignisquelle richtet:<br />
protected void processComponentEvent(ComponentEvent e)<br />
protected void processFocusEvent(FocusEvent e)<br />
protected void processKeyEvent(KeyEvent e)<br />
protected void processMouseEvent(MouseEvent e)<br />
protected void processMouseMotionEvent(MouseEvent e)<br />
protected void processActionEvent(ActionEvent e)<br />
Abb.: Spezialisierte Metho<strong>de</strong>n für das Event-Handl<strong>in</strong>g<br />
"processEvent" bzw. die spezialisierten Metho<strong>de</strong>n für das Event-Handl<strong>in</strong>g wer<strong>de</strong>n<br />
nur aufgerufen, wenn <strong>de</strong>r entsprechen<strong>de</strong> Ereignistyp für diese Ereignisquelle aktiviert<br />
wur<strong>de</strong>. Dies geschieht <strong>in</strong> folgen<strong>de</strong>n Fällen:<br />
- E<strong>in</strong> passen<strong>de</strong>r Ereignisempfänger wur<strong>de</strong> über die zugehörige addEventListener-Metho<strong>de</strong><br />
registriert.<br />
- E<strong>in</strong> Ereignistyp wur<strong>de</strong> explizit durch Aufruf <strong>de</strong>r Metho<strong>de</strong> protected f<strong>in</strong>al void<br />
enableEvents(long eventsToEnable) aktiviert. Die Metho<strong>de</strong> erwartet e<strong>in</strong>e Maske, die<br />
durch e<strong>in</strong>e bitweise O<strong>de</strong>r-Verknüpfung passen<strong>de</strong>r Konstanten aus <strong>de</strong>r Klasse AWTEvent<br />
zusammengesetzt wer<strong>de</strong>n kann. Folgen<strong>de</strong> Bitmasken akzeptiert diese Metho<strong>de</strong>:<br />
ACTION_EVENT_MASK<br />
ADJUSTMENT_EVENT_MASK<br />
COMPONENT_EVENT_MASK<br />
CONTAINER_EVENT_MASK<br />
FOCUS_EVENT_MASK<br />
ITEM_EVENT_MASK<br />
KEY_EVENT_MASK<br />
MOUSE_EVENT_MASK<br />
MOUSE_MOTION_EVENT_MASK<br />
TEXT_EVENT_MASK<br />
WINDOW_EVENT_MASK<br />
Die Namen dieser Bitmasken verweisen auf die Namen <strong>de</strong>r Ereignisklassen, für<br />
<strong>de</strong>ren Objekte sie <strong>de</strong>n Ereignisfilter durchlässig schalten. Sollen mehrere aktiviert<br />
wer<strong>de</strong>n, dann ist diese Komb<strong>in</strong>ation durch Addition bzw. bitweises O<strong>de</strong>r möglich,<br />
z.B.:<br />
enableEvents(ACTION_EVENT_MASK + WINDOW_EVENT_MASK)<br />
bzw.<br />
enableEvents(ACTION_EVENT_MASK | WINDOW_EVENT_MASK)<br />
Sobald e<strong>in</strong> soches Ereignis erzeugt wird, sieht se<strong>in</strong> Weg dann folgen<strong>de</strong>rmaßen aus:<br />
1. Die Metho<strong>de</strong> processEvent <strong>de</strong>r eigenen Klasse erhält das Ereignis<br />
2. Nach <strong>de</strong>r Ereignisverarbeitung wird die Metho<strong>de</strong> <strong>de</strong>r Subklasse aufgerufen<br />
3. Diese prüft <strong>de</strong>n Ereignistyp und ruft dann typspezifische process...Event-Metho<strong>de</strong>n auf, z.B.<br />
processActionEvent, processFocusEvent.<br />
4. Diese prüfen, ob Listener registriert s<strong>in</strong>d, und rufen sie gegebenenfalls auf.<br />
5. Nach diesen Aufrufen wird die Metho<strong>de</strong> processEvent <strong>de</strong>r nächsten Superklasse aufgerufen.<br />
219
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6. Sie verfährt wie<strong>de</strong>r so, wie unter <strong>de</strong>n Ziffern 3 bis 5 beschrieben. Das wie<strong>de</strong>rholt sich so lange, bis<br />
processEvent von ComponentEvent durchlaufen wird.<br />
Bsp.: Das folgen<strong>de</strong> 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 <strong>de</strong>r im Programm zu bearbeiten<strong>de</strong>n 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 />
220
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.2 Kommunikation Anwen<strong>de</strong>r – Programm über Dialoge bzw.<br />
Menüs<br />
3.2.1 Dialoge<br />
Der Anwen<strong>de</strong>r 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. Textfel<strong>de</strong>r, Buttons, Listboxen) zur Darstellung und<br />
Erfassung programmspezifischer Daten. Das Design <strong>de</strong>r Dialoge wird von<br />
Layoutmangern unterstützt, die sich um Größe und Anordnung <strong>de</strong>r 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 <strong>de</strong>s Fensters<br />
Anlegen e<strong>in</strong>es Fensters. E<strong>in</strong> Dialogfenster kann wahlweise aus <strong>de</strong>r Klasse Frame<br />
o<strong>de</strong>r Dialog abgeleitet wer<strong>de</strong>n. "Dialog" erlaubt "modale Dialoge 197 " und<br />
verh<strong>in</strong><strong>de</strong>rt das Verän<strong>de</strong>rn <strong>de</strong>r Fenstergröße durch <strong>de</strong>n Anwen<strong>de</strong>r. Im Gegensatz zum<br />
Frame kann e<strong>in</strong> "Dialog"-Fenster ke<strong>in</strong>e Menüleiste erzeugen und <strong>de</strong>m Fenster ke<strong>in</strong><br />
Icon 198 zuordnen.<br />
Zuordnen e<strong>in</strong>es Layoutmanagers. Es wird über die Metho<strong>de</strong> "public void<br />
setLayout(LayoutManager mgr)" <strong>de</strong>r Klasse Conta<strong>in</strong>er realisiert. <strong>Java</strong> stellt fünf<br />
Layoutmanager 199 bereit: FlowLayout Bor<strong>de</strong>rLayout, GridLayout<br />
GridBagLayout und CardLayout.<br />
Neben <strong>de</strong>n Fähigkeiten e<strong>in</strong>es Layoutmanagers bestimmt <strong>in</strong> <strong>de</strong>r Regel die<br />
Reihenfolge <strong>de</strong>r Aufrufe von <strong>de</strong>r "add"-Metho<strong>de</strong> <strong>de</strong>s Fensters die tatsächliche<br />
Anordnung <strong>de</strong>r Komponenten auf <strong>de</strong>m Bildschirm.<br />
Schachteln von Layoutmanagern. Dazu wird an die Stelle, die das Sublayout erhalten<br />
soll, e<strong>in</strong>fach e<strong>in</strong> Objekt <strong>de</strong>r 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 wer<strong>de</strong>n, die<br />
entsprechend <strong>de</strong>m zugeordneten Sublayout formatiert wer<strong>de</strong>n, z.B.:<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class PR14171 extends Frame<br />
{<br />
public PR14171()<br />
{<br />
197 Modale Dialaloge verh<strong>in</strong><strong>de</strong>rn die Interaktion <strong>de</strong>s Anwen<strong>de</strong>rs mit an<strong>de</strong>ren Fenstern <strong>de</strong>r Anwendung bis zum<br />
Schließen <strong>de</strong>s Dialogfensters.<br />
198 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 <strong>de</strong>s Fensters wie<strong>de</strong>rhergestellt wer<strong>de</strong>n. Mit Hlife <strong>de</strong>r Metho<strong>de</strong> "public<br />
void setIconImage(Image bild)" kann e<strong>in</strong>em Fenster e<strong>in</strong> Icon zugeordnet wer<strong>de</strong>n, das beim<br />
M<strong>in</strong>imieren angezeigt wird.<br />
199 Vgl. 5.4.2<br />
221
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 Bor<strong>de</strong>rLayout());<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 vorliegen<strong>de</strong> Programm zeigt nach <strong>de</strong>m Aufruf das folgen<strong>de</strong> Fenster:<br />
Abb.:<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, <strong>de</strong>r bei bestimmten Layout-Managern<br />
// (z.B. Bor<strong>de</strong>rLayout) Informationen zur Positionierung <strong>de</strong>r Elemente ("bei<br />
// Bor<strong>de</strong>rLayout: "South", "East", "West", "North", "Center") angibt.<br />
<strong>de</strong>r Klasse Conta<strong>in</strong>er. Mit "public void remove(Component komponente)"<br />
können bereits an das Fenster übergebene Komponenten gelöscht wer<strong>de</strong>n.<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()" <strong>de</strong>r Klasse W<strong>in</strong>dow zur<br />
222
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Anpassung <strong>de</strong>r Fenstergröße an <strong>de</strong>n für die Darstellung <strong>de</strong>r Dialogelemente<br />
erfor<strong>de</strong>rlichen Platz ausgeführt wer<strong>de</strong>n.<br />
Popup-Fenster <strong>de</strong>r Klasse Dialog<br />
Die Klasse Dialog 200 stellt e<strong>in</strong> Popup-Fenster bereit und ermöglicht die Erzeugung<br />
"modaler" bzw. "nicht modaler" Dialoge. "Modal" be<strong>de</strong>utet: Das Dialogfeld blockiert<br />
an<strong>de</strong>re Fenster, während es angezeigt wird, z.B. 201 :<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 Bor<strong>de</strong>rLayout(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 wur<strong>de</strong> nach e<strong>in</strong>er Vorlage von"<br />
+ "David Flanagan geschrieben");<br />
dlg.setVisible(true);<br />
}<br />
}<br />
200 vgl. 5.3.4<br />
201 vgl. pr14170<br />
223
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Dialogfenster s<strong>in</strong>d Übergangsfenster. Sie dienen dazu, <strong>de</strong>n Benutzer über Ereignisse<br />
zu <strong>in</strong>formieren o<strong>de</strong>r E<strong>in</strong>gabe vom Benutzer anzufor<strong>de</strong>rn. Im Gegensatz zu Frames<br />
haben Dialogfel<strong>de</strong>r im allg. ke<strong>in</strong>e Titelleiste o<strong>de</strong>r Schaltfläche zum Schließen <strong>de</strong>s<br />
Fensters.<br />
E<strong>in</strong> Dialogfenster ist, wie e<strong>in</strong> Frame, e<strong>in</strong> Panel, <strong>in</strong> <strong>de</strong>m Komponenten <strong>de</strong>r<br />
Benutzeroberfläche angeordnet, gezeichnet sowie Grafikoperationen ausgeführt<br />
wer<strong>de</strong>n können.<br />
Mit <strong>de</strong>r Klasse FileDialog kann e<strong>in</strong> plattformspezifischer Dateidialog erzeugt<br />
wer<strong>de</strong>n.<br />
Dialog<br />
FileDialog<br />
public static f<strong>in</strong>al <strong>in</strong>t LOAD<br />
public static f<strong>in</strong>al <strong>in</strong>t SAVE<br />
><br />
public FileDialog(Frame eltern)<br />
// erzeugt Datei-Dialog ohne Titel zum Öffnen e<strong>in</strong>er Datei<br />
public FileDialog(Frame eltern, Str<strong>in</strong>g titel)<br />
//erzeugt Dialog zum Öffnen e<strong>in</strong>er Datei mit e<strong>in</strong>em Titel im<br />
// Fensterrahmen<br />
public FileDialog(Frame eltern, Str<strong>in</strong>g titel, <strong>in</strong>t mo<strong>de</strong>)<br />
// erzeugt Dialog mit e<strong>in</strong>em Titel im Fensterrahmen. Da <strong>de</strong>r<br />
// Dialog sowohl für Sichern und La<strong>de</strong>n ausgelegt ist, s<strong>in</strong>d<br />
// we<strong>de</strong>r LOAD o<strong>de</strong>r SAVE mit anzugeben.<br />
><br />
public Str<strong>in</strong>g getDirectory()<br />
// liefert das Verzeichnis <strong>de</strong>s Dialogs<br />
public synchronized void setDirectory(Str<strong>in</strong>g dir)<br />
// setzt das Verzeichnis, das zu Beg<strong>in</strong>n ausgegeben wer<strong>de</strong>n soll<br />
public Str<strong>in</strong>g getFile()<br />
// liefert die ausgewählte datei <strong>de</strong>s Dialogs<br />
public synchronized void setFile(Str<strong>in</strong>g file)<br />
// Datei, die zu Beg<strong>in</strong>n angezeigt wird<br />
public FilenameFilter getFilenameFilter()<br />
// liefert FilenameFilter.-Objekt zurück<br />
public synchronized void setFilenameFilter(FilenameFilter filter)<br />
// setzt <strong>de</strong>n FilenameFilter<br />
Abb.: Die Klasse FileDialog<br />
Vererbungskette. FileDialog leitet sich von Dialog ab. Dialog ist e<strong>in</strong>e Ableitung<br />
von W<strong>in</strong>dow. W<strong>in</strong>dow ist e<strong>in</strong> Conta<strong>in</strong>er und dieser wie<strong>de</strong>rum e<strong>in</strong> Component.<br />
Bsp.: La<strong>de</strong>n und Speichern von Dateien mit Unterstützung durch e<strong>in</strong> Dateidialogfeld<br />
202 .<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class DateiDialog extends Frame<br />
{<br />
TextField dateiName = new TextField();<br />
202 pr14160<br />
224
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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,Bor<strong>de</strong>rLayout.SOUTH);<br />
verzeichnis.setEditable(false);<br />
dateiName.setEditable(false);<br />
p = new Panel();<br />
p.setLayout(new GridLayout(2,1));<br />
p.add(dateiName); p.add(verzeichnis);<br />
add(p,Bor<strong>de</strong>rLayout.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 wer<strong>de</strong>n?");<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 wur<strong>de</strong> 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 wer<strong>de</strong>n?",<br />
FileDialog.SAVE);<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 wur<strong>de</strong> 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 />
225
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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); f.setVisible(true);<br />
}<br />
}<br />
Bei Applets ist es vom Browser abhängig, ob Instanzen von FileDialog e<strong>in</strong>gesetzt<br />
wer<strong>de</strong>n können. Die meisten Browser erzeugen lediglich e<strong>in</strong>en Fehler.<br />
Vor<strong>de</strong>f<strong>in</strong>ierte Dialogelemente<br />
Je<strong>de</strong>s 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 <strong>de</strong>r<br />
gewünschten Klasse angelegt und das resultieren<strong>de</strong> Element mit "add" <strong>in</strong> <strong>de</strong>n Dialog<br />
e<strong>in</strong>gefügt. Alle Dialogelemente s<strong>in</strong>d aus <strong>de</strong>r Klasse Component abgeleitet. Sie<br />
verfügen über die grundlegen<strong>de</strong>n Eigenschaften e<strong>in</strong>es Fensters, besitzen Größe und<br />
Position und s<strong>in</strong>d <strong>in</strong> <strong>de</strong>r Lage, Nachrichten zu empfangen und zu bearbeiten.<br />
Component<br />
Button TextComponent Conta<strong>in</strong>er MenuComponent Checkbox<br />
TextField TextArea Menu MenuBar MenuItem<br />
Panel<br />
W<strong>in</strong>dow<br />
Abb.: Komponenten <strong>de</strong>s AWT<br />
Applet Frame Dialog<br />
Vor<strong>de</strong>f<strong>in</strong>ierte Dialogelemente unter <strong>de</strong>n Komponenten <strong>de</strong>s AWT s<strong>in</strong>d:<br />
Labels 203 , Schaltflächen(Buttons) 204 , Kontrollkästchen und Optionsfel<strong>de</strong>r 205 ,<br />
Auswahlmenüs 206 , Listenfel<strong>de</strong>r 207 , Textbereiche und Textfel<strong>de</strong>r 208 , Schieberegler 209 .<br />
Das Dialogelement „Canvas“<br />
203 vgl. 5.2.2<br />
204 vgl. 5.2.1<br />
205 vgl. 5.2.3<br />
206 vgl. 5.2.4<br />
207 vgl. 5.2.5<br />
208 vgl. 5.2.6<br />
209 vgl. 5.2.7<br />
226
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 an<strong>de</strong>ren Komponenten<br />
enthalten, akzeptieren aber Ereignisse. Außer<strong>de</strong>m können sie Animationen und<br />
Bil<strong>de</strong>r anzeigen. Zum Erstellen e<strong>in</strong>es Zeichenbereichs wird die Klasse Canvas<br />
benutzt. Das eigentliche Zeichnen erfolgt <strong>in</strong> <strong>de</strong>r Metho<strong>de</strong> pa<strong>in</strong>t(Graphics g).<br />
Diese Metho<strong>de</strong> wird immer dann aufgerufen, wenn die Zeichenfäche neu gezeichnet<br />
wer<strong>de</strong>n muß. Typische Situationen, <strong>in</strong> <strong>de</strong>nen pa<strong>in</strong>t(Graphics g) aufgerufen wird,<br />
s<strong>in</strong>d:<br />
- Der die Zeichenfläche umfassen<strong>de</strong> Rahmen (Frame) wird ertmals erstellt<br />
- Die Metho<strong>de</strong> repa<strong>in</strong>t() wird explizit aufgerufen<br />
- Die Zeichenfläche wur<strong>de</strong> teilweise o<strong>de</strong>r ganz von an<strong>de</strong>ren Fenstern über<strong>de</strong>ckt<br />
- Die Größe <strong>de</strong>r Zeichenfläche hat sich verän<strong>de</strong>rt<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 <strong>de</strong>m Bildschirm. Der Punkt (0,0) <strong>de</strong>s<br />
übergebenen Graphics-Objekts entspricht dabei <strong>de</strong>r l<strong>in</strong>ken oberen Ecke <strong>de</strong>s<br />
Ausgabebereichs.<br />
Bsp. 210 :<br />
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 />
210 pr52900<br />
227
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.2.2 Menüs<br />
Je<strong>de</strong>s Fenster / Frame kann e<strong>in</strong>e eigene Menüleiste besitzen. Je<strong>de</strong> Menüleiste kann<br />
mehrere Menüs enthalten und je<strong>de</strong>s Menü beliebige E<strong>in</strong>träge 211 .<br />
Menüs dienen zur Auswahl von Funktionen und Optionen <strong>in</strong> Anwendungen. Menüs<br />
können entwe<strong>de</strong>r <strong>in</strong> <strong>de</strong>r Form von Menubars an <strong>de</strong>r Oberseite von Fenstern o<strong>de</strong>r als<br />
Popupmenüs an e<strong>in</strong>er beliebigen Stelle auftreten.<br />
E<strong>in</strong> Menü ist entwe<strong>de</strong>r <strong>in</strong> e<strong>in</strong>er Menüleiste e<strong>in</strong>es Frame-Objekts e<strong>in</strong>gebettet (Klasse<br />
MenuBar) o<strong>de</strong>r ersche<strong>in</strong>t auf Abruf als Kontextmenü (Klasse PopupMenu). Damit<br />
s<strong>in</strong>d entwe<strong>de</strong>r Untermenüs (Klasse Menu) o<strong>de</strong>r Menüe<strong>in</strong>träge (Klasse MenuItem)<br />
enthalten.<br />
Je<strong>de</strong>s Menü besitzt e<strong>in</strong> „label“ und e<strong>in</strong> „aktionKommando“ (e<strong>in</strong> Str<strong>in</strong>g, <strong>de</strong>r das Menü<br />
beim ActionEvent kennzeichnet und <strong>de</strong>r ausgelöst wird, wenn <strong>de</strong>r E<strong>in</strong>trag<br />
angeklickt wird). Für Menüs können Shortcuts, also Tastaturkürzel, angegeben<br />
wer<strong>de</strong>n.<br />
E<strong>in</strong> MenuItem ist e<strong>in</strong> E<strong>in</strong>trag <strong>in</strong> e<strong>in</strong>em Menü, <strong>de</strong>r sich bei Selektion e<strong>in</strong>er Option<br />
än<strong>de</strong>rt (CheckboxMenuItem) o<strong>de</strong>r e<strong>in</strong> Kommando absetzt.<br />
211 vgl. 5.3.3<br />
228
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
MenuComponent<br />
{ abstract }<br />
public Str<strong>in</strong>g getName()<br />
public void setName(Str<strong>in</strong>g name)<br />
public MenuConta<strong>in</strong>er getParent()<br />
public Font getFont()<br />
public void setFont(Font f)<br />
public f<strong>in</strong>al void dispatchEvent(AWTEvent e)<br />
protected void processEvent(AWTEvent e)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
MenuItem<br />
MenuBar<br />
> ><br />
public MenuItem()<br />
public MenuBar()<br />
public MenuItem(Str<strong>in</strong>g label) ><br />
public MenuItem(Str<strong>in</strong>g label, MenuShortcut s)<br />
public void addNotify()<br />
> public void removeNotify()<br />
public void addNotify()<br />
public Menu getHelpMenu()<br />
public Str<strong>in</strong>g getLabel() public void setHelpMenu(Menu m)<br />
public void setLabel(Str<strong>in</strong>g label) public Menu add(Menu m)<br />
public boolean isEnabled()<br />
public void remove<br />
public void setEnabled(boolean b) (MenuComponent m)<br />
public MenuShortcut getShortcut()<br />
public <strong>in</strong>t getMenuCount()<br />
public void setShortcut(MenuShortcut s) public Menu getMenu(<strong>in</strong>t i)<br />
protected f<strong>in</strong>al void enableEvents(long eventsToEnable) public Enumeration shortcuts()<br />
protected f<strong>in</strong>al void disableEvents(long eventsToEnable) public MenuItem<br />
public void setActionCommand(Str<strong>in</strong>g kommando)<br />
getShortcutMenuItem<br />
public Str<strong>in</strong>g getActionCommand() (MenuShortcut s)<br />
public void addActionListener(ActionListener l)<br />
public void removeActionListener(ActionListener l)<br />
protected void processEvent(AWTEvent e)<br />
protected processActionEvent(ActionEvent e)<br />
... ><br />
MenuConta<strong>in</strong>er<br />
CheckboxMenuItem<br />
Menu<br />
> ><br />
public CheckboxMenuItem()<br />
public Menu()<br />
public CheckboxMenuItem(Str<strong>in</strong>g label)<br />
public Menu(Str<strong>in</strong>g label)<br />
public CheckboxMenuItem(Str<strong>in</strong>g label,<br />
boolean state) ><br />
> public MenuItem add(MenuItem m)<br />
public void addItemListener(ItemListener l)<br />
public void add(Str<strong>in</strong>g label)<br />
public void addNotify()<br />
public void addNotify()<br />
public boolean getState()<br />
public MenuItem getItem(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
protected void processEvent(AWTEvent e)<br />
public void <strong>in</strong>sert(MenuItem mi, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
... public void <strong>in</strong>sert(Str<strong>in</strong>g label,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
...<br />
229
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.2.3 Popup-Menüs<br />
Popup-Menüs s<strong>in</strong>d nicht wie normale Menüs an e<strong>in</strong>e bestimmte Position gebun<strong>de</strong>n,<br />
son<strong>de</strong>rn tretem meistens dort auf, wo <strong>de</strong>r Benutzer mit <strong>de</strong>r rechten Maustaste<br />
geklickt hat. Für Popup-Menüs ist die Klasse Popup-Menu zuständig. Menüe<strong>in</strong>träge<br />
können mit <strong>de</strong>r Klasse Menu erzeugt wer<strong>de</strong>n.<br />
Menu<br />
PopupMenu<br />
><br />
public PopupMenu()<br />
// erzeugt e<strong>in</strong> Popup-Menu<br />
public PopupMenu(Str<strong>in</strong>g label)<br />
><br />
public void addNotify()<br />
public void show(Component orig<strong>in</strong>, <strong>in</strong>t x, <strong>in</strong>t y)<br />
// läßt das Popup-Menu auf <strong>de</strong>r Komponenten<br />
// orig<strong>in</strong> an <strong>de</strong>r Position x, y aufspr<strong>in</strong>gen.<br />
Abb.: Die AWT-Menüklasse PopupMenu<br />
Bsp.: 212<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class PopMenDemo extends Frame<br />
{<br />
PopupMenu popmen = new PopupMenu();<br />
public PopMenDemo()<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 />
System.exit(0);<br />
}<br />
});<br />
popmen.add(new MenuItem("E<strong>in</strong>trag 1"));<br />
popmen.addSeparator();<br />
popmen.add(new MenuItem("E<strong>in</strong>trag 2"));<br />
popmen.add(new MenuItem("E<strong>in</strong>trag 3"));<br />
popmen.add(new MenuItem("E<strong>in</strong>trag 4"));<br />
add(popmen);<br />
popmen.addActionListener(new ActionListener()<br />
{<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
System.out.pr<strong>in</strong>tln(e.getActionCommand() + " wur<strong>de</strong> gedrueckt");<br />
}<br />
});<br />
addMouseListener(new MouseAdapter()<br />
212 pr53330, PopMenDemo.java<br />
230
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
public void mouseClicked(MouseEvent m)<br />
{<br />
if (m.getModifiers() == m.BUTTON3_MASK)<br />
popmen.show(PopMenDemo.this,m.getX(),m.getY());<br />
}<br />
});<br />
setSize(300,300); setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{ new PopMenDemo().show(); }<br />
}<br />
231
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.3 Grundlagen <strong>de</strong>r 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 wer<strong>de</strong>n <strong>in</strong>nerhalb von HTML-Seiten über Referenzen e<strong>in</strong>gebun<strong>de</strong>n.<br />
Referenzen können Überschriften, Texte, Kapitel, Unterkapitel, Absätze, Grafiken<br />
bzw. L<strong>in</strong>ks zu an<strong>de</strong>ren Seiten se<strong>in</strong>. HTML ist e<strong>in</strong>e Dokumentationsbeschreibungssprache<br />
mit <strong>de</strong>r logische Strukturen e<strong>in</strong>es Dokuments beschrieben wer<strong>de</strong>n. Über<br />
Klartext (ASCII-Text) gibt e<strong>in</strong> Dokumentenformat Empfehlungen an e<strong>in</strong>e<br />
Darstellungssoftware (Browser) zur Darstellung <strong>de</strong>r Dokumentstruktur.<br />
Außer<strong>de</strong>m wird beschrieben, welche Funktionalität wie auszuführen ist, damit sie<br />
<strong>de</strong>m geplanten Layout und <strong>de</strong>r vorgegebenen Funktionalität entspricht. Es gibt ke<strong>in</strong>e<br />
verb<strong>in</strong>dliche Darstellungsvorschrift, <strong>de</strong>shalb kann die Ausführung von HTML-Seiten<br />
<strong>in</strong> verschie<strong>de</strong>nen Browsern oft unterschiedlich anfallen.<br />
Die Basis von HTML<br />
Die Sprache HTML baut auf <strong>de</strong>r Sprache SGML auf. HTML ist die Abkürzung für<br />
Hypertext Markup Language und wur<strong>de</strong> aus <strong>de</strong>r <strong>in</strong> <strong>de</strong>r 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, Vi<strong>de</strong>o, usw.) enthalten (Referenz auf Grafik- o<strong>de</strong>r<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 wer<strong>de</strong>n.<br />
Die Normung <strong>de</strong>r HTML realisiert und kontrolliert das World Wi<strong>de</strong> Web Consortium<br />
(W3C) mit Sitz <strong>in</strong> Genf. En<strong>de</strong> 1997 kam es zu zur offiziellen Verabschiedung <strong>de</strong>s<br />
Standards.<br />
HTML-Steueranweisungen<br />
Tags. Alle HTML-Steueranweisungen wer<strong>de</strong>n <strong>in</strong> sog. Tags geschrieben, die von<br />
spitzen Klammern (< >) begrenzt s<strong>in</strong>d. Man unterschei<strong>de</strong>t zwischen E<strong>in</strong>leitungs- und<br />
Abschluß-Tags. Die Abschluß-Tags s<strong>in</strong>d be<strong>in</strong>ahe i<strong>de</strong>ntisch mit <strong>de</strong>m E<strong>in</strong>leitungs-Tag.<br />
Sie besitzen lediglich zusätzlich e<strong>in</strong>en Slash (/) nach <strong>de</strong>m „
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Das Grundgerüst e<strong>in</strong>er HTML-Seite<br />
E<strong>in</strong>e HTML-Seite wird immer <strong>in</strong> die Anweisung am Anfang und am<br />
En<strong>de</strong> 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 <strong>de</strong>m Applet-Tag e<strong>in</strong>geleitet. Zwischen <strong>de</strong>m e<strong>in</strong>leiten<strong>de</strong>n Tag und <strong>de</strong>m abschließen<strong>de</strong>n Applet-<br />
Tag () können benötigte Parameter o<strong>de</strong>r beliebiger Text e<strong>in</strong>gegeben<br />
wer<strong>de</strong>n. Die e<strong>in</strong>fachste Form <strong>de</strong>r Applet-Referenz. Ohne irgendwelche Parameter<br />
wird e<strong>in</strong> <strong>Java</strong>-Applet e<strong>in</strong>gebun<strong>de</strong>n mit<br />
<br />
<br />
klassenelement: Applet-Klasse<br />
WIDTH = Wert: Breite <strong>de</strong>s Applet <strong>in</strong> Pixel<br />
HEIGHT = Wert: Höhe <strong>de</strong>s Applet <strong>in</strong> Pixel<br />
Das -Tag erzeugt ke<strong>in</strong>en Absatz, <strong>de</strong>shalb sollte es <strong>in</strong> e<strong>in</strong>em allgeme<strong>in</strong>en<br />
Text-Tag stehen, z.B. o<strong>de</strong>r <strong>in</strong> e<strong>in</strong>em Überschriften-Tag (, usw.).<br />
Optionale Parameter <strong>de</strong>s -Tag<br />
Parameter<br />
CODEBASE<br />
ARCHIVE<br />
OBJECT<br />
ALT<br />
NAME<br />
ALIGN<br />
VSPACE<br />
HSPACE<br />
Be<strong>de</strong>utung<br />
Hier kann e<strong>in</strong> alternatives Verzeichnis 213 für das La<strong>de</strong>n von Klassendateien<br />
angegeben wer<strong>de</strong>n. Fehlt diese Angabe, wird das Dokumentenverzeichnis<br />
genommen.<br />
Angabe <strong>de</strong>s JAR-Archivs, aus <strong>de</strong>m die Klassendateien und sonstige Resourcen<br />
<strong>de</strong>s Applet genommen wer<strong>de</strong>n<br />
Name <strong>de</strong>r Datei, die <strong>de</strong>n serialisierten Inhalt <strong>de</strong>s Applet enthält.<br />
Alternativer Text für Browser, die das Applet verstehen, aber <strong>Java</strong> nicht<br />
unterstützen<br />
E<strong>in</strong><strong>de</strong>utiger Name für das Applet. Er kann zur Unterscheidung mehrerer<br />
kommunizieren<strong>de</strong>r Applets auf e<strong>in</strong>er Web-Seite verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Vertikale Anordnung <strong>de</strong>s Applets <strong>in</strong> e<strong>in</strong>er Textzeile. Hier kann e<strong>in</strong>er <strong>de</strong>r Werte<br />
left, right, top, texttop, middle, absmiddle, basel<strong>in</strong>e, bottom, absbottom<br />
angegeben wer<strong>de</strong>n.<br />
Rand über und unter <strong>de</strong>m Applet<br />
Rand l<strong>in</strong>ks o<strong>de</strong>r rechts vom Applet<br />
Neben <strong>de</strong>n Parametern <strong>de</strong>s „Applet-Tag“ können auch Parameter an das Applet<br />
selbst übergeben wer<strong>de</strong>n. Je<strong>de</strong>r Parameter kann durch e<strong>in</strong> -Tag über zwei<br />
Attribute für Name (name) und Wert (value) festgelegt wer<strong>de</strong>n. Das -Tag<br />
steht zwischen e<strong>in</strong>em öffnen<strong>de</strong>n und schließen<strong>de</strong>n -Tag.<br />
Die Parameter wer<strong>de</strong>n beim La<strong>de</strong>n an das Applet weitergereicht. Innerhalb <strong>de</strong>s<br />
Applets können sie mit <strong>de</strong>r Metho<strong>de</strong> public Str<strong>in</strong>g getParameter(Str<strong>in</strong>g<br />
name) abgefragt wer<strong>de</strong>n.<br />
213 Pfadname, <strong>in</strong> <strong>de</strong>m sich die Klassen bef<strong>in</strong><strong>de</strong>n<br />
233
<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 />
Metho<strong>de</strong>, die beim La<strong>de</strong>n gestartet wird und das Programm solange am Leben hält,<br />
bis es <strong>de</strong>r Benutzer been<strong>de</strong>t. In e<strong>in</strong>em Applet sorgen vier Metho<strong>de</strong>n dafür, daß sich<br />
das Applet <strong>in</strong> se<strong>in</strong>er Umgebung korrekt verhält.<br />
Panel<br />
Applet<br />
><br />
public Applet()<br />
><br />
public void <strong>de</strong>stroy()<br />
public AppletContext getAppletContext()<br />
public Str<strong>in</strong>g getAppletInfo()<br />
public AudioClip getAudioClip(URL url)<br />
public AudioClip getAudioClip(URL url,Str<strong>in</strong>g name)<br />
public URL getCo<strong>de</strong>Base()<br />
public URL getDocumentBase()<br />
public Image getImage(URL url)<br />
public Image getImage(URL url, Str<strong>in</strong>g name)<br />
public Locale getLocale()<br />
public Str<strong>in</strong>g getParameter(Str<strong>in</strong>g name)<br />
public Str<strong>in</strong>g[][] getParameterInfo()<br />
public void <strong>in</strong>it()<br />
public boolean isActive()<br />
public void play(URL url)<br />
public void play(URL url, Str<strong>in</strong>g name)<br />
public void resize(Dimension d)<br />
public void resize(<strong>in</strong>t width, <strong>in</strong>t height)<br />
public void setStub(AppletStub stub)<br />
public void showStatus(Str<strong>in</strong>g msg)<br />
public void start()<br />
public void stop()<br />
…..<br />
Abb. Die Klasse Applet<br />
234
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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“ <strong>de</strong>r Klasse Applet 214<br />
erzeugt wer<strong>de</strong>n. <strong>Java</strong> setzt voraus, daß e<strong>in</strong>e Applet-Subklasse public <strong>de</strong>klariert<br />
wur<strong>de</strong>. 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 gela<strong>de</strong>n. <strong>Java</strong> erstellt e<strong>in</strong>e Instanz dieser Klasse, alle systembezogenenen<br />
Metho<strong>de</strong>n wer<strong>de</strong>n an diese Instanz geschickt. Mehrere Applets auf <strong>de</strong>r gleichen o<strong>de</strong>r<br />
auf unterschiedlichen Seiten verwen<strong>de</strong>n an<strong>de</strong>re Instanzen, so daß sich je<strong>de</strong>s Applet<br />
auf <strong>de</strong>m gleichen System evtl. an<strong>de</strong>rs verhält.<br />
2. Applet-Metho<strong>de</strong>n<br />
Applets können zahlreiche, unterschiedliche Aktivitäten umfassen, die verschie<strong>de</strong>nen<br />
wichtigen Ereignissen im Lebenszyklus e<strong>in</strong>es Applet entsprechen, z.B. Initialisieren,<br />
Zeichnen, Mausereignisse. Je<strong>de</strong>r Aktivität ist e<strong>in</strong>e entsprechen<strong>de</strong> Metho<strong>de</strong><br />
zugeordnet, d.h.: Falls e<strong>in</strong>e Ereignis stattf<strong>in</strong><strong>de</strong>t, ruft <strong>de</strong>r Browser (o<strong>de</strong>r e<strong>in</strong> <strong>Java</strong><br />
ähnliches Werkzeug) diese spezifische Metho<strong>de</strong> auf.<br />
Zum Reagieren auf solche Ereignisse s<strong>in</strong>d bestimmte Verhaltensweisen vorzusehen.<br />
Das geschieht durch Überschreiben <strong>de</strong>r jeweiligen Metho<strong>de</strong> <strong>in</strong> <strong>de</strong>r Applet-Subklasse.<br />
Unterschiedliche Applet-Verhalten be<strong>de</strong>utet: Jeweils an<strong>de</strong>re Metho<strong>de</strong>n müssen<br />
überschieben wer<strong>de</strong>n. Die folgen<strong>de</strong>n Metho<strong>de</strong>n bestimmen <strong>de</strong>n Lebenszyklus e<strong>in</strong>es<br />
Applet:<br />
Rückkehr zur HTML-Seite<br />
<strong>in</strong>it() start() stop() <strong>de</strong>stroy()<br />
Abb.: Metho<strong>de</strong>n im Lebenszklus e<strong>in</strong>es Applet<br />
Verlassen <strong>de</strong>r HTML-Seite<br />
Die Metho<strong>de</strong> <strong>in</strong>it() wird nach <strong>de</strong>m La<strong>de</strong>n <strong>de</strong>s Applet ausgeführt. Sie dient zur<br />
Initialisierung.<br />
Die Metho<strong>de</strong> start() wird automatisch nach Aufruf <strong>de</strong>r Metho<strong>de</strong> <strong>in</strong>it()<br />
aufgerufen bzw. dann, wenn das Applet <strong>in</strong> <strong>de</strong>n Zustand „aktiv“ versetzt wird. Applets<br />
können <strong>in</strong> zwei Zustän<strong>de</strong>n se<strong>in</strong>: aktiv und <strong>in</strong>aktiv. Nach <strong>de</strong>m La<strong>de</strong>n e<strong>in</strong>es Applets ist<br />
dieses zunächst <strong>in</strong>aktiv. Das Applet wechselt <strong>in</strong> <strong>de</strong>n Zustand aktiv, wenn es erstmalig<br />
auf <strong>de</strong>m Bildschirm ersche<strong>in</strong>t. Von dort aus wechselt es se<strong>in</strong>en Zustand zwischen<br />
aktiv und <strong>in</strong>aktiv. Wodurch dieser Zustandswechsel genau ausgelöst wird, ist<br />
abhängig vom Kontext <strong>de</strong>s Applel, d.h. <strong>in</strong> <strong>de</strong>r Regel vom verwen<strong>de</strong>tet Web-Browser.<br />
Die Metho<strong>de</strong> stop() wird aufgerufen, wenn die HTML-Seite, <strong>in</strong> <strong>de</strong>r das Applet<br />
e<strong>in</strong>gebun<strong>de</strong>n ist, verlassen wird bzw. das Applet <strong>in</strong> <strong>de</strong>n Zustand <strong>in</strong>aktiv versetzt wird.<br />
214 Alle Applets müssen java.applet.Applet <strong>in</strong> die Datei mit <strong>de</strong>r Def<strong>in</strong>ition <strong>de</strong>r Applet-Klasse importieren.<br />
java.applet.* vollzieht das E<strong>in</strong>bun<strong>de</strong>n von java.applet.Applet automatisch. Fast alle Applets (die mit grafischen<br />
Schnittstellen) benötigen auch java.awt.*<br />
235
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Metho<strong>de</strong> <strong>de</strong>stroy() zerstört das Applet, nach<strong>de</strong>m es gestoppt wur<strong>de</strong> und <strong>de</strong>r<br />
Kontext <strong>de</strong>s Applet sich für e<strong>in</strong>e Zerstörung entschei<strong>de</strong>t. Die Metho<strong>de</strong> <strong>de</strong>stroy()<br />
sorgt dafür, daß alle vom Applet belegte Ressourcen wie<strong>de</strong>r freigegeben wer<strong>de</strong>n.<br />
Vorhan<strong>de</strong>ne, vom Applet erzeugte Threads wer<strong>de</strong>n ebenfalls zerstört.<br />
Die pa<strong>in</strong>t()-Metho<strong>de</strong> wird <strong>in</strong> <strong>Java</strong> immer aufgerufen, wenn e<strong>in</strong> Applet gezeichnet<br />
wer<strong>de</strong>n muß, z.B. be<strong>in</strong> erstmaligen Zeichnen <strong>de</strong>s Applet, beim Verschieben <strong>de</strong>s<br />
Applet-Fenster, beim Überlagern <strong>de</strong>s Applet-Fenster durch e<strong>in</strong> an<strong>de</strong>res Fenster. Die<br />
pa<strong>in</strong>t()-Metho<strong>de</strong> hat folgen<strong>de</strong> 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 <strong>de</strong>r 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 215 <strong>in</strong> <strong>de</strong>n Co<strong>de</strong> <strong>de</strong>r Applet-Subklasse importiert 216<br />
wird.<br />
Bsp.: „Aller Anfang ist schwer!. Dieser Spruch soll mit Hilfe e<strong>in</strong>es Applet gezeigt<br />
wer<strong>de</strong>n.. Die zugehörige Quellco<strong>de</strong>datei „AllerAnfangApplet.java“ umfaßt 217 :<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 unterschei<strong>de</strong>n,) simuliert<br />
g.setColor(Color.red);<br />
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 />
Die zugehörige HTML-Datei AllerAnfangApplet.html umfaßt:<br />
215 Teil <strong>de</strong>s Pakets java.awt<br />
216 Normalerweise geschieht dies über: import java.awt.Graphics<br />
217 vgl. pr32101<br />
236
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
<br />
<br />
Hallo!<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
In e<strong>in</strong>em Browser führt das zu <strong>de</strong>r folgen<strong>de</strong>n Darstellung:<br />
<strong>Java</strong>-Applets zeichnen sich durch Überschreiben <strong>de</strong>r „pa<strong>in</strong>t“-Metho<strong>de</strong> selbst. Wie<br />
wird die „pa<strong>in</strong>t“-Metho<strong>de</strong> aufgerufen?<br />
Es gibt drei verschie<strong>de</strong>ne Metho<strong>de</strong>n 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 <strong>de</strong>s Applets <strong>in</strong> <strong>de</strong>n Zeichenbereich. Sie wird immer aufgerufen,<br />
wenn e<strong>in</strong> Applet neu gezeichnet 218 wer<strong>de</strong>n muß. Das <strong>in</strong> <strong>de</strong>r „pa<strong>in</strong>t“-Metho<strong>de</strong> abgebene Graphics-<br />
Objekt enthält <strong>de</strong>n Grafikstatus, d.h. die aktuellen Merkmale <strong>de</strong>r Zeichnungsoberfläche.<br />
public void repa<strong>in</strong>t()<br />
Sie kann je<strong>de</strong>rzeit aufgerufen wer<strong>de</strong>n, wann auch immer das Applet neu gezeichnet wer<strong>de</strong>n muß. Sie<br />
ist <strong>de</strong>r Auslöser, die „pa<strong>in</strong>t“-Metho<strong>de</strong> sobald wie möglich aufzurufen und das Applet neu zu<br />
zeichnen. Sollten die repa<strong>in</strong>t()-Anweisungen schneller ablaufen, als <strong>Java</strong> diese verarbeiten kann,<br />
wer<strong>de</strong>n evtl. e<strong>in</strong>ige übersprungen. In vielen Fällen ist die Verzögerung zwischen <strong>de</strong>m Aufruf von<br />
repa<strong>in</strong>t() und <strong>de</strong>r eigentlichen Aktualisierung <strong>de</strong>s Fensters vernachlässigbar.<br />
public void update(Graphics g)<br />
Sie wird von repa<strong>in</strong>t() aufgerufen. Die „update“-Metho<strong>de</strong> löscht <strong>de</strong>n vollständigen<br />
Zeichenbereich 219 und ruft anschließend die „pa<strong>in</strong>t“-Metho<strong>de</strong> auf, die dann das Applet vollständig<br />
neu zeichnet. Der Aufruf <strong>de</strong>r „pa<strong>in</strong>t“-Metho<strong>de</strong> erfolgt also nicht direkt über die „repa<strong>in</strong>t“-Metho<strong>de</strong>,<br />
son<strong>de</strong>rn <strong>in</strong>direkt über die „update“-Metho<strong>de</strong>.<br />
Applets wer<strong>de</strong>n aus Sicherheitsgrün<strong>de</strong>n gewissen E<strong>in</strong>schränkungen unterworfen:<br />
218 Dies ist immer beim ersten Aufruf <strong>de</strong>s Applets <strong>de</strong>r Fall, aber auch je<strong>de</strong>smal dann, wenn das Applet-Fenster<br />
verschoben o<strong>de</strong>r zwischenzeitlich von e<strong>in</strong>em an<strong>de</strong>ren Fenster überlagert wur<strong>de</strong>.<br />
219 Das ruft oft <strong>de</strong>n unangenehmen Flimmereffekt bei schnellen Bildsequenzen hervor.<br />
237
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
- Applets können das Dateisystem <strong>de</strong>s Bernutzers nicht lesen und nicht beschreiben, abgesehen<br />
von bestimmten Verzeichnissen (die vom Benutzer durch e<strong>in</strong>e Zugriffskontrolliste, die<br />
standardäßig leer ist, bestimmt wer<strong>de</strong>n). E<strong>in</strong>ige Browser lassen ke<strong>in</strong>erlei Schreib- und Leseaktion<br />
<strong>de</strong>s Applets auf <strong>de</strong>m Client zu.<br />
- Applets können auf <strong>de</strong>m Client ke<strong>in</strong>erlei Programme ausführen.<br />
- Applets können normalerweise nur mit <strong>de</strong>m System kommunizieren, auf <strong>de</strong>nen sie gespeichert<br />
s<strong>in</strong>d.<br />
- Applets können ke<strong>in</strong>e ke<strong>in</strong>e nativen Programme <strong>de</strong>r lokalten Plattform la<strong>de</strong>n, auch ke<strong>in</strong>e<br />
geme<strong>in</strong>same Bibliotheken (wie DLL’s).<br />
3. Metho<strong>de</strong>n 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 <strong>de</strong>r Maustaste) stellt <strong>Java</strong> Ereignisbehandlungs-Metho<strong>de</strong>n<br />
<strong>de</strong>s JDK 1.0 bzw. JDK 1.1 zur Verfügung.<br />
Bsp. 220 : E<strong>in</strong> Applet zum Zeichnen von Punkten an <strong>de</strong>n Stellen, an <strong>de</strong>nen e<strong>in</strong>e<br />
Maustaste gedrückt wur<strong>de</strong>.<br />
// Import <strong>de</strong>r Pakete<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
// Top-Level Klassen-Deklaration <strong>de</strong>s 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 />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<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 />
// Ausgabemetho<strong>de</strong><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 />
220 pr32305<br />
238
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
Nach je<strong>de</strong>m 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()-Metho<strong>de</strong> ruft vor <strong>de</strong>r<br />
Ausführung <strong>de</strong>r pa<strong>in</strong>t()-Metho<strong>de</strong> die update()-Metho<strong>de</strong> auf, die<br />
anschließend pa<strong>in</strong>t() aufruft. „update()“ leert <strong>in</strong> Orig<strong>in</strong>alform <strong>de</strong>n<br />
Anzeigebereich <strong>de</strong>s 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 <strong>de</strong>s Anzeigebereichs.<br />
// Import <strong>de</strong>r Pakete<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
// Top-Level Klassen-Deklaration <strong>de</strong>s 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 />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<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 />
// Ausgabemetho<strong>de</strong><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 />
public void update(Graphics g)<br />
{<br />
pa<strong>in</strong>t(g);<br />
}<br />
}<br />
239
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
E<strong>in</strong>e überschriebene update()-Metho<strong>de</strong> kann <strong>de</strong>n 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 wer<strong>de</strong>n, daß alle o<strong>de</strong>r auch e<strong>in</strong>zelnen<br />
Co<strong>de</strong>teile <strong>in</strong> ihrem eigenen Thread laufen, ohne an<strong>de</strong>re Teile <strong>de</strong>s 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 wer<strong>de</strong>n:<br />
1. Erweitern <strong>de</strong>r Unterschrift <strong>de</strong>s Applets um implements Runnable<br />
2. H<strong>in</strong>zufügen e<strong>in</strong>er Instanzvariablen, die <strong>de</strong>n Thread <strong>de</strong>s Applet enthält<br />
3. Reduktion <strong>de</strong>r start()-Metho<strong>de</strong>, so daß sie außer <strong>de</strong>m Start <strong>de</strong>s Threads ke<strong>in</strong>e weiteren Threads<br />
enthält<br />
4. H<strong>in</strong>zufügen <strong>de</strong>r run()-Metho<strong>de</strong>, die <strong>de</strong>n eigentlichen Co<strong>de</strong> enthält, <strong>de</strong>n das Applet ausführen soll.<br />
Bsp.: E<strong>in</strong> Applet zur Anzeige von Datum und Uhrzeit, je<strong>de</strong> Sekun<strong>de</strong> wird<br />
aktualisiert 221 . Nach <strong>de</strong>n bisher vorliegen<strong>de</strong>n Erkenntnissen müßte das<br />
zugehörige Applet folgen<strong>de</strong> Gestalt haben:<br />
import java.awt.Graphics;<br />
import java.awt.Font;<br />
import java.util.Date;<br />
//<br />
// Top Level Deklaration <strong>de</strong>s 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 Metho<strong>de</strong>n<br />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<br />
public void start()<br />
{<br />
// Ausfuehrung <strong>de</strong>s Applet<br />
while (true)<br />
{<br />
datum = new Date();<br />
repa<strong>in</strong>t(); // Aufruf <strong>de</strong>r repa<strong>in</strong>t()-Metho<strong>de</strong><br />
try {Thread.sleep(1000); } // Pause von 1000 Millisekun<strong>de</strong>n<br />
catch(InterruptedException e) {}<br />
}<br />
}<br />
// Optional, aber sehr wahrsche<strong>in</strong>lich – die Ausgabemetho<strong>de</strong><br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.setFont(e<strong>in</strong>Font); // Setzen <strong>de</strong>s 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() wie<strong>de</strong>rholt mit jeweils <strong>de</strong>m aktuellen Wert von<br />
// „datum“ aufgerufen wird, wird die Zeichenkette je<strong>de</strong> Sekun<strong>de</strong><br />
//zur Ausgabe <strong>de</strong>s neuen Datums aufgerufen<br />
}<br />
}<br />
In <strong>de</strong>r start()-Metho<strong>de</strong> nimmt die while-Schleife alle Systemressourcen für<br />
sich <strong>in</strong> Anspruch (e<strong>in</strong>schl. <strong>de</strong>r Anzeige am Bildschirm). Deshalb funktioniert die<br />
221 vgl. pr42001<br />
240
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
digitale Uhr nicht. Außer<strong>de</strong>m kann das Applet nicht gestoppt wer<strong>de</strong>n, da die<br />
stop()-Metho<strong>de</strong> nicht aufgerufen wer<strong>de</strong>n kann. Die Lösung <strong>de</strong>s Problems liegt<br />
im erneuten Schreiben <strong>de</strong>s Applets mit Threads. Das Applet muß dazu mit <strong>de</strong>n<br />
vorgegebenen vier Arbeitsschritten erweitert wer<strong>de</strong>n.<br />
import java.awt.Graphics;<br />
import java.awt.Font;<br />
import java.util.Date;<br />
//<br />
// Top Level Deklaration <strong>de</strong>s 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 fa<strong>de</strong>n;<br />
// Eigene Metho<strong>de</strong>n<br />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<br />
public void start()<br />
{<br />
if (fa<strong>de</strong>n == null)<br />
{<br />
fa<strong>de</strong>n = new Thread(this);<br />
fa<strong>de</strong>n.start();<br />
}<br />
}<br />
public void stop()<br />
{<br />
if (fa<strong>de</strong>n != null)<br />
{<br />
fa<strong>de</strong>n.stop();<br />
fa<strong>de</strong>n = null;<br />
}<br />
}<br />
public void run()<br />
{<br />
// Ausfuehrung <strong>de</strong>s Applet, hier f<strong>in</strong><strong>de</strong>t die Animation statt<br />
while (true)<br />
{<br />
datum = new Date();<br />
repa<strong>in</strong>t(); // Aufruf <strong>de</strong>r repa<strong>in</strong>t()-Metho<strong>de</strong><br />
try {Thread.sleep(1000); } // Pause von 1000 Millisekun<strong>de</strong>n<br />
catch(InterruptedException e) {}<br />
}<br />
}<br />
// Optional, aber sehr wahrsche<strong>in</strong>lich – die Ausgabemetho<strong>de</strong><br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.setFont(e<strong>in</strong>Font); // Setzen <strong>de</strong>s 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() wie<strong>de</strong>rholt mit jeweils <strong>de</strong>m aktuellen Wert von<br />
// "datum" aufgerufen wird, wird die Zeichenkette je<strong>de</strong> Sekun<strong>de</strong><br />
// zur Ausgabe <strong>de</strong>s neuen Datums aufgerufen<br />
}<br />
}<br />
Das folgen<strong>de</strong> Gerüst umfaßt e<strong>in</strong> Muster für „multithread<strong>in</strong>g“-fähige Applets:<br />
// Name <strong>de</strong>r Klasse:<br />
// Beschreibung:<br />
241
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
// Import <strong>de</strong>r Pakete<br />
// import java.lang.*;<br />
// import java.applet.*;<br />
// import java.awt.*;<br />
// Top-Level-Klassen-Deklaration bzw. Def<strong>in</strong>ition <strong>de</strong>s Applets<br />
public Klassenname extends java.applet.Applet<br />
{<br />
// Variablen-Deklarationen bzw. Def<strong>in</strong>itionen<br />
// ...<br />
// Eigene Metho<strong>de</strong>n<br />
// ...<br />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<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 <strong>de</strong>stroy()<br />
{<br />
// ...<br />
}<br />
// Optional: die Ausgabemetho<strong>de</strong><br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
// ..<br />
}<br />
// Bei Multithread<strong>in</strong>g: Verwendung <strong>de</strong>r run-Metho<strong>de</strong><br />
public void run()<br />
{<br />
// ...<br />
}<br />
}<br />
242
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.3.4 Animation <strong>in</strong> Applets<br />
Animationsschritte<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. Entsprechen<strong>de</strong> häufige Wie<strong>de</strong>rholung <strong>de</strong>r Zeichnung, um <strong>de</strong>n E<strong>in</strong>druck von Bewegung zu<br />
vermitteln (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 <strong>de</strong>r Größe <strong>de</strong>s Ausgabebereichs<br />
- Positionieren <strong>de</strong>r Animation<br />
- Erstellen o<strong>de</strong>r La<strong>de</strong>n <strong>de</strong>r e<strong>in</strong>zelnen Animationsbil<strong>de</strong>r<br />
- Aufbau von e<strong>in</strong>zelnen Animationssequenzen<br />
Abspielen e<strong>in</strong>er Animation<br />
Die pa<strong>in</strong>t()-Metho<strong>de</strong> wird von <strong>Java</strong> aufgerufen, wenn e<strong>in</strong> Applet gezeichnet<br />
wer<strong>de</strong>n muß. <strong>Java</strong> kann aber auch aufgefor<strong>de</strong>rt wer<strong>de</strong>n, e<strong>in</strong> Bild zu e<strong>in</strong>em<br />
bestimmten Zeitpunkt nachzuzeichnen. Tut man das wie<strong>de</strong>rholt und schnell genug<br />
mit <strong>de</strong>r repa<strong>in</strong>t()-Metho<strong>de</strong>, 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 Pen<strong>de</strong>lAppl1 extends java.applet.Applet implements Runnable<br />
{<br />
// Instanzvariable<br />
// Position vom Zentrum <strong>de</strong>s schw<strong>in</strong>gen<strong>de</strong>n Pen<strong>de</strong>ls<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 Pen<strong>de</strong>l<br />
double theta = (double) 0.;<br />
//<br />
double wechsel = (double) 0.01;<br />
//<br />
<strong>in</strong>t xStart = 150, yStart = 20;<br />
// Radius <strong>de</strong>s Pen<strong>de</strong>ls<br />
double r = (double) 200;<br />
// Durchmesser <strong>de</strong>s Balls<br />
<strong>in</strong>t d = 20;<br />
Thread fa<strong>de</strong>n;<br />
// Metho<strong>de</strong>n<br />
public void <strong>in</strong>it()<br />
{<br />
setBackground(Color.yellow);<br />
}<br />
public void start()<br />
{<br />
243
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
if (fa<strong>de</strong>n == null)<br />
{<br />
fa<strong>de</strong>n = new Thread(this);<br />
fa<strong>de</strong>n.start();<br />
}<br />
}<br />
public void stop()<br />
{<br />
if (fa<strong>de</strong>n != null)<br />
{<br />
fa<strong>de</strong>n.stop();<br />
fa<strong>de</strong>n = 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 />
// Instanzvariable<br />
// Position vom Zentrum <strong>de</strong>s schw<strong>in</strong>gen<strong>de</strong>n Pen<strong>de</strong>ls<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 Pen<strong>de</strong>l<br />
double theta = (double) 0.;<br />
//<br />
double wechsel = (double) 0.01;<br />
//<br />
<strong>in</strong>t xStart = 150, yStart = 20;<br />
// Radius <strong>de</strong>s Pen<strong>de</strong>ls<br />
double r = (double) 200;<br />
// Durchmesser <strong>de</strong>s Balls<br />
<strong>in</strong>t d = 20;<br />
Thread fa<strong>de</strong>n;<br />
<strong>in</strong>t xAlt, yAlt;<br />
// Metho<strong>de</strong>n<br />
public void <strong>in</strong>it()<br />
{<br />
setBackground(Color.white);<br />
}<br />
public void start()<br />
{<br />
if (fa<strong>de</strong>n == null)<br />
{<br />
fa<strong>de</strong>n = new Thread(this);<br />
fa<strong>de</strong>n.start();<br />
}<br />
}<br />
public void stop()<br />
{<br />
if (fa<strong>de</strong>n != null)<br />
{<br />
fa<strong>de</strong>n.stop();<br />
fa<strong>de</strong>n = 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 />
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 />
Mit „double buffer<strong>in</strong>g“ wird e<strong>in</strong>e zweite Oberfläche geschaffen, <strong>in</strong> <strong>de</strong>r alles<br />
vorgezeichnet und dann auf e<strong>in</strong>mal <strong>in</strong> die Zeichnungsoberfläche <strong>de</strong>s Applet<br />
ausgegeben wird.<br />
Bsp. 223 :<br />
import java.awt.*;<br />
public class Pen<strong>de</strong>l extends java.applet.Applet implements Runnable<br />
{<br />
// Instanzvariable<br />
// Position vom Zentrum <strong>de</strong>s schw<strong>in</strong>gen<strong>de</strong>n Pen<strong>de</strong>ls<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 Pen<strong>de</strong>l<br />
double theta = (double) 0.;<br />
//<br />
double wechsel = (double) 0.01;<br />
//<br />
<strong>in</strong>t xStart = 150, yStart = 20;<br />
// Radius <strong>de</strong>s Pen<strong>de</strong>ls<br />
double r = (double) 200;<br />
// Durchmesser <strong>de</strong>s Balls<br />
<strong>in</strong>t d = 20;<br />
Thread fa<strong>de</strong>n;<br />
<strong>in</strong>t xAlt, yAlt;<br />
Image backgroundImage;<br />
Graphics backgroundGraphics;<br />
// Metho<strong>de</strong>n<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 (fa<strong>de</strong>n == null)<br />
{<br />
fa<strong>de</strong>n = new Thread(this);<br />
fa<strong>de</strong>n.start();<br />
}<br />
}<br />
public void stop()<br />
{<br />
if (fa<strong>de</strong>n != null)<br />
{<br />
fa<strong>de</strong>n.stop();<br />
fa<strong>de</strong>n = null;<br />
}<br />
}<br />
public void run()<br />
{<br />
223 pr32213, Pen<strong>de</strong>l.java<br />
246
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
3.3.5 Das La<strong>de</strong>n und Anzeigen von Bil<strong>de</strong>rn<br />
Den Umgang mit Bil<strong>de</strong>rn ermöglicht die Klasse Image <strong>de</strong>s Pakets java.awt. In<br />
e<strong>in</strong>em Applet können Metho<strong>de</strong>n <strong>de</strong>r Klassen Applet und Graphics zum La<strong>de</strong>n und<br />
Anzeigen von Bil<strong>de</strong>rn herangezogen wer<strong>de</strong>n. Bil<strong>de</strong>r wer<strong>de</strong>n als seperate Dateien<br />
außerhalb <strong>de</strong>r .class-Dateien von <strong>Java</strong> gespeichert. Falls die Image-Klasse<br />
verwen<strong>de</strong>t wird, muß das Bild im Format .GIF o<strong>de</strong>r .JPG vorliegen.<br />
La<strong>de</strong>n von Bil<strong>de</strong>rn. Es erfolgt mit <strong>de</strong>r Metho<strong>de</strong> getImage()aus <strong>de</strong>r Applet-Klasse,<br />
die mit e<strong>in</strong>em o<strong>de</strong>r zwei Argumenten aufgerufen wer<strong>de</strong>n kann:<br />
- Aufruf von getImage mit e<strong>in</strong>em Argument (e<strong>in</strong> Objekt vom Typ URL 224 )<br />
- Aufruf mit zwei Argumenten (Basis URL <strong>de</strong>s Bilds (URL-Objekt)) und e<strong>in</strong> Str<strong>in</strong>g, <strong>de</strong>r <strong>de</strong>n relativen<br />
Pfad o<strong>de</strong>r <strong>de</strong>n Date<strong>in</strong>amen <strong>de</strong>s aktuellen Bilds angibt.<br />
Die Klasse Applet besitzt zwei Metho<strong>de</strong>n zum Erzeugen e<strong>in</strong>er Basis-URL ohne<br />
Angaben fester Adressen im Programm:<br />
- die Metho<strong>de</strong> getDocumentBase() gibt e<strong>in</strong> URL-Objekt zurück, das <strong>de</strong>n Ordner (das<br />
Verzeichnis) repräsentiert, die die Webseite mit <strong>de</strong>m Applet enthält.<br />
- die Metho<strong>de</strong> getCo<strong>de</strong>Base() gibt e<strong>in</strong> Verzeichnis (Ordner) zurück, das das Verzeichnis<br />
repräsentiert, <strong>in</strong> <strong>de</strong>m sich die .class-Datei <strong>de</strong>r Hauptklasse <strong>de</strong>s Applet bef<strong>in</strong><strong>de</strong>t.<br />
Ausgabe von Bil<strong>de</strong>rn. Mit <strong>de</strong>r Metho<strong>de</strong> drawImage() <strong>de</strong>r Graphics-Klasse kann e<strong>in</strong><br />
Bild, das <strong>in</strong> e<strong>in</strong> Image-Objekt gela<strong>de</strong>n wur<strong>de</strong>, angezeigt wer<strong>de</strong>n. drawImage() hat 4<br />
Argumente:<br />
- das Image-Objekt, das angezeigt wer<strong>de</strong>n 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 wer<strong>de</strong>n:<br />
public pa<strong>in</strong>t(Graphigs g)<br />
{<br />
g.drawImage(imageObjekt, xKoord, yKoord, this);<br />
}<br />
Bsp. 225 :<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 />
224 Adressen im World Wi<strong>de</strong> Web wer<strong>de</strong>n durch URL-Objekte repräsentiert. Die Klasse URL (Uniform<br />
Resource Locator) ist Teil <strong>de</strong>s Pakets java.net<br />
225 vgl. pr33501<br />
248
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.3.6 Die Ausgabe von Sound<br />
Das JDK bietet Möglichkeiten zur Ausgabe von Sound 226 an. Die Ausgabe von<br />
Sound kann über zwei Metho<strong>de</strong>n <strong>de</strong>r Klasse Applet erfolgen:<br />
public void play(URL url)<br />
public void play(URL url, Str<strong>in</strong>g name)<br />
hier kann entwe<strong>de</strong>r die URL e<strong>in</strong>er Sound-Datei o<strong>de</strong>r die Komb<strong>in</strong>ation von<br />
Verzeichnis-URL und Date<strong>in</strong>amen angegeben wer<strong>de</strong>n. Die Übergabe <strong>de</strong>r URLs<br />
geschieht über die Applet-Metho<strong>de</strong>n:<br />
public URL getCo<strong>de</strong>Base()<br />
public URL getDocumentbase()<br />
Die Metho<strong>de</strong>n liefern e<strong>in</strong>e URL <strong>de</strong>s Verzeichnisses, aus <strong>de</strong>m das Applet gestartet wur<strong>de</strong> bzw. <strong>in</strong> <strong>de</strong>m<br />
die aktuelle HTML-Seite liegt. Der nachteil dieser Vorgehensweise ist, daß die Sound-datei bei je<strong>de</strong>m<br />
Aufruf neu gela<strong>de</strong>n wer<strong>de</strong>n muß.<br />
public getAudioClip(URL url, Str<strong>in</strong>g name)<br />
Hier wird e<strong>in</strong> Objekt <strong>de</strong>r Klasse AudioClip beschafft, das dann abgespielt wer<strong>de</strong>n<br />
kann. AudioClip stellt drei Metho<strong>de</strong>n zur Verfügung:<br />
public void play()<br />
startet die zuvor gela<strong>de</strong>ne Sound-Datei und spielt sie genau e<strong>in</strong>mal ab.<br />
public void loop()<br />
startet die zuvor gela<strong>de</strong>ne Sound-Datei und spielt <strong>de</strong>n Sound <strong>in</strong> e<strong>in</strong>er Endlosschleife<br />
immer wie<strong>de</strong>r ab.<br />
public void stop()<br />
Darüber kann die zuvor mit loop() <strong>in</strong>iziierte Schleife been<strong>de</strong>t wer<strong>de</strong>n.<br />
Bsp. 227 :<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 />
226 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 <strong>de</strong>r<br />
Sun-Welt und legt e<strong>in</strong> Sample im Format 8 Bit Mono, Sampl<strong>in</strong>g-Rate 8 kHz, µ -lawKompression ab)<br />
vorliegen mußte. Seit <strong>de</strong>m JDK 1.2 wer<strong>de</strong>n auch die Sample-Formate WAV und AIFF sowie die Midi-Formate<br />
Typ 0 und Typ 1 und RMF unterstützt. Zu<strong>de</strong>m gibt es e<strong>in</strong>ige Shareware- o<strong>de</strong>r Freeware-Tools, die zwischen<br />
verschie<strong>de</strong>n Formaten konvertieren können (z.B. CoolEdit o<strong>de</strong>r Gold-Wave).<br />
227 Vgl. pr33602, Aufruf z.B.: java PR33602 file:///c:/w<strong>in</strong>nt\media\r<strong>in</strong>g<strong>in</strong>.wav<br />
249
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
}<br />
catch (MalformedURLException e)<br />
{<br />
System.out.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />
}<br />
3.3.7 Die Klasse JApplet<br />
Diese Klasse bef<strong>in</strong><strong>de</strong>t sich im Paket javax.sw<strong>in</strong>g, gehört aber logisch zu <strong>de</strong>n<br />
Applets. Sie erweitert die Applets um typische Sw<strong>in</strong>g-Eigenschaften.<br />
java.awt.Panel<br />
java.applet.Applet<br />
javax.sw<strong>in</strong>g.JApplet<br />
><br />
public JApplet()<br />
><br />
public void setJMenuBar(JMenuBar menuBar)<br />
public JMenuBar getJMenuBar()<br />
public void setLayout(LayoutManager manager)<br />
public Conta<strong>in</strong>er getContentPane()<br />
public void setContentPane(Conta<strong>in</strong>er contentPane)<br />
....<br />
Abb. Die Klasse JApplet<br />
250
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.3.8 Das Interface AppletContext<br />
Die Referenz vom Typ <strong>de</strong>s Interface AppletContext dient vorwiegend zur<br />
Kommunikation zwischen Applet und <strong>de</strong>m Webbrowser bzw. an<strong>de</strong>ren Applets.<br />
><br />
AppletContext<br />
public Applet getApplet(Str<strong>in</strong>g name)<br />
public Enumeration getApplets()<br />
public AudioClip getAudioClip(URL url)<br />
public Image getImage(URL url)<br />
public void showDocument(URL url)<br />
public void showDocument(URL url, Str<strong>in</strong>g target)<br />
public void showStatus(Str<strong>in</strong>g status)<br />
Abb.: Das Interface AppletContext<br />
Mit Hilfe von z.B. getAppletContext().getApplets() kann auf an<strong>de</strong>re Applets<br />
Bezug genommen wer<strong>de</strong>n. Die Metho<strong>de</strong> showDocument() lädt e<strong>in</strong>e Webseite <strong>in</strong> <strong>de</strong>n<br />
Browser, auf <strong>de</strong>m das Applet läuft.<br />
251
<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 folgen<strong>de</strong>rmaßen gestaltet se<strong>in</strong>:<br />
- Anwendung und grafische Benutzeroberfläche sollen möglichst unabhängig vone<strong>in</strong>an<strong>de</strong>r se<strong>in</strong>, <strong>in</strong><br />
je<strong>de</strong>m Fall aber sauber vone<strong>in</strong>an<strong>de</strong>r getrennt se<strong>in</strong> (Anwendungsklasse, GUI-Klasse).<br />
- Je<strong>de</strong>s GUI-Objekt muß se<strong>in</strong>en Anwendungsfall kennen, um <strong>de</strong>sssen Metho<strong>de</strong>n aufrufen zu<br />
können<br />
- Eigentlich müßte umgekehrt je<strong>de</strong>s Anwendungsobjekt „se<strong>in</strong> GUI-Objekt“ kennen, z.B. zur Anzeige<br />
<strong>de</strong>r Anfangswerte<br />
- Das Hauptprogramm „<strong>de</strong>generiert“ 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 />
wer<strong>de</strong>n. Die eigene Klasse muß von <strong>de</strong>r Klasse Observable abgeleitet se<strong>in</strong>. Die<br />
Observable-Klasse erlaubt es e<strong>in</strong>em Objekt, an<strong>de</strong>re Objekte zu <strong>in</strong>formieren, wenn es<br />
e<strong>in</strong>e Än<strong>de</strong>rung erfährt.<br />
public class java.util.Observable<br />
{<br />
Observable();<br />
public void addObserver(Observer o);<br />
public void <strong>de</strong>leteObserver(Observer o);<br />
public void <strong>de</strong>leteObservers();<br />
public <strong>in</strong>t countObservers);<br />
protected void setChanged();<br />
portected void clearChanged();<br />
public boolean hasChanged();<br />
public void notifyObservers();<br />
public void notifyObservers(Object arg);<br />
}<br />
Metho<strong>de</strong>n: Die wichtigsten Metho<strong>de</strong>n beim Erzeugen e<strong>in</strong>er Subklasse von<br />
Observable s<strong>in</strong>d „setChanged“ und „notifyObservers“. Die „setChanged“-<br />
Metho<strong>de</strong> markiert, daß Observable verän<strong>de</strong>rt wur<strong>de</strong>. Beim Aufruf von<br />
„notifyObservers“ wer<strong>de</strong>n die Observer benachrichtigt.<br />
protected void setChanged()<br />
setzt e<strong>in</strong> <strong>in</strong>ternes Flag für die Modifikation (wird von „notifyObservers“ verwen<strong>de</strong>t). Es wird<br />
automatisch gelöscht, wenn „notifyObservers“ aufgerufen wird, kann aber auch manuell mit <strong>de</strong>r<br />
„clearChanged“-Metho<strong>de</strong> gelöscht wer<strong>de</strong>n.<br />
protected void clearChanged()<br />
public void notifyObservers()<br />
prüft, ob das changed-Flag gesetzt wur<strong>de</strong>. Ist dies nicht <strong>de</strong>r Fall, kann ke<strong>in</strong>e Mitteilung über e<strong>in</strong>e<br />
Än<strong>de</strong>rung versen<strong>de</strong>t wer<strong>de</strong>n.<br />
public void notifyObservers(Object arg)<br />
Das Argument kann zur Übergabe zusätzlicher Information über die Modifikation dienen. Ohne<br />
Parameter entspricht <strong>de</strong>r Aufruf e<strong>in</strong>em Aufruf mit <strong>de</strong>m Argument Null.<br />
public boolean hasChanged()<br />
stellt fest, ob e<strong>in</strong> Objekt von Interesse modifiziert wur<strong>de</strong>.<br />
public void addObserver(Observer obs)<br />
252
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Mit dieser Metho<strong>de</strong> können Observer ihr Interesse an e<strong>in</strong>em beliebigen Observable bekun<strong>de</strong>n.<br />
public void <strong>de</strong>leteObserver (Observer obs)<br />
Mit dieser Metho<strong>de</strong> kann e<strong>in</strong> Observer die Überwachung <strong>de</strong>r entsprechen<strong>de</strong>n Observables been<strong>de</strong>n<br />
public void <strong>de</strong>leteObservers()<br />
löscht die Liste aller Observer<br />
public <strong>in</strong>t countObservers()<br />
liefert die Anzahl <strong>de</strong>r für <strong>in</strong> Observable registrierten Observer<br />
Das Interface Observer<br />
Je<strong>de</strong> Klasse, die Mitteilungen über Modifikationen e<strong>in</strong>es Observable bekommen<br />
möchte, muß das Observer-Interface implementieren. Dieses Interface besteht aus<br />
e<strong>in</strong>er e<strong>in</strong>zigen Metho<strong>de</strong>:<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än<strong>de</strong>rt wur<strong>de</strong>. Wur<strong>de</strong> „notifyObservers“ ohne Argument aufgerufen,<br />
dann ist arg Null.<br />
Observable-Observer: Kopplung von Anwendung und GUI<br />
Die Klasse Observable 228 erlaubt e<strong>in</strong>em Objekt, Informationen an an<strong>de</strong>re Objekte<br />
zu geben, wenn es e<strong>in</strong>e Än<strong>de</strong>rung erfährt. Beim Erstellen von Benutzeroberflächen<br />
kann es verschie<strong>de</strong>ne Möglichkeiten zur Än<strong>de</strong>rung e<strong>in</strong>es Datenobjekts geben. E<strong>in</strong>e<br />
solche Än<strong>de</strong>rung kann wie<strong>de</strong>rum die Aktualisierung verschie<strong>de</strong>ner Teile e<strong>in</strong>er<br />
Anzeige zur Folge haben.<br />
Bsp.: 229<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.util.*;<br />
class BoxObservable extends Observable<br />
{<br />
public void notifyObservers(Object b)<br />
{<br />
setChanged();<br />
super.notifyObservers(b);<br />
}<br />
}<br />
public class BoxObserver extends Frame<br />
{<br />
Observable notifier = new BoxObservable();<br />
public BoxObserver(<strong>in</strong>t grid)<br />
{<br />
setTitle("Demonstration Observer");<br />
setLayout(new GridLayout(grid,grid));<br />
for (<strong>in</strong>t x = 0; x < grid; x++)<br />
for (<strong>in</strong>t y = 0; y < grid; y++)<br />
add(new OCBox(x, y, notifier));<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
228 Das Konzept für diese Klasse ist e<strong>in</strong>e Leihgabe von Smalltalk und unter <strong>de</strong>m namen Mo<strong>de</strong>l-View-Controller<br />
(MVC) bekannt.<br />
229 pr34100<br />
253
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
<strong>in</strong>t grid = 8;<br />
if (args.length > 0)<br />
grid = Integer.parseInt(args[0]);<br />
Frame f = new BoxObserver(grid);<br />
f.setSize(500,400); f.setVisible(true);<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 />
{ System.exit(0); }<br />
});<br />
}<br />
}<br />
class OCBox extends Canvas<br />
implements Observer<br />
{<br />
Observable notifier;<br />
<strong>in</strong>t x, y;<br />
Color fFarbe = neueFarbe();<br />
static f<strong>in</strong>al Color[] farben = {<br />
Color.black, Color.blue, Color.cyan,<br />
Color.darkGray, Color.gray, Color.green,<br />
Color.lightGray, Color.magenta, Color.orange,<br />
Color.p<strong>in</strong>k, Color.red, Color.white, Color.yellow<br />
};<br />
OCBox(<strong>in</strong>t x, <strong>in</strong>t y, Observable notifier)<br />
{<br />
this.x = x; this.y = y;<br />
notifier.addObserver(this); this.notifier = notifier;<br />
addMouseListener(new ML());<br />
}<br />
static f<strong>in</strong>al Color neueFarbe()<br />
{<br />
return farben[(<strong>in</strong>t) (Math.random() * farben.length)];<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.setColor(fFarbe); Dimension d = getSize();<br />
g.fillRect(0, 0, d.width, d.height);<br />
}<br />
class ML extends MouseAdapter<br />
{<br />
public void mousePressed(MouseEvent e)<br />
{ notifier.notifyObservers(OCBox.this); }<br />
}<br />
public void update(Observable o, Object arg)<br />
{<br />
OCBox clicked = (OCBox) arg;<br />
if (nextTo(clicked))<br />
{ fFarbe = clicked.fFarbe; repa<strong>in</strong>t(); }<br />
}<br />
private f<strong>in</strong>al boolean nextTo(OCBox b)<br />
{<br />
return Math.abs(x - b.x)
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.5 Sw<strong>in</strong>g<br />
Die grundlegen<strong>de</strong> GUI-Programmierung <strong>in</strong> <strong>Java</strong> wird durch die Klassenbibliothek<br />
AWT (Abstrach W<strong>in</strong>dow Toolkit) ermöglicht. Dabei wer<strong>de</strong>n <strong>in</strong> Wirklichkeit die<br />
graphischen Elemente nicht durch die AWT komplett realisiert, son<strong>de</strong>rn die<br />
Erzeugung wird im wesentlichen an die jeweilige Plattform (W<strong>in</strong>dows, Solaris, Mac)<br />
<strong>de</strong>legiert. Das im H<strong>in</strong>tergrund erzeugte und arbeiten<strong>de</strong> Element wird dann als „Peer“-<br />
Komponente bezeichnet. Die Klassenbibliothek kapselt <strong>de</strong>n Zugriff auf diese<br />
Elemente und erleichtert damit auch teilweise die Handhabung e<strong>in</strong>zelner Objekte.<br />
1996 erstellte Netscape e<strong>in</strong>e GUI-Bibliothek „Internet Foundation Classes“ mit<br />
komplett an<strong>de</strong>rem E<strong>in</strong>satz. Die Peer-Funktionalität wird auf e<strong>in</strong> M<strong>in</strong>imum reduziert:<br />
E<strong>in</strong> Fenster zu erstellen, darauf zu zeichnen und dieses wie<strong>de</strong>r zu schliessen.<br />
Dadurch wird e<strong>in</strong>e geme<strong>in</strong>same Basis für alle Elemente <strong>de</strong>r Benutzeroberfläche<br />
geschaffen, auf <strong>de</strong>r aufbauend alle GUI-Elemente wie Schaltflächen, Listen, Menüs<br />
usw. gezeichnet wer<strong>de</strong>n konnten. Die komplette Funktionalität muß dann für alle<br />
Komponenten „nachgebaut“ wer<strong>de</strong>n, mit <strong>de</strong>m Vorteil e<strong>in</strong>er e<strong>in</strong>heitlchen,<br />
plattformübergreifen<strong>de</strong>n Lösung. Diese Lösung wur<strong>de</strong> geme<strong>in</strong>sam von Netscape und<br />
Sun ausgebaut und verbessert, wodurch e<strong>in</strong>e nicht peerbasierte GUI-Bibliothek als<br />
Teil <strong>de</strong>r <strong>Java</strong> Foundation Classes (JFC) für die Benutzeroberfläche mit <strong>de</strong>m Namen<br />
Sw<strong>in</strong>g entstan<strong>de</strong>n ist.<br />
Sw<strong>in</strong>g 230 ist e<strong>in</strong>e Erweiterung <strong>de</strong>s 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 <strong>de</strong>s 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 wer<strong>de</strong>n kann.<br />
Die grafische Benutzeroberfläche für <strong>Java</strong> Programme "Sw<strong>in</strong>g" umfasst die<br />
folgen<strong>de</strong>n drei wesentlichen Konzepte:<br />
- Komponenten (Schnittstellenelemente wie z.B. Buttons, Menüs, ...). Sw<strong>in</strong>g-Komponenten wer<strong>de</strong>n<br />
auf gleiche Weise verwen<strong>de</strong>t wie die Komponenten <strong>de</strong>s AWT: Erzeugen e<strong>in</strong>er Komponente über <strong>de</strong>n<br />
Konstruktor, Aufruf <strong>de</strong>r Metho<strong>de</strong>n <strong>de</strong>r Komponente.<br />
- Conta<strong>in</strong>er (Behälter, die mit Komponenten gefüllt wer<strong>de</strong>n, z.B. Fenster, Dialoge, Panels,...).<br />
- Events (Nachrichten über Benutzeraktionen mit Maus, Tastatur bzw. Verän<strong>de</strong>rung von<br />
Komponenten o<strong>de</strong>r Systemstatus (Zeit<strong>in</strong>tervall vergangen, Netzwerkanfragen, ...).<br />
230 vgl. 5.6<br />
255
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.6 <strong>Java</strong> Beans<br />
3.6.1 Wie<strong>de</strong>rverwendbare Softwarekomponenten<br />
Unter e<strong>in</strong>er Software-Komponente 231 versteht man:<br />
E<strong>in</strong>e Komponente ist e<strong>in</strong> Stück Software, das kle<strong>in</strong> genug ist, um es <strong>in</strong> e<strong>in</strong>em Stück zu erzeugen und<br />
pflegen zu können, groß genug ist, um e<strong>in</strong>e s<strong>in</strong>nvoll e<strong>in</strong>setzbare Funktionalität zu bieten und e<strong>in</strong>e<br />
<strong>in</strong>dividuelle Unterstützung zu rechtfertigen, sowie mit standardisierten Schnittstelle ausgestattet ist,<br />
um mit an<strong>de</strong>ren Komponenten zusammen zu arbeiten.<br />
Zu <strong>de</strong>n grundlegen<strong>de</strong>n Eigenschaften e<strong>in</strong>er Softwarekomponente zählen:<br />
- e<strong>in</strong>e Softwarekomponente ist e<strong>in</strong> ausführbares Programm<br />
- sie realisiert e<strong>in</strong>e klar abgegrenzte Programmfunktionalität (z.B. e<strong>in</strong> GUI-Control o<strong>de</strong>r e<strong>in</strong><br />
Berechnungsmodul)<br />
- ihre Implementierung ist nach außen nicht transparent (black-box-Mo<strong>de</strong>ll)<br />
- sie verfügt über öffentliche Schnittstellen, über die auf die Funktionalität <strong>de</strong>r Komponente zugegriffen<br />
wer<strong>de</strong>n kann (Eigenschaften, Metho<strong>de</strong>n, Ereignisse).<br />
- e<strong>in</strong>e Softwarekomponente lässt sich <strong>in</strong> umfangreichere Programme <strong>in</strong>tegrieren<br />
- im Unterschied zu Objekten s<strong>in</strong>d Komponenten auf e<strong>in</strong>e abstrakten Ebene angesie<strong>de</strong>lt und nur lose<br />
mite<strong>in</strong>an<strong>de</strong>t verkoppelt. Das soll vor allem die e<strong>in</strong>fache Wie<strong>de</strong>rverwendbarkeit von Komponenten<br />
gewährleisten<br />
Bisher gibt es ke<strong>in</strong>e e<strong>in</strong>heitliche Entwicklungsmetho<strong>de</strong> für component ware. Es<br />
existieren e<strong>in</strong>e Reihe konkurrieren<strong>de</strong>r Komponentenarchitekturen, u.a.<br />
- Microsoft ActiveX/COM/DCOM als Weiterentwicklung von OLE(object l<strong>in</strong>k<strong>in</strong>g and embedd<strong>in</strong>g)<br />
- <strong>Java</strong> Beans<br />
- CORBA Bus<strong>in</strong>ess Objects<br />
Sie s<strong>in</strong>d z.T. untere<strong>in</strong>an<strong>de</strong>r <strong>in</strong>teroperable, d.h. e<strong>in</strong> <strong>Java</strong> Beans kann als CORBAfähiges<br />
Objekt ausgestattet se<strong>in</strong> o<strong>de</strong>r im Rahmen von ActiveX e<strong>in</strong>gesetzt wer<strong>de</strong>n<br />
(über e<strong>in</strong>e ActiveX-Bridge, die das Bean als Actve-X-Komponente verpackt).<br />
Für die Komponentenentwicklung von e<strong>in</strong>zelnen Beans stehen folgen<strong>de</strong><br />
Funktionalitäten bereit:<br />
- Eigenschaften (properties) und Anpassung (customization) von Komponenten<br />
- Ereignisverarbeitung, um unterschiedliche Komponenten mite<strong>in</strong>an<strong>de</strong>r zu verknüpfen und sie<br />
kommunizieren zu lassen<br />
- Introspektion (<strong>in</strong>trospection), so dass e<strong>in</strong> Entwicklungswerkzeug erkennen kann, wie e<strong>in</strong> Bean<br />
arbeitet.<br />
- Persistenz und Verpacken von Komponenten, so dass <strong>in</strong> e<strong>in</strong>em Entwicklungswerkzeug angepasstes<br />
bzw. modifiziertes Bean <strong>in</strong> e<strong>in</strong>em neuen Zustand gespeichert wer<strong>de</strong>n kann.<br />
Die wichtigsten Merkmale e<strong>in</strong>es Beans s<strong>in</strong>d:<br />
- se<strong>in</strong>e Eigenschaften (properties)<br />
- se<strong>in</strong>e Metho<strong>de</strong>n, die von an<strong>de</strong>ren Komponenten aufgerufen wer<strong>de</strong>n können.<br />
- Ereignisse / Nachrichen, die es auslöst.<br />
231 Die Def<strong>in</strong>ition wur<strong>de</strong> zitiert nach: Griffel, Frank: Componentenware – Konzepte und Techniken e<strong>in</strong>es<br />
Softwareparadigma, dpunkt-Verlag, 1998<br />
256
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
3.6.2 Komponenten für <strong>Java</strong>: Beans<br />
<strong>Java</strong>Beans ist das Komponentenmo<strong>de</strong>ll von <strong>Java</strong>. Diese Komponenten haben e<strong>in</strong>e<br />
genauere und für Programmierwerkzeuge verständlichere Schnittstellen<strong>de</strong>f<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 <strong>de</strong>n 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 Metho<strong>de</strong>n Ereignisse<br />
Abb.: Die <strong>Java</strong>Bean-Features<br />
1. Properties s<strong>in</strong>d die öffentlichen, mit Namen versehenen Attribute o<strong>de</strong>r Eigenschaften. Über diese<br />
Properties s<strong>in</strong>d Beans an die Vorstellungen <strong>de</strong>s Programmierers anpassbar, ohne daß er er <strong>de</strong>n<br />
Quellco<strong>de</strong> än<strong>de</strong>rn und darauf irgen<strong>de</strong><strong>in</strong> Zugriff haben muß. Die Implementierung von Properties<br />
erfolgt durch entsprechen<strong>de</strong> lesen<strong>de</strong> und schreiben<strong>de</strong> Metho<strong>de</strong>n, die e<strong>in</strong>er Namenskonvention<br />
(„Design-Pattern“ 232 ) gehorchen. Die <strong>Java</strong>-Beans-Architektur unterschei<strong>de</strong>t zwischen sog.<br />
In<strong>de</strong>xed, Bound und Constra<strong>in</strong>t Properties.<br />
2. Die öffentlichen Metho<strong>de</strong>n, die e<strong>in</strong>e Bean ausführen kann<br />
3. E<strong>in</strong> <strong>Java</strong>Bean erzeugt Ereignisse, z.B. dann, wenn sich ihre Properties än<strong>de</strong>rn.<br />
Diese drei Arten von Features s<strong>in</strong>d im Interface BeanInfo dokumentiert.<br />
Das Paket java.beans enthält folgen<strong>de</strong> Klassen, Schnittstellen und Ausnahmen:<br />
AppletInitalizer<br />
BeanInfo<br />
Customizer<br />
DesignMo<strong>de</strong><br />
PropertyChangeListener<br />
PropertyEditor<br />
VetoableChangeListener<br />
Visibility<br />
Metho<strong>de</strong>n für die Initialisierung von Beans, die auch Applets s<strong>in</strong>d<br />
Metho<strong>de</strong>n für die Beschreibung e<strong>in</strong>es Beans, z.B.<br />
getBeanDescriptor()<br />
Schnittstelle für Klassen, die <strong>de</strong>r Anpassung von Beans dienen<br />
(Bean-Editoren, Bean-Customizer)<br />
Metho<strong>de</strong>n, die feststellen, ob sich e<strong>in</strong> Bean <strong>in</strong> e<strong>in</strong>er Design- o<strong>de</strong>r<br />
Lauffzeitumgebung bef<strong>in</strong><strong>de</strong>t<br />
Lauscherschnittstelle, die Eigenschaftsän<strong>de</strong>rungsnachrichten<br />
abfängt<br />
Metho<strong>de</strong>n für Klassen, die das Editieren von Beans bzw. ihrer<br />
Eigenschaften erlauben.<br />
Lauscherschnittstelle für sog. "constra<strong>in</strong>t properties", d.h.<br />
Eigenschaften <strong>de</strong>ren Än<strong>de</strong>rung von "externen Faktoren" abhängt,<br />
d.h. gegen <strong>de</strong>ren Än<strong>de</strong>rung von an<strong>de</strong>ren Komponenten e<strong>in</strong> Veto<br />
e<strong>in</strong>gelegt wer<strong>de</strong>n kann.<br />
Metho<strong>de</strong>n zur Feststellung, ob e<strong>in</strong> Bean <strong>in</strong> e<strong>in</strong>em GUI ausgeführt<br />
wird.<br />
Abb.: Schnittstellen <strong>in</strong> java.beans<br />
232 Unter Design Pattern s<strong>in</strong>d e<strong>in</strong>fache Muster auf <strong>de</strong>r Basis von Metho<strong>de</strong>nnamen und Signaturen geme<strong>in</strong>t, z.B.<br />
- E<strong>in</strong> Property mit <strong>de</strong>m Namen Color, für das sowohl schreiben<strong>de</strong> als auch lesen<strong>de</strong> Zugriffe erlaubt s<strong>in</strong>d wird<br />
durch Implementierung <strong>de</strong>r Metho<strong>de</strong>n „public Color getColor()“ und „public void setColor()“ dargestellt.<br />
- Das Entwurfsmuster für das Verb<strong>in</strong><strong>de</strong>n e<strong>in</strong>es Event-Handlers mit e<strong>in</strong>er Event-Source besteht aus e<strong>in</strong>er<br />
Metho<strong>de</strong>, die mit „set“ beg<strong>in</strong>nt und mit „Listener“ en<strong>de</strong>t und e<strong>in</strong> Argument besitzt. Außer<strong>de</strong>m muß e<strong>in</strong>e<br />
Vererbung vom EventListener-Interface vorhan<strong>de</strong>n se<strong>in</strong>.<br />
257
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
BeanDescriptor<br />
Beans<br />
EventSetDescriptor<br />
FeatureDescriptor<br />
Introspector<br />
MethodDescriptor<br />
ParameterDescriptor<br />
PropertyChangeEvent<br />
PropertyChangeSupport<br />
PropertyDescriptor<br />
PropertyEditorManager<br />
PropertyEditorSupport<br />
SimpleBeanInfo<br />
VetoableChangeSupport<br />
Klasse für <strong>de</strong>n Zugriff auf allgeme<strong>in</strong>e Eigenschaften e<strong>in</strong>er<br />
Komponente<br />
Hilfsklasse mit nützlichen Metho<strong>de</strong>n um Informationen über e<strong>in</strong><br />
Bean zu erhalten (isDesignTime(), isGuiAvailable(), etc.)<br />
beschreibt Ereignistypen, die von e<strong>in</strong>em Bean ausgelöst wer<strong>de</strong>n.<br />
Superklasse aller Deskriptor-Klassen für Beans mit generischen<br />
Informationsmetho<strong>de</strong>n (z.B. getNames(), attributeNames(),<br />
getValues(), etc.).<br />
Zugriff auf Beaneigenschaften zur Design-Zeit durch Metho<strong>de</strong>n wie<br />
z.B. getBeanInfo().<br />
beschrebt e<strong>in</strong>e Mretho<strong>de</strong> e<strong>in</strong>es <strong>Java</strong> Bean, die von außen<br />
zugänglich ist<br />
zusätzliche Information über Parameter (d.h. mehr als das, was<br />
man über die reflection-Metho<strong>de</strong>n ermitteln kann<br />
Nachrichtenklasse für die Verarbeitung von Eigenschaftsän<strong>de</strong>rungsachrichten<br />
Hilfsklasse für die Verarbeitung von Eigenschaftsän<strong>de</strong>rungsnachrichten<br />
beschreibt die Eigenschaft e<strong>in</strong>es Bean, die von außen zugänglich<br />
ist.<br />
ist beim Aufbau e<strong>in</strong>es geeigneten Editor für e<strong>in</strong> Bean behilflich<br />
Hilfsklasse für <strong>de</strong>n Aufbau von Editoren<br />
Hilfsklasse für die Generierung bon BeanInfo-Objekten<br />
Hilfsklasse für die Verarbeitung von Eigenschaften, gegen die e<strong>in</strong><br />
Veto möglich ist.<br />
Abb.: Klassen <strong>in</strong> java.beans<br />
IntrospectionException<br />
PropertyVetoException<br />
tritt bei Fehlern während <strong>de</strong>r Introspektion e<strong>in</strong>es Beans auf<br />
tritt auf, falls e<strong>in</strong>e Eigenschaft e<strong>in</strong>es Bean auf e<strong>in</strong>en nicht<br />
akzeptablen Wert geän<strong>de</strong>rt wer<strong>de</strong>n soll<br />
Abb.: Ausnahmen <strong>in</strong> java.beans<br />
3.6.3 Enterprise <strong>Java</strong> Beans<br />
„<strong>Java</strong> Beans“ wur<strong>de</strong> als e<strong>in</strong> lokales Komponentenmo<strong>de</strong>ll 233 entworfen. Das <strong>Java</strong>-<br />
Beans-Mo<strong>de</strong>ll sieht aber auch die Nutzung entfernter Ressourcen vor: Enterprise<br />
<strong>Java</strong> Beans. Damit wer<strong>de</strong>n Anb<strong>in</strong>dungen zur folgen<strong>de</strong>n Application Interfaces<br />
möglich:<br />
- <strong>Java</strong> Database Connectivity -API: Es gestattet <strong>de</strong>n Zugriff auf relationale Datenbanken.<br />
- Remote Method Invocation: RMI stellt e<strong>in</strong> API zur Verfügung, mit <strong>de</strong>ssen Hilfe die Kommunikation<br />
zweier Komponenten über Adreß- o<strong>de</strong>r Masch<strong>in</strong>enräume h<strong>in</strong>weg möglich ist. RMI ist e<strong>in</strong>e Art<br />
objektorientierter RPC-Mechanismus (Remote Procedure Call), <strong>de</strong>r speziell für <strong>Java</strong> entwickelt<br />
wur<strong>de</strong>.<br />
- CORBA<br />
233 D.h.: Die Kommunikation zwischen Komponenten f<strong>in</strong><strong>de</strong>t auf e<strong>in</strong>er Masch<strong>in</strong>e statt.<br />
258
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4. Grafik und Bildverarbeitung<br />
Mit e<strong>in</strong>er Instanz von Graphics kann gezeichnet wer<strong>de</strong>n, 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> <strong>de</strong>r Klasse Component als public Graphics getGraphics() <strong>de</strong>f<strong>in</strong>ierte<br />
Metho<strong>de</strong> gibt <strong>de</strong>n „Graphics“-Kontext von <strong>de</strong>r Komponente zurück bzw. Null, wenn<br />
die Komponente ke<strong>in</strong>en aktuellen Grafikbezug hat. Bei je<strong>de</strong>r Zeichenoperation muß<br />
<strong>de</strong>r grafische Kontext angegeben wer<strong>de</strong>n, <strong>de</strong>nn dieses Objekt verwaltet:<br />
- die Komponente, auf <strong>de</strong>r zu zeichnen ist.<br />
- Koord<strong>in</strong>aten <strong>de</strong>s Bildbereichs und <strong>de</strong>s Clipp<strong>in</strong>g-Bereichs.<br />
- <strong>de</strong>r aktuelle Clip-Bereich und Font, die aktuelle Farbe<br />
- die Pixeloperation (XOR o<strong>de</strong>r Pa<strong>in</strong>t)<br />
- Composite (Überschreibmodus/Alphakanal)<br />
Die meisten Zeichenvorgänge wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r pa<strong>in</strong>t()-Metho<strong>de</strong> durchgeführt. <strong>Java</strong>-<br />
Applets zeichnen sich selbst neu nach Überschreiben <strong>de</strong>r pa<strong>in</strong>t()-Metho<strong>de</strong>. Es gibt<br />
drei verschie<strong>de</strong>ne Metho<strong>de</strong>n 234 zum Neuzeichnen:<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 />
E<strong>in</strong> Graphics-Objekt erzeugt nicht <strong>de</strong>r Entwickler, son<strong>de</strong>rn er bekommt <strong>de</strong>n Kontext<br />
gestellt, auf <strong>de</strong>m er zeichnen möchte. Die Klasse Graphics hat ke<strong>in</strong>en öffentlichen<br />
Konstruktor.<br />
234 vgl. 3.2.2<br />
259
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
.........<br />
Graphics<br />
{ abstract }<br />
><br />
protected Graphics()<br />
><br />
public abstract Graphics create()<br />
public Graphics create(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void translate(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public abstract Color getColor()<br />
public abstract void setColor(Color farbe)<br />
public abstract void setXORMo<strong>de</strong>(Color farbe)<br />
public abstract Font getFont()<br />
public abstract void setFont(Font f)<br />
public FontMetrics getFontMetrics()<br />
public abstract Rectangle getClipBounds()<br />
public abstract void clipRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void setClip(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract Shape getClip()<br />
public abstract 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)<br />
public abstract fillRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public void drawRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void clearRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void drawRoundRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height, <strong>in</strong>t arcWidth, <strong>in</strong>t arcHeight)<br />
public abstract fillRoundRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height, <strong>in</strong>t arcWidth, <strong>in</strong>t arcHeight)<br />
public abstract void drawOval(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void fillOval(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void drawArc(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height, <strong>in</strong>t startAngle, <strong>in</strong>t arcAngle)<br />
public abstract void drawStr<strong>in</strong>g(Str<strong>in</strong>g str, <strong>in</strong>t x, <strong>in</strong>t y)<br />
public abstract boolean drawImage(Image bild, <strong>in</strong>t x, <strong>in</strong>t y, ImageObserver observer)<br />
Abb.: Die Klasse Graphics<br />
4.1 Allgeme<strong>in</strong>e Zeichenvorgänge<br />
4.1.1 Punkte, L<strong>in</strong>ien, Kreise, Bögen, Polygone<br />
Das Koord<strong>in</strong>atensystem. Der Ausgangspunkt (0,0) <strong>de</strong>s <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 <strong>de</strong>r Koord<strong>in</strong>aten erfolgen <strong>in</strong> Pixel. Alle<br />
Pixelwerte s<strong>in</strong>d Ganzzahlen.<br />
Punkte. E<strong>in</strong> Punkt ist durch zwei o<strong>de</strong>r mehr Koord<strong>in</strong>aten gekennzeichnet. In <strong>Java</strong> gibt<br />
es ke<strong>in</strong>e Funktion, mit <strong>de</strong>r Punkte gezeichnet wer<strong>de</strong>n. Diese können nur durch<br />
L<strong>in</strong>iebefehle erzeugt wer<strong>de</strong>n.<br />
Zeichnen e<strong>in</strong>er L<strong>in</strong>ie. Es geschieht mit <strong>de</strong>r Metho<strong>de</strong>: 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 <strong>de</strong>n<br />
Anfangspunkt, (x2,y2) bestimmt <strong>de</strong>n Endpunkt <strong>de</strong>r L<strong>in</strong>ie.<br />
260
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp.: E<strong>in</strong> Applet mit zufällig verteilten L<strong>in</strong>ien 235<br />
import java.awt.*;<br />
// Top Level Deklaration <strong>de</strong>s 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 Metho<strong>de</strong>n<br />
// Metho<strong>de</strong>n, die ueberschrieben wer<strong>de</strong>n<br />
public void <strong>in</strong>it()<br />
{<br />
setBackground(Color.lightGray);<br />
}<br />
public void start()<br />
{<br />
if (fa<strong>de</strong>n == null)<br />
{<br />
fa<strong>de</strong>n = new Thread(this);<br />
fa<strong>de</strong>n.start();<br />
}<br />
}<br />
public void stop()<br />
{<br />
if (fa<strong>de</strong>n != null)<br />
{<br />
fa<strong>de</strong>n.stop();<br />
fa<strong>de</strong>n = null;<br />
}<br />
}<br />
public void run()<br />
{<br />
// Ausfuehrung <strong>de</strong>s 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 <strong>de</strong>r repa<strong>in</strong>t()-Metho<strong>de</strong><br />
try {fa<strong>de</strong>n.sleep(1000); } // Pause von 1000 Millisekun<strong>de</strong>n<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 Metho<strong>de</strong> 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 />
235 vgl. pr42005<br />
261
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Zeichnen e<strong>in</strong>es Rechtecks. Dafür gibt es die Metho<strong>de</strong>: public 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 <strong>de</strong>s<br />
Rechtecks fest.<br />
Zeichnen e<strong>in</strong>es gefüllten Rechtecks. Es wird ermöglicht durch die Metho<strong>de</strong>: 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 <strong>de</strong>r das Rechteck gefüllt wer<strong>de</strong>n soll, kann mit <strong>de</strong>r folgen<strong>de</strong>n Metho<strong>de</strong><br />
gesetzt wer<strong>de</strong>n: public abstract void setColor(Color c).<br />
Bsp.: E<strong>in</strong> Applet mit zufällig verteilten Rechtecken 236<br />
// zeichne Rechtecke<br />
import java.applet.*;<br />
import java.awt.*;<br />
public class RechteckeAppl3 extends Applet<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 />
// Metho<strong>de</strong>n<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 />
236 vgl. pr41103<br />
262
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Löschen e<strong>in</strong>es Rechtecks. Das übernimmt die Metho<strong>de</strong> 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 Metho<strong>de</strong> 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 <strong>de</strong>r Metho<strong>de</strong> 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 abgerun<strong>de</strong>ter Rechtecke. Sie können gezeichnet wer<strong>de</strong>n 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 <strong>de</strong>n W<strong>in</strong>kel<br />
<strong>de</strong>r Abrundung auf <strong>de</strong>r horizontalen, „arcHeight“ <strong>de</strong>n W<strong>in</strong>kel auf <strong>de</strong>r vertikalen<br />
Ebene. Je größer die W<strong>in</strong>kel s<strong>in</strong>d, <strong>de</strong>sto stärker gerun<strong>de</strong>t ersche<strong>in</strong>t das Rechteck.<br />
Zeichnen abgerun<strong>de</strong>ter, gefüllter Rechtecke. Dafür existiert die Metho<strong>de</strong> 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 Metho<strong>de</strong> public abstract void<br />
drawPolygon(<strong>in</strong>t[] xPunkte, <strong>in</strong>t[] yPunkte, <strong>in</strong>t nPunkte)<br />
herangezogen wer<strong>de</strong>n. Es gibt zwei Möglichkeiten beim Zeichnen von Polygonen:<br />
- Weitergabe <strong>de</strong>r bei<strong>de</strong>n Datenbereiche (Arrays) mit <strong>de</strong>n x- und y-Koord<strong>in</strong>aten <strong>de</strong>r Punkte, z.B. 237 :<br />
import java.awt.*;<br />
public class ZeichnePolyAppl1 extends java.applet.Applet<br />
{<br />
// Instanzvariable<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n x-Koord<strong>in</strong>aten<br />
<strong>in</strong>t xKoord[] = {20,50,70,40,20,20};<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n y-Koord<strong>in</strong>aten<br />
<strong>in</strong>t yKoord[] = {30,10,20,70,50,30};<br />
// Metho<strong>de</strong>n<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 <strong>de</strong>r Polygon-Klasse, z.B. 238 :<br />
import java.awt.*;<br />
public class ZeichnePolyAppl2 extends java.applet.Applet<br />
{<br />
// Instanzvariable<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n x-Koord<strong>in</strong>aten<br />
<strong>in</strong>t xKoord[] = {20,50,70,40,20,20};<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n 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 />
// Metho<strong>de</strong>n<br />
public void <strong>in</strong>it() { setBackground(Color.yellow); }<br />
public void pa<strong>in</strong>t(Graphics g)<br />
237 pr41105<br />
238 pr41105<br />
263
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 Metho<strong>de</strong> public abstract<br />
void fillPolygon(<strong>in</strong>t[] xPunkte, <strong>in</strong>t[] yPunkte, <strong>in</strong>t nPunkte).<br />
Bsp. 239 :<br />
import java.awt.*;<br />
public class ZeichnePolyAppl3 extends java.applet.Applet<br />
{<br />
// Instanzvariable<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n x-Koord<strong>in</strong>aten<br />
<strong>in</strong>t xKoord[] = {20,50,70,40,20};<br />
// Def<strong>in</strong>ition <strong>de</strong>s Felds mit <strong>de</strong>n y-Koord<strong>in</strong>aten<br />
<strong>in</strong>t yKoord[] = {30,10,20,70,50};<br />
// Metho<strong>de</strong>n<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 />
Zeichnen e<strong>in</strong>es L<strong>in</strong>ienzuges mit <strong>de</strong>r Metho<strong>de</strong> abstract void drawPolygon(<strong>in</strong>t<br />
xPunkte[], <strong>in</strong>t yPunkte[], <strong>in</strong>t nPunkte) durch die gegebenen<br />
Koord<strong>in</strong>aten <strong>in</strong> <strong>de</strong>r Vor<strong>de</strong>rgrundfarbe. Die Figur wird dabei nicht geschlossen, wenn<br />
nicht Strat- und Endkoord<strong>in</strong>aten gleich s<strong>in</strong>d. Mit nPunkte wer<strong>de</strong>n die Anzahl <strong>de</strong>r<br />
gezeichneten L<strong>in</strong>ien kontrolliert.<br />
Die Klasse Polygon. Sie ist e<strong>in</strong>e Erweiterung <strong>de</strong>s Interface Shape . E<strong>in</strong> Polygon-<br />
Objekt verwaltet eigenständig se<strong>in</strong>e Koord<strong>in</strong>aten, von außen können Elemente<br />
aufgenommen wer<strong>de</strong>n.<br />
239 pr41105<br />
264
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
java.awt.Polygon<br />
protected Rectangle bounds<br />
public <strong>in</strong>t npo<strong>in</strong>ts<br />
public <strong>in</strong>t[] xpo<strong>in</strong>ts<br />
public <strong>in</strong>t[] ypo<strong>in</strong>ts<br />
><br />
public Polygon()<br />
public Polygon(<strong>in</strong>t[] xpo<strong>in</strong>ts, <strong>in</strong>t[] ypo<strong>in</strong>ts, <strong>in</strong>t npo<strong>in</strong>ts)<br />
><br />
public void addPo<strong>in</strong>t(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public boolean conta<strong>in</strong>s(double x, double y)<br />
public boolean conta<strong>in</strong>s(double x, double y, double w, double h)<br />
public boolean conta<strong>in</strong>s(<strong>in</strong>t x, <strong>in</strong>t y)<br />
...<br />
public Rectangle getBounds();<br />
...<br />
public boolean <strong>in</strong>si<strong>de</strong>(<strong>in</strong>t x, <strong>in</strong>t y)<br />
...<br />
public void translate(<strong>in</strong>t <strong>de</strong>ltaX, <strong>in</strong>t <strong>de</strong>ltaY)<br />
Abb.: Die Klasse Polygon<br />
Das Zeichnen von Kreisen und Ellipsen. Es erfolgt über die Metho<strong>de</strong> 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 <strong>de</strong>r oberen l<strong>in</strong>ken Ecke <strong>de</strong>s umschreiben<strong>de</strong>n Rechtecks<br />
an.<br />
Das Zeichnen von gefüllten Kreisen und Ellipsen. Es erfolgt über die Metho<strong>de</strong><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 folgen<strong>de</strong> Metho<strong>de</strong> 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 />
<strong>de</strong>n Anfangsw<strong>in</strong>kel von e<strong>in</strong>er (gedachten) horizontalen Mittell<strong>in</strong>ie aus gesehen, ab<br />
<strong>de</strong>m <strong>de</strong>r Bogen gezeichnet wer<strong>de</strong>n soll. „bogenW<strong>in</strong>kel“ legt fest, wie weit <strong>de</strong>r<br />
Bogen ab <strong>de</strong>m Startpunkt gezeichnet wird und <strong>in</strong> welche Richtung er geht. Die<br />
positive Richtung <strong>in</strong> <strong>Java</strong> ist entgegen <strong>de</strong>m Uhrzeigers<strong>in</strong>n.<br />
Das Zeichnen von gefüllten Bögen. Es erfolgt über die Metho<strong>de</strong> 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 />
Das Zeichnen von Zeichenketten erfolgt mit Hilfe <strong>de</strong>r Metho<strong>de</strong>n<br />
public abstract void drawStr<strong>in</strong>g(Str<strong>in</strong>g str, <strong>in</strong>t x, <strong>in</strong>t y)<br />
public void drawChars(char[] daten, <strong>in</strong>t offset, <strong>in</strong>t length, <strong>in</strong>t x, <strong>in</strong>t y)<br />
public void drawBytes(byte[] daten, <strong>in</strong>t offset, <strong>in</strong>t length, <strong>in</strong>t x, <strong>in</strong>t y)<br />
265
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.1.2 Farbangaben<br />
<strong>Java</strong> setzt Farben aus sog. Primärfarben (Rot, Grün, Blau) <strong>de</strong>s Lichts zusammen<br />
(RGB-Mo<strong>de</strong>ll). E<strong>in</strong>e Farbe im RGB-Mo<strong>de</strong>ll wird durch die Angabe, wieviel rotes,<br />
grünes und blaues Licht <strong>in</strong> <strong>de</strong>r Farbe enthalten s<strong>in</strong>d, bestimmt. Dies kann entwe<strong>de</strong>r<br />
mit e<strong>in</strong>er Ganzzahl zwischen 0 und 255 o<strong>de</strong>r 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ß (white) 255 255 255<br />
Hellgrau (lightGray) 192 192 192<br />
Grau (gray) 128 128 128<br />
Dunkelgrau (darkGray) 64 64 64<br />
Schwarz (black) 0 0 0<br />
Rot (rot) 255 0 0<br />
Grün (green) 0 255 0<br />
Blau (blue) 0 0 255<br />
Gelb (yellow) 255 255 0<br />
Orange (orange) 255 200 0<br />
P<strong>in</strong>k (p<strong>in</strong>k) 255 175 175<br />
Magenta (magenta) 255 0 255<br />
Cyan (cyan) 0 255 255<br />
Abb.: Gebräuchliche Farbwerte RGB-Werte)<br />
Neben <strong>de</strong>m RGB-Farbmo<strong>de</strong>ll unterstützt <strong>Java</strong> auch das HSB-Farbmo<strong>de</strong>ll. Dieses<br />
stellt e<strong>in</strong>e Farbe durch die drei Parameter Farbton, Intensität und Helligkeit dar. Die<br />
Farbmo<strong>de</strong>lle können die gleichen Farben beschreiben und umgerechnet wer<strong>de</strong>n.<br />
Die Color-Klasse. Auf drei Arten kann e<strong>in</strong>e Farbe erzeugt wer<strong>de</strong>n:<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 />
erzeugt e<strong>in</strong> Color-Objekt aus <strong>de</strong>m rgb-Wert, <strong>de</strong>r die Farben rot, grün, blau kodiert. Der Rot-Anteil<br />
bef<strong>in</strong><strong>de</strong>t sich <strong>in</strong> <strong>de</strong>n Bits 16 bis 23, <strong>de</strong>r Grünanteil <strong>in</strong> 8 bis 15 und auch <strong>de</strong>r Blauanteil <strong>in</strong> 0 bis 7. Je<strong>de</strong><br />
Farbe ist durch e<strong>in</strong> Byte repräsentiert.<br />
public Color(float red, float green, float blue)<br />
E<strong>in</strong>e gängige Farbe kann schneller über die Standardfarbobjekte <strong>de</strong>r <strong>in</strong> <strong>de</strong>r Color-Klasse <strong>de</strong>f<strong>in</strong>ierten<br />
verschie<strong>de</strong>nen Klassenvariablen gewonnen wer<strong>de</strong>n, 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 <strong>de</strong>r 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 />
266
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public <strong>in</strong>t getBlue();<br />
Setzen von Farben. Es wird möglich durch die Metho<strong>de</strong>: public abstract void<br />
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ß o<strong>de</strong>r dunkelgrau (je nach Conta<strong>in</strong>er). Individuell kann die H<strong>in</strong>tergrundfarbe<br />
e<strong>in</strong>es Applets gesetzt wer<strong>de</strong>n durch: public void setBackground(Color c).<br />
Parameter ist das gewünschte Farbobjekt.<br />
Setzen von Vor<strong>de</strong>rgrundfarben. Falls die Farbe für alle Zeichenobjekte <strong>in</strong>nerhalb<br />
e<strong>in</strong>es Applets pauschal festgesetzt wer<strong>de</strong>n soll, dann kann die Metho<strong>de</strong> public<br />
void setForeground(Color c) verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
4.1.3 Textausgabe über <strong>de</strong>n Zeichen-Modus<br />
Die Graphics-Klasse enthält auch Metho<strong>de</strong>n zum Zeichnen von Textzeichen und<br />
Zeichenketten (z.B. die drawStr<strong>in</strong>g() Metho<strong>de</strong>). Zusätzlich spielen die Font-<br />
Klasse 240 und die Fontmetrics-Klasse 241 beim Textzeichnen e<strong>in</strong>e Rolle.<br />
Font<br />
FontMetrics<br />
{ abstract }<br />
public static f<strong>in</strong>al <strong>in</strong>t PLAIN<br />
public static f<strong>in</strong>al <strong>in</strong>t BOLD<br />
public Font getFont()<br />
public static f<strong>in</strong>al <strong>in</strong>t ITALIC<br />
public <strong>in</strong>t getLead<strong>in</strong>g()<br />
protected Str<strong>in</strong>g name<br />
public <strong>in</strong>t getAscent()<br />
protected <strong>in</strong>t style<br />
public <strong>in</strong>t getDescent()<br />
protected <strong>in</strong>t size<br />
public <strong>in</strong>t getHeight()<br />
public <strong>in</strong>t getMaxAscent()<br />
> public <strong>in</strong>t getMaxDescent()<br />
public Font(Str<strong>in</strong>g name, <strong>in</strong>t style, <strong>in</strong>t size)<br />
public <strong>in</strong>t getMaxAdvance()<br />
> public <strong>in</strong>t charWidth(<strong>in</strong>t zeichen)<br />
public Str<strong>in</strong>g getName()<br />
public <strong>in</strong>t charWidth(char zeichen)<br />
public <strong>in</strong>t getStyle()<br />
public <strong>in</strong>t str<strong>in</strong>gWidth(Str<strong>in</strong>g str)<br />
public <strong>in</strong>t getSize()<br />
public <strong>in</strong>t[] getWidths()<br />
public boolean isPla<strong>in</strong>()<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
public boolean isBold()<br />
public boolean isItalic()<br />
public static Font getFont(Str<strong>in</strong>g nm)<br />
public static Font getFont(Str<strong>in</strong>g nm, Font font)<br />
public static Font <strong>de</strong>co<strong>de</strong>(Str<strong>in</strong>g str)<br />
public <strong>in</strong>t hashCo<strong>de</strong>()<br />
public boolean equals(Object obj)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
Abb.: Die Klassen Font und FontMetrics<br />
240 Die Font-Klasse stellt bestimmte Fonts dar (Name, Stil, Fontgröße)<br />
241 Die Fontmetrics-Klasse enthält Informationen über <strong>de</strong>n Font wie tatsächliche Höhe und Breite e<strong>in</strong>es<br />
bestimmten Zeichens.<br />
267
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klasse Font<br />
Texte wer<strong>de</strong>n <strong>in</strong> e<strong>in</strong>em standarmäßig bereitgestellten Font ausgegeben. Soll e<strong>in</strong><br />
an<strong>de</strong>rer Font zur Textausgabe verwen<strong>de</strong>t wer<strong>de</strong>n, so muß e<strong>in</strong> Objekt <strong>de</strong>r Klasse<br />
Font erzeugt und <strong>de</strong>m verwen<strong>de</strong>ten Graphics-Objekt zugewiesen wer<strong>de</strong>n.<br />
Das Erzeugen neuer Font-Objekte wird über die Parameter name, style und size<br />
<strong>de</strong>s Konstruktors <strong>de</strong>r 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 <strong>de</strong>s gewünschten Font. In allen <strong>Java</strong>-Systemen sollen „SansSerif“, „Serif“, und<br />
„Monospaced“ unterstützt wer<strong>de</strong>n. Unter W<strong>in</strong>dows wer<strong>de</strong>n die Standardnamen auf die „True-Type-<br />
Fonts“ „Arial“, „TimesNewRoman“ und „CourierNew“ abgebil<strong>de</strong>t.<br />
style: Auswahl <strong>de</strong>r Ausprägung (fett, kursiv)<br />
Name Wert Be<strong>de</strong>utung<br />
Font.PLAIN 0 Standard-Font<br />
Font.BOLD 1 fett 242<br />
Font.ITALIC 2 kursiv<br />
size: Angabe <strong>de</strong>r Größe <strong>de</strong>r gewünschten Schriftart <strong>in</strong> Pixel (Punktgrößen)<br />
public void setFont(Font font) wird zum E<strong>in</strong>tragen <strong>de</strong>s Font-Objekts <strong>in</strong> <strong>de</strong>n<br />
Grafikkontext verwen<strong>de</strong>t.<br />
public Font getFont() ermittelt <strong>de</strong>n aktuellen Font.<br />
Die Ermittlung, welche Zeichensätze auf e<strong>in</strong>em System <strong>in</strong>stalliert s<strong>in</strong>d, kann über<br />
Toolkit.getDefaultToolkit().getFontList() erfolgen. Str<strong>in</strong>g[]<br />
getFontList() gibt die Namen <strong>de</strong>r verfügbaren Zeichensätze zurück, z.B.: 243<br />
import java.awt.*;<br />
class ListFont<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
// herkoemmliche Metho<strong>de</strong> zur Ermittlung <strong>de</strong>r<br />
// Schriftarten <strong>in</strong> e<strong>in</strong>em <strong>Java</strong>-System<br />
Str<strong>in</strong>g fonts[] = Toolkit.getDefaultToolkit().getFontList();<br />
for (<strong>in</strong>t i = 0; i < fonts.length; i++)<br />
System.out.pr<strong>in</strong>tln(fonts[i]);<br />
}<br />
}<br />
Die Klasse FontMetrics<br />
Diese Klasse bietet Metho<strong>de</strong>n zur Bestimmung <strong>de</strong>r Größe <strong>de</strong>r angezeigten Zeichen<br />
<strong>in</strong> <strong>de</strong>r 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 <strong>de</strong>r <strong>de</strong>r Text steht.<br />
Descent (Unterstand): Damit ist geme<strong>in</strong>t, wie weit e<strong>in</strong> Buchstabe unter 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 />
242 BOLD und ITALIC können auch geme<strong>in</strong>sam verwen<strong>de</strong>t wer<strong>de</strong>n, <strong>in</strong><strong>de</strong>m bei<strong>de</strong> Konstanten mit „+“<br />
zusammengefügt wer<strong>de</strong>n.<br />
243 pr41300<br />
268
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Lead<strong>in</strong>g (Zeileabstand): Damit ist <strong>de</strong>r Raum zwischen <strong>de</strong>m Descent e<strong>in</strong>es Buchstabens und <strong>de</strong>m<br />
Ascent <strong>de</strong>r nächsten Zeile geme<strong>in</strong>t.<br />
Metho<strong>de</strong>n.<br />
Metho<strong>de</strong> 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 <strong>de</strong>r Grundl<strong>in</strong>ie und <strong>de</strong>r oberen Grenze <strong>de</strong>r Buchstaben<br />
aus<br />
getDescent() Gibt die Entfernung zwischen <strong>de</strong>r Grundl<strong>in</strong>ie und <strong>de</strong>r unteren Grenze <strong>de</strong>r<br />
Buchstaben aus (z.B. p und g)<br />
getLead<strong>in</strong>g() Gibt <strong>de</strong>n Abstand zwischen <strong>de</strong>m Überstand e<strong>in</strong>er Zeile und <strong>de</strong>m Überstand <strong>de</strong>r<br />
nächsten Zeile aus<br />
getHeight() gibt die Gesamthöhe <strong>de</strong>r Schrift aus, d.h. die Summe von Überstand, Unterstand<br />
und Zeilenabstand<br />
Abb.: Fontmetrics-Metho<strong>de</strong>n<br />
Bsp. 244 :<br />
import java.applet.*;<br />
import java.awt.*;<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 />
// Metho<strong>de</strong>n<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 unterschei<strong>de</strong>n,) 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 />
244 pr41301<br />
269
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
4.1.4 Grössenangaben<br />
Für die meisten Größenangaben wer<strong>de</strong>n <strong>in</strong>t-Werte benutzt. Darüber h<strong>in</strong>aus gibt es<br />
auch alterantive Formulierungsmöglichkeiten mit <strong>de</strong>n Klassen Dimension, Po<strong>in</strong>t<br />
und Rectangle.<br />
><br />
Shape<br />
Po<strong>in</strong>t<br />
public <strong>in</strong>t x<br />
public <strong>in</strong>t y<br />
Rectangle<br />
><br />
public <strong>in</strong>t y<br />
public Po<strong>in</strong>t()<br />
public <strong>in</strong>t y public Po<strong>in</strong>t(Po<strong>in</strong>t p)<br />
public <strong>in</strong>t width public Po<strong>in</strong>t(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public <strong>in</strong>t height ><br />
public Po<strong>in</strong>t getLocation()<br />
> public void setLocation(Po<strong>in</strong>t p)<br />
public Rectangle(Rectangle r) public void setLocation(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public Rectangle(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height) public void move(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public Rectangle(<strong>in</strong>t width, <strong>in</strong>t height) public void translate(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public Rectangle(Po<strong>in</strong>t p, Dimension d)<br />
public <strong>in</strong>t hashCo<strong>de</strong>()<br />
public Rectangle(Po<strong>in</strong>t p)<br />
public boolean equals(Object obj)<br />
public Rectangle(Dimension d)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
><br />
public Rectangle getBounds()<br />
public void setBounds(<strong>in</strong>t x,<strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
Dimension<br />
public void setBounds(Rectangle r)<br />
public Po<strong>in</strong>t getLocation()<br />
public <strong>in</strong>t width<br />
public void setLocation(Po<strong>in</strong>t p)<br />
public <strong>in</strong>t height<br />
public void setLocation((<strong>in</strong>t x, <strong>in</strong>t y)<br />
public void translate(<strong>in</strong>t x, <strong>in</strong>t y) ><br />
public Dimension getSize()<br />
public Dimension()<br />
public void setSize(<strong>in</strong>t width, <strong>in</strong>t height) public Dimension(Dimension d)<br />
public boolean conta<strong>in</strong>s(Po<strong>in</strong>t p)<br />
public Dimension(<strong>in</strong>t width, <strong>in</strong>t height)<br />
public boolean conta<strong>in</strong>s(<strong>in</strong>t x, <strong>in</strong>t y) ><br />
public boolean isEmpty()<br />
public Dimension getSize()<br />
public <strong>in</strong>t hashCo<strong>de</strong>() public void setSize(Dimension d)<br />
public boolean equals(Object obj)<br />
public boolean equals(Object obj)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
Abb.: Die Klassen Dimension und Rectangle<br />
Das Interface Shape wird von <strong>de</strong>n bisher bekannten geometrischen Formen (z.B.<br />
Rectangle, Polygon) implementiert und außer<strong>de</strong>m von <strong>de</strong>n neuen geometrischen<br />
Formen im Paket java.awt.geom.<br />
270
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.1.5 Clipp<strong>in</strong>g-Operationen<br />
Je<strong>de</strong>r Grafikkontext hat e<strong>in</strong>e zugeordnete Clipp<strong>in</strong>g-Region, die dazu dient, die<br />
Ausgabe auf e<strong>in</strong>en bestimmten Bereich e<strong>in</strong>zugrenzen. Clipp<strong>in</strong>g ist e<strong>in</strong>e Eigenschaft<br />
<strong>de</strong>s aktuellen „Graphic“ Objekts. Mit <strong>de</strong>r Metho<strong>de</strong> clipRect(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t<br />
breite, <strong>in</strong>t hoehe) läßt sich <strong>de</strong>r Bereich e<strong>in</strong>schränken, dann erfolgen alle<br />
Operationen <strong>in</strong> diesem Bereich. Mit<br />
public abstract void setClip(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t width, <strong>in</strong>t height)<br />
public abstract void setClip(Shape clip)<br />
kann die Clipp<strong>in</strong>g-Region auf e<strong>in</strong>en beliebigen Bereich <strong>in</strong>nerhalb <strong>de</strong>s aktuelle<br />
Fensters ausge<strong>de</strong>hnt wer<strong>de</strong>n. Die zweite Version von setClip() erlaubt die<br />
Übergabe e<strong>in</strong>es Objekts, die das Shape-Interface implementiert.<br />
4.2 Bildverarbeitung<br />
Bil<strong>de</strong>r s<strong>in</strong>d neben Text das wichtigste visuelle Gestaltungsmerkmal. In <strong>Java</strong> können<br />
Grafiken an verschie<strong>de</strong>nen Stellen e<strong>in</strong>gebun<strong>de</strong>n wer<strong>de</strong>n, z.B. als Grafiken <strong>in</strong><br />
Zeichenflächen (Canvas) o<strong>de</strong>r als Icons <strong>in</strong> Buttons. Über <strong>Java</strong> können GIF-Bil<strong>de</strong>r 245<br />
und JPEG-Bil<strong>de</strong>r gela<strong>de</strong>n wer<strong>de</strong>n.<br />
Je<strong>de</strong> Grafik wird als Exemplar <strong>de</strong>r Klasse Image erzeugt. Image dient zur<br />
Implementierung von:<br />
- ImageProducer für die Erzeugung von Bil<strong>de</strong>rn auf <strong>de</strong>r Grundlage von Bildpunkten.<br />
- ImageConsumer für die Darstellung von Bil<strong>de</strong>rn als Interpretation <strong>de</strong>r gespeicherten Bildpunkte.<br />
- ImageFilter für die Filterung <strong>de</strong>s Bil<strong>de</strong>s <strong>in</strong>sbeson<strong>de</strong>re h<strong>in</strong>sichtlich vorgebbarer Farbmo<strong>de</strong>lle und<br />
Bil<strong>de</strong>igenschaften (mit <strong>de</strong>r speziellen Subklasse RGBImageFilter).<br />
- ImageObserver bspw. für die Beobachtung, ob e<strong>in</strong> Bild vollständig gela<strong>de</strong>n ist u.ä.m. Zur<br />
vollständigen Kontrolle <strong>de</strong>s La<strong>de</strong>ns e<strong>in</strong>es Bilds stellt java.awt. die Klasse MediaTracker bereit.<br />
Bil<strong>de</strong>r e<strong>in</strong>er Applikation wer<strong>de</strong>n über die Klasse Toolkit e<strong>in</strong>gebun<strong>de</strong>n.<br />
Bsp.: Anfor<strong>de</strong>rn e<strong>in</strong>es Bilds <strong>in</strong> e<strong>in</strong>er Applikation.<br />
Image pic = Toolkit.getDefaultToolkit().getImage("");<br />
Zur Anzeige e<strong>in</strong>es Bilds <strong>in</strong> Orig<strong>in</strong>algröße wird die Metho<strong>de</strong> drawImage() mit<br />
folgen<strong>de</strong>n Argumenten aufgerufen:<br />
- Das Image-Objekt, das angezeigt wer<strong>de</strong>n soll.<br />
- die x-Koord<strong>in</strong>ate<br />
- die y-Koord<strong>in</strong>ate<br />
- Das Schlüsselwort this.<br />
245 Das GIF-Format (Graphics Interchange Format) ist e<strong>in</strong> komprimieren<strong>de</strong>s Verfahren, das 1987 von<br />
CompuServe-Betreibern zum Austausch von Bil<strong>de</strong>rn entwickelt wur<strong>de</strong>. GIF-Bil<strong>de</strong>r können bis zu 1600 mal<br />
1600 Punkte umfassen. Die Komprimierung (nach <strong>de</strong>m LZW-Verfahren) ist verlustfrei. Je<strong>de</strong>s GIF-Bild kann aus<br />
maximal 256 Farben bestehen (bei e<strong>in</strong>er Palette von 16,7 Millionen Farben).<br />
271
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.2.1 Klassen zur Bildverarbeitung<br />
Toolkit<br />
{ abstract }<br />
public abstract Image getImage(Str<strong>in</strong>g dateiName)<br />
public abstract Image getImage(Url url)<br />
public abstract Image createImage(ImageProducer erzeuger)<br />
public abstract boolean prepareImage(Image bild, <strong>in</strong>t breite, <strong>in</strong>t hoehe,ImageObserver observer)<br />
public abstract <strong>in</strong>t checkImage(Image bild, <strong>in</strong>t breite, <strong>in</strong>t hoehe, ImageObserver observer)<br />
....<br />
Image<br />
{ abstract }<br />
public abstract <strong>in</strong>t getHeight(ImageObserver obs)<br />
public abstract <strong>in</strong>t getWidth(ImageObserver obs)<br />
public abstract ImageProducer getSource()<br />
public abstract Graphics getGraphics()<br />
public abstract void flush()<br />
public abstract Object getProperty(Str<strong>in</strong>g attribut, ImageObserver obs)<br />
public Image getScaledInstance(<strong>in</strong>t breite, <strong>in</strong>t hoehe, <strong>in</strong>t modus)<br />
public static f<strong>in</strong>al <strong>in</strong>t ALLBITS<br />
public static f<strong>in</strong>al <strong>in</strong>t SOMEBITS<br />
public static f<strong>in</strong>al <strong>in</strong>t ABORT<br />
public static f<strong>in</strong>al <strong>in</strong>t ERROR<br />
public static f<strong>in</strong>al <strong>in</strong>t PROPERTIES<br />
><br />
ImageObserver<br />
public abstract boolean imageUpdate(Image bild, <strong>in</strong>t <strong>in</strong>foFlags, <strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
public static f<strong>in</strong>al <strong>in</strong>t ABORTED<br />
public static f<strong>in</strong>al <strong>in</strong>t COMPLETE<br />
public static f<strong>in</strong>al <strong>in</strong>t ERRORED<br />
public static f<strong>in</strong>al <strong>in</strong>t LOADING<br />
MediaTracker<br />
><br />
public MediaTracker(Component comp)<br />
><br />
public void addImage(Image bild, <strong>in</strong>t id)<br />
public void addImage(Image bild, <strong>in</strong>t id, <strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
public boolean checkAll()<br />
public void waitForAll() throws InterruptedException<br />
public boolean checkID(<strong>in</strong>t id)<br />
public void waitForID(<strong>in</strong>t id) throws InterruptedException<br />
...<br />
Abb.: Image-Klassen<br />
272
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klassen zur Bildverarbeitung bef<strong>in</strong><strong>de</strong>n sich im Package java.awt.image. Mit<br />
Hilfe <strong>de</strong>r Klasse java.awt.Toolkit kann e<strong>in</strong> Bild aus e<strong>in</strong>er angegebenen Quelle<br />
mit getImage() gela<strong>de</strong>n wer<strong>de</strong>n. Dabei wird e<strong>in</strong> Objekt vom Typ<br />
java.awt.Image zurückgegeben. Der La<strong>de</strong>zustand e<strong>in</strong>es Objekts (z.B e<strong>in</strong>es Bilds)<br />
kann überwacht wer<strong>de</strong>n, wenn die zum Objekt zugehörige Klasse das Interface<br />
java.awt.image.ImageObserver implementiert. Das tun alle AWT- und Sw<strong>in</strong>g-<br />
Kontrollelemente. Zur vere<strong>in</strong>fachten Benutzung beim La<strong>de</strong>n mehrerer Bil<strong>de</strong>r gibt es<br />
die Klasse java.awt.MediaTracker. Die weiteren Klassen im Paket<br />
java.util.image ermöglichen Skalierung, Rotation, Filtern und an<strong>de</strong>re<br />
Verän<strong>de</strong>rungen <strong>de</strong>r Bil<strong>de</strong>r. Als Bildformate wer<strong>de</strong>n GIF und JPG unterstützt.<br />
In <strong>Java</strong> 2 kamen Klassen zum pixelorientierten Erzeugen und Bearbeiten von Bil<strong>de</strong>rn<br />
im Paket java.awt.image und <strong>de</strong>m neuen java.awt.image.ren<strong>de</strong>rable<br />
h<strong>in</strong>zu.<br />
Bsp.: E<strong>in</strong> Bildbetrachter 246<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class ImageViewer extends Frame implements ActionListener<br />
{<br />
private Image image;<br />
private Frame frame;<br />
public ImageViewer()<br />
{<br />
setTitle("Bildbetrachter");<br />
// konstruiere die Menuezeile<br />
MenuBar mbar = new MenuBar();<br />
Menu menue = new Menu("Datei");<br />
MenuItem menueItem = new MenuItem("Oeffnen", new MenuShortcut((<strong>in</strong>t)<br />
'O'));<br />
menueItem.addActionListener(this);<br />
menue.add(menueItem);<br />
mbar.add(menue);<br />
setMenuBar(mbar);<br />
// Schliessen <strong>de</strong>s Fenster mit X<br />
frame = this;<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 />
{ System.exit(0); }<br />
});<br />
setSize(600,400);<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
if (image != null)<br />
{<br />
g.drawImage(image,0,0,this);<br />
setSize(image.getWidth(this),image.getHeight(this));<br />
}<br />
}<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
FileDialog d = new FileDialog(frame,"Oeffne Grafikdatei",<br />
FileDialog.LOAD);<br />
d.setFile("*.jpg;*gif");<br />
d.show();<br />
Str<strong>in</strong>g file = d.getDirectory() + d.getFile();<br />
246 pr42300<br />
273
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
image = Toolkit.getDefaultToolkit().getImage(file);<br />
if (image != null) repa<strong>in</strong>t();<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
new ImageViewer().show();<br />
}<br />
}<br />
E<strong>in</strong> Bild <strong>in</strong> e<strong>in</strong>er an<strong>de</strong>ren Größe kann durch e<strong>in</strong>e erweiterte Version von<br />
drawImage() angezeigt wer<strong>de</strong>n, falls folgen<strong>de</strong> Parameter angegeben wer<strong>de</strong>n:<br />
- Das Imgae-Objekt, das angezeigt wer<strong>de</strong>n soll<br />
- die x-Koord<strong>in</strong>ate<br />
- die y-Koord<strong>in</strong>ate<br />
- die Breite<br />
- die Höhe<br />
- das Schlüsselwort this<br />
Zwei Metho<strong>de</strong>n <strong>de</strong>r Image-Klasse s<strong>in</strong>d zur Anzeige e<strong>in</strong>es Bilds, das nich <strong>in</strong><br />
Orig<strong>in</strong>algröße gezeigt wer<strong>de</strong>n soll, hilfreich:<br />
- getHeight() gibt die Höhe <strong>de</strong>s Bilds zurück.<br />
- getWidth() gibt die Breite <strong>de</strong>s Bilds zurück.<br />
Bsp. 247 : Verkle<strong>in</strong>ern <strong>de</strong>r Orig<strong>in</strong>algröße e<strong>in</strong>es Bilds (Haus Kirchplatz 7) um 25 bzw. 50<br />
Prozent<br />
import java.awt.Graphics;<br />
import java.awt.Image;<br />
public class Kirchplatz7 extends java.applet.Applet<br />
{<br />
Image whig;<br />
public void <strong>in</strong>it()<br />
{<br />
whig = getImage(getCo<strong>de</strong>Base(),"B01000800.jpg");<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
<strong>in</strong>t iBreite = whig.getWidth(this);<br />
<strong>in</strong>t iHoehe = whig.getHeight(this);<br />
<strong>in</strong>t xPos = 10;<br />
// 25%<br />
g.drawImage(whig, xPos, 10, iBreite / 4, iHoehe / 4, this);<br />
// 50%<br />
xPos += (iBreite / 4) + 10;<br />
g.drawImage(whig, xPos, 10, iBreite / 2, iHoehe / 2, this);<br />
}<br />
}<br />
247 vgl. pr42300<br />
274
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Das Haus "Am Kirchplatz 7". L<strong>in</strong>ks ist e<strong>in</strong> Viertel, rechts die Hälfte <strong>de</strong>r Orig<strong>in</strong>algröße dargestellt.<br />
Mit <strong>de</strong>r Klasse MediaTracker kann festgestellt wer<strong>de</strong>n, ob e<strong>in</strong> Bild für die Anzeige<br />
bereit ist. E<strong>in</strong> MediaTracker, z.B. für e<strong>in</strong> Applet, kann erzeugt wer<strong>de</strong>n über<br />
MediaTracker me<strong>in</strong>Tracker = new MediaTracker(this);<br />
„this“ bezieht sich auf das Applet. E<strong>in</strong> Bild wird angezeigt über die Metho<strong>de</strong><br />
getImage(), z.B. über Image bild = getImage(getDocumentBase(),"B......jpg").<br />
Der Mediatracker wird angewiesen, dieses Bild über<br />
me<strong>in</strong>Tracker.addImage(bild,0)<br />
zu beobachten. Mit waitForID() kann gewartet wer<strong>de</strong>n, bis das Bild fertig gela<strong>de</strong>n<br />
wir<strong>de</strong>, z.B. me<strong>in</strong>Tracker.waitForID(0). Mit waitForAll() kann gewartet<br />
wer<strong>de</strong>n, bis alle Bil<strong>de</strong>r gela<strong>de</strong>n s<strong>in</strong>d. Falls nicht die ganze Zeit gewartet wer<strong>de</strong>n soll,<br />
bis das Bild gela<strong>de</strong>n ist, kann <strong>de</strong>r La<strong>de</strong>vorgang mit <strong>de</strong>r Metho<strong>de</strong> statusID()<br />
überwacht wer<strong>de</strong>n. Beim Aufruf von statusID() wird e<strong>in</strong>e I<strong>de</strong>ntifikation (ID)<br />
übergeben, für die e<strong>in</strong> Status angelegt wer<strong>de</strong>n soll, und e<strong>in</strong> boolscher Operator mit<br />
e<strong>in</strong>er Angabe, ob <strong>de</strong>r La<strong>de</strong>vorgang für das Bild gestartet wer<strong>de</strong>n soll o<strong>de</strong>r nicht, z.B.:<br />
me<strong>in</strong>Tracker.statusID(0,true)<br />
Soll <strong>de</strong>r Status aller Bil<strong>de</strong>r überprüft wer<strong>de</strong>n, dann erfolgt <strong>de</strong>r Aufruf<br />
me<strong>in</strong>Tracker.statusAll(true). Die Metho<strong>de</strong>n statusID() bzw.<br />
statusAll() geben e<strong>in</strong>e ganze Zahl zurück, die durch folgen<strong>de</strong> Flags symbolisiert<br />
wird:<br />
MediaTracker.ABORTED<br />
MediaTracker.COMPLETE<br />
// Das La<strong>de</strong>n von Bil<strong>de</strong>rn wur<strong>de</strong> abgebrochen<br />
// Das Bil<strong>de</strong>r wur<strong>de</strong>n komplett gela<strong>de</strong>n<br />
275
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
MediaTracker.LOADING<br />
MediaTracker.ERRORED<br />
// Das Bil<strong>de</strong>r wer<strong>de</strong>n noch gela<strong>de</strong>n<br />
// Das La<strong>de</strong>n von Bil<strong>de</strong>rn ist fehlerhaft<br />
Mit checkID() bzw. checkALL() kann überprüft wer<strong>de</strong>n, ob e<strong>in</strong> Bild bzw. alle<br />
Bil<strong>de</strong>r gela<strong>de</strong>n wur<strong>de</strong>(n):<br />
public boolean checkAll()<br />
public boolean checkAll(boolean startLoad<strong>in</strong>g)<br />
public boolean checkID(<strong>in</strong>t id)<br />
public boolean checkID(<strong>in</strong>t id,boolean startLoad<strong>in</strong>g)<br />
Falls „startLoad<strong>in</strong>g“ true ist, wird <strong>de</strong>r La<strong>de</strong>vorgang für alle Bil<strong>de</strong>r, die noch nicht<br />
gela<strong>de</strong>n s<strong>in</strong>d, gestartet.<br />
4.2.2 Bildproduzenten und Bildkonsumenten<br />
Bildproduzenten s<strong>in</strong>d die Quellen für Bilddateien. Bildkonsumenten s<strong>in</strong>d Objekte, die<br />
Bil<strong>de</strong>r verwen<strong>de</strong>n 248 . In <strong>Java</strong> ist die Aufgabe von Bildproduzenten bzw.<br />
Bildkonsumenten durch die Schnittstelle ImageProducer und ImageConsumer<br />
abgebil<strong>de</strong>t.<br />
Das Interface ImageProducer beschreibt Metho<strong>de</strong>n zum Bereitstellen von Pixeln<br />
e<strong>in</strong>es Bil<strong>de</strong>s. Klassen, die die Schnittstelle implementieren, stellen Bild<strong>in</strong>formationen<br />
e<strong>in</strong>er speziellen Quelle dar. So ist die Klasse MemoryImageSource e<strong>in</strong>e<br />
vorgefertigte Klasse, die ImageProducer implementiert. Sie produziert<br />
Bild<strong>in</strong>formationen aus e<strong>in</strong>em Array von Pixeln, die im Speicher gehalten wer<strong>de</strong>n.<br />
Die Schnittstelle ImageConsumer beschreibt Metho<strong>de</strong>n, die e<strong>in</strong>em Objekt <strong>de</strong>n<br />
Zugriff auf die Bilddatei <strong>de</strong>s Produzenten erlauben.<br />
Das Produzenten/Konsumenten-Mo<strong>de</strong>ll verwen<strong>de</strong>t e<strong>in</strong>e ColorMo<strong>de</strong>l-Klasse. Bil<strong>de</strong>r,<br />
die zwischen Produzenten und Konsumenten ausgetauscht wer<strong>de</strong>n, wer<strong>de</strong>n aus<br />
Datenfel<strong>de</strong>rn von Ganzzahlen erstellt. Je<strong>de</strong> Ganzzahl steht für die Farbe e<strong>in</strong>es<br />
Pixels. Die ColorMo<strong>de</strong>l-Klasse verfügt über Metho<strong>de</strong>n zum Herausziehen von roten,<br />
grünen, blauen und „alpha“-Komponenten.<br />
Die „alpha“-Komponente steht für die Transparenz e<strong>in</strong>er Farbe. E<strong>in</strong> „alpha“-Wert von<br />
255 be<strong>de</strong>utet, daß die Farbe vollkommen lichtundurchlässig ist. E<strong>in</strong> „alpha“-Wert von<br />
0 zeigt an, daß die Farbe vollständig transparent ist.<br />
Das Standard-Farbmo<strong>de</strong>ll ist das RGB-Default-Mo<strong>de</strong>ll mit <strong>de</strong>m die 4<br />
Farbkomponenten <strong>in</strong> e<strong>in</strong>e Form „0xaarrggbb“ gebracht wer<strong>de</strong>n. Die 8 Bit ganz l<strong>in</strong>ks<br />
s<strong>in</strong>d <strong>de</strong>r alpha-Wert, die nächsten 8 Bit s<strong>in</strong>d die „Rot“-Komponente, danach kommt<br />
die „Grün“-Komponente und zum Schluß kommen 8 Bits für Blau.<br />
Bsp.: E<strong>in</strong>e Farbe von „0x12345678“ wür<strong>de</strong> e<strong>in</strong>e „alpha“-Komponente von 0x12<br />
(ziemlich transparent) haben, e<strong>in</strong>e Rotkomponente von 0x34, e<strong>in</strong>e Grünkomponente<br />
von 0x56 und e<strong>in</strong>e Blaukomponente von 0x78.<br />
248 typischerweise e<strong>in</strong>fache Zeichenrout<strong>in</strong>en, die das Bild auf <strong>de</strong>m Bildschirm anzeigen.<br />
276
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.2.3 Bildfilter<br />
ImageFilter liegen zwischen Produzenten und Konsumenten, verän<strong>de</strong>rn<br />
Bild<strong>in</strong>formationen und nehmen E<strong>in</strong>fluß auf die Größe.<br />
Subklassen <strong>de</strong>r Klasse ImageFilter:<br />
BufferedImageFilter. Mit diesem Filter läßt sich e<strong>in</strong> Objekt vom Typ BufferedImageOp<br />
übergeben, mit <strong>de</strong>m unterschiedliche Manipulationen ermöglicht wer<strong>de</strong>n. BufferedImageOp ist e<strong>in</strong>e<br />
Schnittstelle, die von Aff<strong>in</strong>eTransformOp, ConvolveOp, LookupOp implementiert wird.<br />
CropImageFilter. Bildteile wer<strong>de</strong>n herausgeschnitten.<br />
ReplicateScaleFilter. Zum Vergrößern / Verkle<strong>in</strong>ern von Bil<strong>de</strong>rn.<br />
RGBImageFilter. Dieser allgeme<strong>in</strong>e Filter ist für e<strong>in</strong>e eigene, um RGBFilter erweiterte Filterklasse<br />
gedacht.<br />
Bil<strong>de</strong>r skalieren mit getScaledInstance()<br />
Die Metho<strong>de</strong> public Image getScaledInstance(<strong>in</strong>t width,<strong>in</strong>t<br />
height,<strong>in</strong>t h<strong>in</strong>ts) liefert e<strong>in</strong> skaliertes Bild mit <strong>de</strong>n neuen Ausmaßen width<br />
und height, h<strong>in</strong>ts gibt e<strong>in</strong>en Skalierungsfaktor als Konstante an.<br />
getScaledInstance() greift auf die Filterklassen AreaAverag<strong>in</strong>gScaleFilter<br />
und ReplicateScaleFilter zu. Sie berechnen jeweils das neue Bild über <strong>de</strong>n<br />
Bildproduzenten. Bei e<strong>in</strong>er Vergrößerung wer<strong>de</strong>n die Pixel e<strong>in</strong>er Zeile und Spalte<br />
e<strong>in</strong>fach verdoppelt. Bei e<strong>in</strong>er Verkle<strong>in</strong>erung wer<strong>de</strong>n e<strong>in</strong>fach Reihen und Spalten<br />
weggelassen 249 .<br />
Beim Vergrößern o<strong>de</strong>r Verkle<strong>in</strong>ern kommt es zu Pixelfehlern und die Frage, wie Pixel<br />
vergrößert wer<strong>de</strong>n, bee<strong>in</strong>flusst das En<strong>de</strong>rgebnis und die Geschw<strong>in</strong>digkeit..<br />
getScaledInstance() verlangt nicht nur Breite und Höhe, son<strong>de</strong>rn auch e<strong>in</strong>e<br />
Konstante für die Art <strong>de</strong>r Skalierung. Der Skalierungsparameter bestimmt <strong>de</strong>n<br />
Algorithmus.<br />
Skalierungsparameter<br />
SCALE_DEFAULT<br />
SCALE_FAST<br />
SCALE_SMOOTH<br />
SCALE_REPLICATE<br />
SCALE_AREA_AVERAGING<br />
verwen<strong>de</strong>t e<strong>in</strong>en Standard-Skalierungs-Algorithmus<br />
verwen<strong>de</strong>t e<strong>in</strong>en Skalierungs-Algorithmus, <strong>de</strong>r mehr Wert auf<br />
Geschw<strong>in</strong>digkeit als auf Glätte <strong>de</strong>s Bil<strong>de</strong>s legt<br />
verwen<strong>de</strong>t e<strong>in</strong>en Algorithmus mit guter Bildqualität und legt wenig<br />
Wert auf Geschw<strong>in</strong>digkeit<br />
benutzt für <strong>de</strong>n Skalierungs-Algorithmus <strong>de</strong>n ReplicateScaleFilter<br />
verwen<strong>de</strong>t <strong>de</strong>n AreaAverag<strong>in</strong>gScaleFilter<br />
Abb.: Skalierungsparameter für getScaledInstance()<br />
Bsp. 250 :<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.image.*;<br />
import java.applet.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class ScaledImage extends Applet<br />
{<br />
249 Mit e<strong>in</strong>em AreaAverag<strong>in</strong>gScaleFilter erhält man die besseren Resultate, da Pixel nicht e<strong>in</strong>fach kopiert<br />
wer<strong>de</strong>n, son<strong>de</strong>rn e<strong>in</strong>gefügte Pixel aus <strong>de</strong>r Mittelwertberechnung bestimmt wer<strong>de</strong>n. Der Algorithmus heißt auch<br />
nearest neighbor algorithm.<br />
250 pr42300<br />
277
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
private Image orig<strong>in</strong>alImage;<br />
private Image scaledImage;<br />
public void <strong>in</strong>it()<br />
{<br />
orig<strong>in</strong>alImage = new ImageIcon("B01000800.jpg").getImage();<br />
<strong>in</strong>t prozent = 50;<br />
scaledImage = orig<strong>in</strong>alImage.getScaledInstance(<br />
(orig<strong>in</strong>alImage.getWidth(this) * prozent)/100,<br />
(orig<strong>in</strong>alImage.getHeight(this)*prozent)/100,<br />
Image.SCALE_SMOOTH );<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.drawImage(scaledImage ,5,0,this);<br />
}<br />
}<br />
Bildteile ausschnei<strong>de</strong>n mit <strong>de</strong>m CropImageFilter<br />
Für die Anwendung e<strong>in</strong>es Filters wird die Klasse FilteredImageSource<br />
herangezogen. Im Konstruktor von FilteredImageSource wird das Bild und <strong>de</strong>r<br />
Filter angegeben.<br />
Bsp.: 251 Das folgen<strong>de</strong> Applet nimmt das Bild aus <strong>de</strong>r vorstehen<strong>de</strong>n Abbildung und<br />
setzt ihm e<strong>in</strong> CropImageFilter auf, damit es nur e<strong>in</strong>en Teil <strong>de</strong>s Bil<strong>de</strong>s anzeigt.<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.image.*;<br />
import java.applet.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class ScaledCropImage extends Applet<br />
{<br />
251 pr42300<br />
278
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
private Image orig<strong>in</strong>alImage;<br />
private Image scaledImage;<br />
private Image croppedImage;<br />
private ImageFilter cropFilter;<br />
public void <strong>in</strong>it()<br />
{<br />
orig<strong>in</strong>alImage = new ImageIcon("B01000800.jpg").getImage();<br />
<strong>in</strong>t prozent = 50;<br />
scaledImage = orig<strong>in</strong>alImage.getScaledInstance(<br />
(orig<strong>in</strong>alImage.getWidth(this) * prozent)/100,<br />
(orig<strong>in</strong>alImage.getHeight(this)*prozent)/100,<br />
Image.SCALE_SMOOTH );<br />
cropFilter = new CropImageFilter(0,0,240,200);<br />
croppedImage = createImage(new<br />
FilteredImageSource(scaledImage.getSource(),cropFilter));<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.drawImage(croppedImage ,3,0,this);<br />
}<br />
}<br />
Manipulation über Farbfilter<br />
Die folgen<strong>de</strong> Filterklasse ist abgeleitet von RGBImageFilter. Sie umfaßt<br />
filterRGB() und zw<strong>in</strong>gt e<strong>in</strong>em Bild e<strong>in</strong>en Grauschleier auf.<br />
class GrayFilter extends RGBImageFilter<br />
{<br />
public GrayFilter() {<br />
canFilterIn<strong>de</strong>xColorMo<strong>de</strong>l = true;<br />
}<br />
}<br />
public <strong>in</strong>t filterRGB(<strong>in</strong>t x, <strong>in</strong>t y, <strong>in</strong>t rgb) {<br />
<strong>in</strong>t a = rgb & 0xff000000;<br />
<strong>in</strong>t r = (((rgb & 0xff0000) + 0x180000)/3) & 0xff0000;<br />
<strong>in</strong>t g = (((rgb & 0x00ff00) + 0x018000)/3) & 0x00ff00;<br />
<strong>in</strong>t b = (((rgb & 0x0000ff) + 0x000180)/3) & 0x0000ff;<br />
return a | r | g | b;<br />
}<br />
279
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp. 252 : Das folgen<strong>de</strong> Applet benutzt das Bild <strong>de</strong>r vorstehen<strong>de</strong>n Abbildung und färbt<br />
es mit Hilfe <strong>de</strong>r vorstehen<strong>de</strong>n Filterklasse GrayFilter grau e<strong>in</strong>.<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.image.*;<br />
import java.applet.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class ScaledCropGrayImage extends Applet<br />
{<br />
private Image orig<strong>in</strong>alImage;<br />
private Image scaledImage;<br />
private Image croppedImage;<br />
private Image grauImage;<br />
private ImageFilter cropFilter;<br />
private ImageFilter grauFilter;<br />
public void <strong>in</strong>it()<br />
{<br />
orig<strong>in</strong>alImage = new ImageIcon("B01000800.jpg").getImage();<br />
<strong>in</strong>t prozent = 50;<br />
scaledImage = orig<strong>in</strong>alImage.getScaledInstance(<br />
(orig<strong>in</strong>alImage.getWidth(this) * prozent)/100,<br />
(orig<strong>in</strong>alImage.getHeight(this)*prozent)/100,<br />
Image.SCALE_SMOOTH );<br />
cropFilter = new CropImageFilter(0,0,240,200);<br />
croppedImage = createImage(new<br />
FilteredImageSource(scaledImage.getSource(),cropFilter));<br />
grauFilter = new GrayFilter();<br />
ImageProducer erzeuger = new<br />
FilteredImageSource(croppedImage.getSource(),grauFilter);<br />
grauImage = this.createImage(erzeuger);<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
g.drawImage(grauImage,3,0,this);<br />
g.drawImage(croppedImage ,250,0,this);<br />
}<br />
}<br />
252 vgl. pr42300<br />
280
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.2.4 Kopieren von Speicher <strong>in</strong> e<strong>in</strong> Bild bzw. von Bil<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>en Speicher<br />
4.2.4.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 Bil<strong>de</strong>rn ist e<strong>in</strong> Datenfeld mit ganzen<br />
Zahlen, die für die Farbe e<strong>in</strong>es je<strong>de</strong>n Pixels stehen. Möglich wird das durch die<br />
Klasse MemoryImageSource.<br />
Bsp.: Das folgen<strong>de</strong> 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 <strong>de</strong>s Bilds aus <strong>de</strong>m Array pixels.<br />
Die Pixels wer<strong>de</strong>n zeilenweise von Postion 0<br />
aus <strong>de</strong>m 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 <strong>de</strong>s Bilds wer<strong>de</strong>n 10fach vergroessert<br />
g.drawImage(me<strong>in</strong>Bild,0,0,100,100,this);<br />
}<br />
}<br />
281
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Darstellung von SpeicherBild<br />
4.2.4.2 Kopieren von Bil<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>en Speicher<br />
Die PixelGrabber-Klasse nimmt e<strong>in</strong> Bild und macht aus diesem e<strong>in</strong> Datenfeld mit<br />
ganzen Zahlen. E<strong>in</strong> PixelGrabber wird auf e<strong>in</strong> Image-Objekt aufgesetzt und füllt e<strong>in</strong><br />
Ganzzahl-Feld mit <strong>de</strong>n Farbwerten, die die Anteile <strong>de</strong>r Farben rot, grün und blau<br />
enthalten.<br />
Der PixelGrabber ist für Modifikationen bereits existieren<strong>de</strong>r Bil<strong>de</strong>r nützlich.<br />
class java.awt.image.PixelGrabber implements ImageConsumer<br />
Konstruktor.<br />
public PixelGrabber(Image img, <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 />
feld[], <strong>in</strong>t verschiebung, <strong>in</strong>t scanSize)<br />
erzeugt e<strong>in</strong> PixelGrabber-Objekt, das e<strong>in</strong> Rechteck von RGB-Farben aus <strong>de</strong>m Feld holt. Das<br />
Rechteck ist durch die Maße x, y, breite, hoehe beschrieben. Die Farbe für e<strong>in</strong>en Punkt (i,j) s<strong>in</strong>d im<br />
Feld an <strong>de</strong>r Position (j-y)*scanSize+(i-x)+verschiebung. Mit <strong>de</strong>r Umwandlung wird noch<br />
nicht begonnen. Sie muß mit <strong>de</strong>r Funktion grabPixels() angeregt wer<strong>de</strong>n.<br />
Metho<strong>de</strong>n.<br />
public boolean grabPixels() throws InterruptedException<br />
Die Werte von e<strong>in</strong>em Image o<strong>de</strong>r ImageProducer wer<strong>de</strong>n geholt. Die Funktion kann von außen<br />
unterbrochen wer<strong>de</strong>n.<br />
public <strong>in</strong>t getHeight()<br />
liefert die Höhe <strong>de</strong>s Pixelfelds. Ist die Höhe nicht verfügbar, dann ist das Ergebnis –1.<br />
public <strong>in</strong>t getWidth() liefert die Breite <strong>de</strong>s Pixelfelds.<br />
Bsp.: Das nachfolgen<strong>de</strong> Bild lädt e<strong>in</strong> Bild und gibt die Farb<strong>in</strong>formationen auf <strong>de</strong>r<br />
Konsole aus.<br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.image.*;<br />
public class PR42400 extends Frame<br />
{<br />
Image bild;<br />
<strong>in</strong>t breite, hoehe;<br />
<strong>in</strong>t pixels[];<br />
public PR42400()<br />
{<br />
282
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
/*<br />
bild = Toolkit.getDefaultToolkit().getImage(<br />
"d:\\jdk1.3.1\\pgj\\progr\\pr42400\\B01000800.jpg");<br />
*/<br />
bild = new ImageIcon("B01000800.jpg").getImage();<br />
if (bild == null) System.out.pr<strong>in</strong>tln("Ke<strong>in</strong> Bild");<br />
breite = bild.getWidth(this);<br />
System.out.pr<strong>in</strong>tln(breite);<br />
hoehe = bild.getHeight(this);<br />
pixels = new <strong>in</strong>t [breite * hoehe];<br />
PixelGrabber grabber = new PixelGrabber(bild,0,0,breite,hoehe,<br />
pixels,0,breite);<br />
try {<br />
grabber.grabPixels();<br />
}<br />
catch(InterruptedException e)<br />
{<br />
System.err.pr<strong>in</strong>tln("Fehler beim Holen <strong>de</strong>r Pixel");<br />
}<br />
setSize(breite,hoehe);<br />
repa<strong>in</strong>t();<br />
addMouseListener(new MouseAdapter()<br />
{<br />
public void mouseClicked(MouseEvent m)<br />
{<br />
<strong>in</strong>t pixel = pixels[breite * m.getY() + m.getX()];<br />
<strong>in</strong>t alpha = (pixel >> 24) & 0xff;<br />
<strong>in</strong>t rot = (pixel >> 16) & 0xff;<br />
<strong>in</strong>t gruen = (pixel >> 8) & 0xff;<br />
<strong>in</strong>t blau = (pixel) & 0xff;<br />
System.out.pr<strong>in</strong>tln("R=" +rot+ " G=" +gruen+ "B=" +blau);<br />
}<br />
});<br />
}<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
if (bild != null)<br />
g.drawImage(bild,0,0,this);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Frame f = new PR42400();<br />
f.show();<br />
}<br />
}<br />
283
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.3 <strong>Java</strong> 2D<br />
Überblick<br />
<strong>Java</strong> 2D ist Bestandteil <strong>de</strong>r <strong>Java</strong> Foundation Classes (JFC) 253 , e<strong>in</strong> Teil <strong>de</strong>ssen, 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. <strong>Java</strong> 2D unterstützt:<br />
- Shapes (Formen): L<strong>in</strong>ien, Polygonzüge, Rechtecke, Ellipsen, parametrische Kurven, etc.<br />
- Strokes (Stricharten): Striche verschie<strong>de</strong>ner Dicke und Farbe zum Zeichnen von Shapes,<br />
ausgezogen o<strong>de</strong>r aus Punkten, etc., zusammengesetzt sptze o<strong>de</strong>r abgerun<strong>de</strong>te Ecken.<br />
- Fill<strong>in</strong>g (Ausfüllen): geschlossene Polygonzüge o<strong>de</strong>r Kurven bil<strong>de</strong>n Figuren, die mit Farben,<br />
Mustern, Texturen, etc. (Pa<strong>in</strong>ts) ausgefüllt wer<strong>de</strong>n können.<br />
- Antialias<strong>in</strong>g: Geometrische Formen ergeben auf <strong>de</strong>m Rasterschirm oft "unschöne Treppeneffekte"<br />
(Alias<strong>in</strong>g). Mit Antalias<strong>in</strong>g-Techniken können diese Effekte i. allg. gemil<strong>de</strong>rt wer<strong>de</strong>n.<br />
- Images (Rasterbil<strong>de</strong>r), z.B. e<strong>in</strong>gescannte Fotografien.<br />
- Text: Unterstützung verschie<strong>de</strong>ner Zeichensätze (Fonts) und Darstellungsarten (Text Layout).<br />
- Transformations: Translation (Verschieben), Rotation, Skalierung (Vergrössern, Verkle<strong>in</strong>ern),<br />
Verzerrung, ets. von Grafiken, Text und Bil<strong>de</strong>rn (Images)<br />
- Clipp<strong>in</strong>g (Wegschnei<strong>de</strong>n, Kappen): z.B. hat <strong>in</strong> e<strong>in</strong>em Fenster nur e<strong>in</strong> Teil e<strong>in</strong>er Grafik Platz, dann<br />
wird <strong>de</strong>r Rest entfernt ("weggeschnitten").<br />
- Composites: Bil<strong>de</strong>r, Figuren, etc. wer<strong>de</strong>n übere<strong>in</strong>an<strong>de</strong>r gelegt. Wie wer<strong>de</strong>n die e<strong>in</strong>zelnen<br />
schichten gewichtet, z.B. bzgl. <strong>de</strong>r Durchsichtigkeit (Transparenz)?<br />
- Color: E<strong>in</strong>satz von Farben, verschie<strong>de</strong>ne Farbmo<strong>de</strong>lle verwendbar.<br />
- Image Process<strong>in</strong>g (Bildverarbeitung): z.B. Verschärfen, Farbkorrekturen, etc.<br />
- Pr<strong>in</strong>t<strong>in</strong>g (Drucken): Ausgabe aller <strong>Java</strong> 2D Grafiken auf e<strong>in</strong>em Drucker, Steuerungsmöglichkeiten,<br />
etc.<br />
Ren<strong>de</strong>r<strong>in</strong>g Mo<strong>de</strong>ll<br />
Der Kern von <strong>Java</strong> 2D ist die Klasse java.awt.Graphics2D. Sie ist e<strong>in</strong>e Erweiterung<br />
<strong>de</strong>r AWT-Klasse und stellt die Implementierung <strong>de</strong>s Ren<strong>de</strong>r<strong>in</strong>g-Mo<strong>de</strong>lls von <strong>Java</strong> 2D<br />
dar.<br />
Wie wird Grafik auf e<strong>in</strong> Ausgabegerät (Bildschirm, Drucker, Puffer) abgebil<strong>de</strong>t /<br />
übertragen?<br />
1. Je<strong>de</strong>s Graphics2D-Objekt ist mit e<strong>in</strong>em Ausgabeziel verknüpft, das festlegt, woh<strong>in</strong> geren<strong>de</strong>rt wird.<br />
Die Eigenschaften <strong>de</strong>s Ausgabeziels, wie z.B. Pixelformat und Auflösung wer<strong>de</strong>n durch e<strong>in</strong><br />
GraphicsConfiguration-Objekt beschieben<br />
2. Ren<strong>de</strong>r<strong>in</strong>g:<br />
(a) Durch Setzen von Attributen wird <strong>de</strong>r grafische Kontext 254 festgelegt.<br />
(b) Das darzustellen<strong>de</strong> Grafikobjekt (Shape, Text o<strong>de</strong>r Bild) wird ausgewählt.<br />
(c) Das Ren<strong>de</strong>r<strong>in</strong>g wird durchgeführt.<br />
Da die meisten Metho<strong>de</strong>n <strong>de</strong>n Zugriff auf e<strong>in</strong> allgeme<strong>in</strong>es Graphics-Objekt liefern ist<br />
e<strong>in</strong>e Typumwandlung (Cast) nach Graphics2D nötig.<br />
253 JFC ist e<strong>in</strong>e Erweiterung <strong>de</strong>s Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit (AWT): AWT = UIToolkit (Sw<strong>in</strong>g) + Draw<strong>in</strong>g<br />
Toolkit (2D API)<br />
254 Der grafische Kontext kann durch die folgen<strong>de</strong> Attribute festgelegt wer<strong>de</strong>n: Font (Schriftart), Stroke<br />
(Strichart), Pa<strong>in</strong>t (Füllfarbe, Textur), Composite (Vermischen von mehreren Grafikobjekten), Ren<strong>de</strong>r<strong>in</strong>g H<strong>in</strong>ts<br />
(Antialias<strong>in</strong>g, Dither<strong>in</strong>g, etc.), Clipp<strong>in</strong>g (Beschränkung <strong>de</strong>s Ren<strong>de</strong>r<strong>in</strong>g auf e<strong>in</strong>en bestimmten Ausschnitt),<br />
Transform (Aff<strong>in</strong>e Transformation)<br />
284
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Graphics<br />
{ abstract }<br />
Graphics2D<br />
{ abstract }<br />
Stroke stroke // Def<strong>in</strong>ition von L<strong>in</strong>ienstiften<br />
Pa<strong>in</strong>t pa<strong>in</strong>t<br />
// Erweiterung <strong>de</strong>s Farbmo<strong>de</strong>lls<br />
Aff<strong>in</strong>eTransform transform // erlaubt Verän<strong>de</strong>rungen <strong>de</strong>r Form<br />
Composite composite // gibt an, wie Objekte verschie<strong>de</strong>ner Farben überlagert wer<strong>de</strong>n<br />
// sollen, erlaubt weiche Farbübergänge (Anti-Alias<strong>in</strong>g)<br />
><br />
protected Graphics2D()<br />
><br />
public abstract void addRen<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>ts(Map h<strong>in</strong>ts)<br />
public abstract void clip(Shape s)<br />
public abstract draw(Shape s)<br />
public abstract void drawImage(Image img, Aff<strong>in</strong>eTransform xForm, ImageObserver obs)<br />
public abstract void fill(Shape s)<br />
public abstract GraphicsConfiguration getDeviceConfiguration()<br />
public abstract FontRen<strong>de</strong>rContext getFontRen<strong>de</strong>rContext()<br />
public abstract Pa<strong>in</strong>t getPa<strong>in</strong>t()<br />
public abstract Object getRen<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>t(Ren<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>ts.Key h<strong>in</strong>tKey)<br />
public abstract Stroke getStroke()<br />
public abstract Aff<strong>in</strong>eTransform getTransform()<br />
public abstract void rotate(double theta)<br />
public abstract void scale(double sx, double sy)<br />
public abstract void setComposite(Composite comp)<br />
public abstract setPa<strong>in</strong>t(Pa<strong>in</strong>t pa<strong>in</strong>t)<br />
public abstract void setRen<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>t(Ren<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>ts.Key h<strong>in</strong>tKey, Object h<strong>in</strong>tValue)<br />
public abstract void setTransform(Aff<strong>in</strong>eTransform Tx)<br />
public abstract void transform(Aff<strong>in</strong>eTransform Tx)<br />
public abstract void translate(double tx, double ty)<br />
public abstract void translate(<strong>in</strong>t x, <strong>in</strong>t y)<br />
...<br />
Abb.: Die Klasse Graphics2D<br />
4.3.1 Das Zeichnen unter <strong>Java</strong>2D API<br />
Zeichnen unter <strong>de</strong>m AWT Draw<strong>in</strong>g Mo<strong>de</strong>l<br />
Dieses Mo<strong>de</strong>ll wur<strong>de</strong> bisher zum Zeichnen verwen<strong>de</strong>t, z. B.:<br />
import java.awt.*;<br />
import java.applet.*;<br />
public class MaleGefRechteck extends Applet<br />
{<br />
// Zeichnen unter <strong>de</strong>m AWT Draw<strong>in</strong>g Mo<strong>de</strong>l<br />
public void pa<strong>in</strong>t(Graphics g)<br />
285
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
g.setColor(Color.red);<br />
g.fillRect(300,300,200,100);<br />
}<br />
}<br />
Die Vorgehensweise beim Bearbeiten für je<strong>de</strong> Komponente kann aus diesem Bsp.<br />
unmittelbar abgeleitet wer<strong>de</strong>n:<br />
1. Spezifikation <strong>de</strong>r notwendigen Atribute für die zu zeichnen<strong>de</strong> Form, z.B. die Farbe mit „setColor“.<br />
2. Def<strong>in</strong>ition <strong>de</strong>r zu zeichnen<strong>de</strong>n Form<br />
3. Festlegen <strong>de</strong>s genauen Aussehens <strong>de</strong>r Form, z.B. über e<strong>in</strong>e passen<strong>de</strong> Grafikmetho<strong>de</strong>.<br />
Das AWT biete e<strong>in</strong>fache grafische Funktionen an. Diese AWT-Funktionen besitzen<br />
aber<br />
- e<strong>in</strong>en niedrigen Abstraktionsgrad und ke<strong>in</strong>e objektorientierte Repräsentation von grafischen<br />
Objekten.<br />
- diskrete Fenster- statt kont<strong>in</strong>uierlicher Weltkoord<strong>in</strong>aten<br />
- e<strong>in</strong> "schwaches" Mo<strong>de</strong>ll zur Abbildung von Farben und Farbverläufen.<br />
Zeichnen mit <strong>Java</strong>2D<br />
Das <strong>Java</strong>2D API umfaßt zusätzliche unterstützen<strong>de</strong> Features zur Spezifizierung von<br />
Zeichenstiften, komplexen Formen und diversen Zeichenprozessen. Zur Nutzung<br />
dieser Möglichkeit muß <strong>de</strong>r Graphics-Parameter <strong>de</strong>r pa<strong>in</strong>t()-Metho<strong>de</strong> <strong>in</strong> e<strong>in</strong><br />
Graphics2D-Objekt gebracht wer<strong>de</strong>n („gecastet“) wer<strong>de</strong>n, 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 <strong>de</strong>r Attribute<br />
g2d.setColor(Color.red);<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form (Verwen<strong>de</strong> Even-Odd-Regel)<br />
GeneralPath path = new GeneralPath();<br />
path.moveTo(300.0f,400.0f); // untere l<strong>in</strong>ke Ecke<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();<br />
// Schliessen <strong>de</strong>s Rechtecks<br />
// Fuellen <strong>de</strong>r Form<br />
g2d.fill(path);<br />
}<br />
}<br />
E<strong>in</strong>e Polygon-Klasse wie unter <strong>de</strong>m AWT gibt es <strong>in</strong> <strong>de</strong>m 2D-API nicht. Hier wird e<strong>in</strong><br />
neuer Weg e<strong>in</strong>geschlagen, <strong>de</strong>r über die Klasse GeneralPath geht. Damit lassen<br />
sich beliebige Formen bil<strong>de</strong>n. Dem Pfad wer<strong>de</strong>n verschie<strong>de</strong>ne Punkte h<strong>in</strong>zugefügt,<br />
die dann verbun<strong>de</strong>n wer<strong>de</strong>n. Die Punkte müssen nicht zw<strong>in</strong>gend, wie bei e<strong>in</strong>em<br />
Polygon mit L<strong>in</strong>ien verbun<strong>de</strong>n wer<strong>de</strong>n, son<strong>de</strong>rn lassen sich auch durch quadratische<br />
o<strong>de</strong>r kubische Kurven verb<strong>in</strong><strong>de</strong>n. Da Graphics2D e<strong>in</strong>e Unterklasse von Graphics ist,<br />
lassen sich natürlich alle AWT-Operatoren weiter verwen<strong>de</strong>n.<br />
286
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp.: Aufbau e<strong>in</strong>es "roten Polygons" aus e<strong>in</strong>em Pfad 255<br />
import java.awt.*;<br />
import java.applet.*;<br />
import java.awt.geom.*;<br />
public class PolyRot extends Applet<br />
{<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
// Erzeuegen e<strong>in</strong>es Graphics2D-Objekt<br />
Graphics2D g2d = (Graphics2D) g;<br />
g2d.setColor(Color.blue);<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form<br />
GeneralPath e<strong>in</strong>Pfad = new GeneralPath();<br />
// Startpunkt festlegen (Ursprung <strong>de</strong>r sichtbaren<br />
// Zeichenflaeche <strong>de</strong>s Fensters<br />
e<strong>in</strong>Pfad.moveTo(getInsets().left,getInsets().top);<br />
for (<strong>in</strong>t i = 1, j = 10;i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Verfahrensweise beim Zeichnen mit <strong>de</strong>n <strong>Java</strong> 2D-API-Klassen<br />
1. Spezifikation <strong>de</strong>r notwendigen beschreiben<strong>de</strong>n Attribute<br />
2. Def<strong>in</strong>ition <strong>de</strong>r Form, e<strong>in</strong>es Textstr<strong>in</strong>gs o<strong>de</strong>r e<strong>in</strong>es Bilds.<br />
Das <strong>Java</strong>2D-API behan<strong>de</strong>lt Positionsangeben (Pfa<strong>de</strong>), Texte und Bil<strong>de</strong>r gleichartig.<br />
Sie können rotiert, skaliert, verzerrt und mit diversen Metho<strong>de</strong>n zusammengesetzt<br />
wer<strong>de</strong>n. Das „Shape“-Interface <strong>de</strong>f<strong>in</strong>iert e<strong>in</strong>en ganzen Satz von Metho<strong>de</strong>n 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 (zusammengestzt aus L<strong>in</strong>ien- und Kurvensegmenten) verwen<strong>de</strong>t wer<strong>de</strong>n<br />
kann.<br />
><br />
java.awt.Shape<br />
java.awt.Polygon java.awt.geom.L<strong>in</strong>e2D java.awt.geom.GeneralPath java.awt.geom.Area<br />
java.awt.geom.RectangularShape<br />
java.awt.geom.Arc2D java.awt.geom.Ellipse2D java.awt.geom.Rectangle2D<br />
Abb.: das Interface Shape und implementieren<strong>de</strong> Klassen<br />
draw() aus <strong>de</strong>r Klasse Graphics2D nimmt e<strong>in</strong> Shape-Objekt und zeichnet es.<br />
Shape-Objekte s<strong>in</strong>d L<strong>in</strong>ien, Polygone o<strong>de</strong>r auch Kurven.<br />
abstract public void draw(Shape s) zeichnet die Forrm im aktuellen<br />
Graphics2D-Kontext.<br />
Bsp.: E<strong>in</strong> Kreis <strong>in</strong>nerhalb von e<strong>in</strong>em Kasten. 256<br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.geom.*;<br />
public class ShapeBsp extends JPanel<br />
{<br />
private Ellipse2D.Double kreis<br />
= new Ellipse2D.Double(10,10,350,350);<br />
private Rectangle2D.Double quadrat<br />
= new Rectangle2D.Double(10,10,350,350);<br />
public void pa<strong>in</strong>tComponent(Graphics g)<br />
{<br />
clear(g);<br />
Graphics2D g2d = (Graphics2D) g;<br />
256 vgl. PR43100<br />
288
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
g2d.fill(kreis);<br />
g2d.draw(quadrat);<br />
}<br />
protected void clear(Graphics g)<br />
{<br />
super.pa<strong>in</strong>tComponent(g);<br />
// loescht die Pixelmap <strong>de</strong>s Bildschirms<br />
// per Default gibt es Double Buffer<strong>in</strong>g<br />
}<br />
protected Ellipse2D.Double getCircle()<br />
{<br />
return (kreis);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
ShapeBsp jp = new ShapeBsp();<br />
Str<strong>in</strong>g titel = jp.getClass().toStr<strong>in</strong>g();<br />
if (titel.<strong>in</strong><strong>de</strong>xOf("class") != -1)<br />
titel = titel.substr<strong>in</strong>g(6);<br />
JFrame frame = new JFrame(titel);<br />
frame.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 />
frame.getContentPane().add(jp,Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setSize(380,400);<br />
frame.setVisible(true);<br />
}<br />
}<br />
3. Festlegen vom Aussehen <strong>de</strong>r Form, <strong>de</strong>s Textstr<strong>in</strong>gs o<strong>de</strong>r <strong>de</strong>s Bil<strong>de</strong>s über<br />
passen<strong>de</strong> Graphics2D-Metho<strong>de</strong>n.<br />
289
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
290
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Geometrische Objekte<br />
<strong>Java</strong>2D unterschei<strong>de</strong>t folgen<strong>de</strong> geometrische Objekte:<br />
- Shapes: beliebige offene o<strong>de</strong>r geschlossene Figuren, zusammengesetzt aus Folgen von L<strong>in</strong><strong>in</strong>en und<br />
Kurvensegmenten.<br />
- Text: Text <strong>in</strong> vorhert festgelegtem Zeichensatz (Zeichen s<strong>in</strong>d als Shapes <strong>de</strong>f<strong>in</strong>iert)<br />
- Image (rechteckiger Ausschnitt e<strong>in</strong>er Bitmap).<br />
Je<strong>de</strong>m geometrischen Objekt (Punkt, Klasse, Rechteck) ist e<strong>in</strong> <strong>Java</strong>-Klasse<br />
zugeordnet. Das konkrete Aussehen <strong>de</strong>s Objekts (Farbe, Umriss) wird erst bei <strong>de</strong>r<br />
Darstellung festgelegt. Die Darstellung erfolgt über e<strong>in</strong>en Rasterisierer 257 , <strong>de</strong>r<br />
Kompositionsvorschriften für kont<strong>in</strong>uierliche geometrische Objekte <strong>in</strong><br />
Weltkoord<strong>in</strong>aten über e<strong>in</strong> diskretes Raster umsetzt.<br />
Allgeme<strong>in</strong>e Vorgehensweise<br />
1. Setzen von Graphikattributen (ren<strong>de</strong>r<strong>in</strong>g attributes) wie L<strong>in</strong>ientyp, Füllmuster (auch<br />
komplexe Gradienten).<br />
2. Def<strong>in</strong>ition <strong>de</strong>r Form, e<strong>in</strong>er Zeichenkette (auszugeben<strong>de</strong>r Text) o<strong>de</strong>r e<strong>in</strong>es Bilds.<br />
3. Anwendung e<strong>in</strong>er Transformation (z.B. Bild verzerren o<strong>de</strong>r Filtern, Text drehen<br />
etc.).<br />
4. Ausgabe e<strong>in</strong>es graphischen Elements (z.B. durch die Graphics2D-Metho<strong>de</strong>n<br />
draw(), drawImage(), drawRectangle() o<strong>de</strong>r fill().<br />
Die eigentliche Ausgabe erfolgt <strong>in</strong> 4 Schritten:<br />
1. Das Objekt wird <strong>in</strong> Grafikprimitive umgewan<strong>de</strong>lt und auf <strong>de</strong>n Koord<strong>in</strong>atenraum <strong>de</strong>s Ausgabegerätes<br />
(<strong>de</strong>vice space) abgebil<strong>de</strong>t.<br />
- Han<strong>de</strong>lt es sich um e<strong>in</strong>e Form (Shape), so wer<strong>de</strong>n die <strong>in</strong> <strong>de</strong>r Form enthaltenen Graphikelemente<br />
bestimmt.<br />
- Han<strong>de</strong>lt es sich um e<strong>in</strong>en Text, wird die Form <strong>de</strong>r Buchstaben (Glyphen) aus <strong>de</strong>r Schrift<strong>in</strong>formation<br />
bestimmt und <strong>in</strong> e<strong>in</strong>en Umriß (outl<strong>in</strong>e) umgewan<strong>de</strong>lt, <strong>de</strong>r sich als Shape-Objekt beschreiben lässt.<br />
- Bei Bil<strong>de</strong>rn (images) wird ihre Bound<strong>in</strong>g Box <strong>in</strong> Device-Koord<strong>in</strong>aten umgewan<strong>de</strong>lt (unter<br />
Verwendung <strong>de</strong>r im Programm angegebenen Transformationen <strong>de</strong>s Graphics2D-Kontextes)<br />
2. Der aktuelle clipp<strong>in</strong>g path schränkt die Darstellungsoperation (ren<strong>de</strong>r<strong>in</strong>g operation) e<strong>in</strong>. E<strong>in</strong><br />
clipp<strong>in</strong>g path kann je<strong>de</strong> Form annehmen, die sich durch e<strong>in</strong> Shape-Objekt beschreiben lässt.<br />
Normalerweise han<strong>de</strong>lt es sich um <strong>de</strong>n Bereich <strong>de</strong>r gera<strong>de</strong> tatsächlich gezeichnet wer<strong>de</strong>n kann (z.B.<br />
sichtbare Fläche e<strong>in</strong>es Fensters).<br />
3. Die Ausgabefarbe wird bestimmt (aus <strong>de</strong>n Bilddaten bei Bil<strong>de</strong>rn, aus <strong>de</strong>m aktuellen Pa<strong>in</strong>t- o<strong>de</strong>r<br />
Color-Objekt <strong>in</strong> allen an<strong>de</strong>ren Fällen.<br />
4. Die Farbe wird aus das auszugeben<strong>de</strong> Objekt angewandt.<br />
<strong>Java</strong> 2D API-Klassen 258<br />
Außer <strong>de</strong>r Klasse java.awt.Graphics2D umfaßt <strong>Java</strong> 2D API Klassen <strong>in</strong> <strong>de</strong>n<br />
Paketen java.awt.geom (geometrische Formen, Pfa<strong>de</strong> und Transformationen),<br />
257 Die kont<strong>in</strong>uierlichen Shapes (z.B. e<strong>in</strong> Kreis) wer<strong>de</strong>n vom Rasterisierer <strong>in</strong> diskrete Rasterbelegungen<br />
umgewan<strong>de</strong>lt. Man unterschei<strong>de</strong>t Rasterisierung mit o<strong>de</strong>r ohne Alias<strong>in</strong>g:<br />
258 pr43210<br />
291
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
java.awt.font, java.awt.color (Farbräume), java.awt.image und<br />
java.awt.image.ren<strong>de</strong>rable (Bitmaps und Filter) sowie java.awt.pr<strong>in</strong>t<br />
(Drucken).<br />
Die Klassen für geometrische Objekte, die sich von <strong>de</strong>r Klasse Shape ableiten, s<strong>in</strong>d<br />
Polygon, RectangularShape, Rectangle, Area, QuadCurve2D und<br />
CubicCurve2D 259 . E<strong>in</strong>e beson<strong>de</strong>re Klasse, die auch von Shape abgeleitet ist, heißt<br />
GeneralPath. Damit lassen sich mehrere Objekte e<strong>in</strong>er Figur zusammensetzten.<br />
Die Klasse Rectangle2D, RoundRectangle2D, Aread2D und Ellipse2D erben<br />
von <strong>de</strong>r Klasse RectangularShape und s<strong>in</strong>d Objekte, die durch e<strong>in</strong>e rechteckige<br />
Box umgeben s<strong>in</strong>d.<br />
4.3.2 Eigenschaften geometrischer Objekte<br />
Dicke und Art <strong>de</strong>r L<strong>in</strong>ien bestimmen<br />
Die Metho<strong>de</strong> setStroke() kann <strong>de</strong>f<strong>in</strong>ieren<br />
- die Dicke (width)<br />
- die Eigenschaft wie e<strong>in</strong> L<strong>in</strong>iensegment beg<strong>in</strong>nt und abschließt<br />
- die Art, wie sich die L<strong>in</strong>ien verb<strong>in</strong><strong>de</strong>n<br />
- e<strong>in</strong> L<strong>in</strong>ien-Pattern (dash attributes)<br />
Unterstützt wird setStroke() durch die Schnittstelle Stroke, die konkret durch<br />
BasicStroke implementiert wird, z.B.<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2 = (Graphics2D) g;<br />
BasicStroke pen =<br />
new BasicStroke(2.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND)<br />
g2.setStroke(pen);<br />
}<br />
Für BasicStroke gibt es 9 Konstruktoren. Der hier verwen<strong>de</strong>te Konstruktor von<br />
BasicStroke har drei Argumente:<br />
- e<strong>in</strong>en float-Wert, <strong>de</strong>r die L<strong>in</strong>ienstärke angibt<br />
- e<strong>in</strong>en <strong>in</strong>t-Wert, <strong>de</strong>r die Art <strong>de</strong>s L<strong>in</strong>ienen<strong>de</strong>s festlegt<br />
- e<strong>in</strong>en <strong>in</strong>t-Wert, <strong>de</strong>r <strong>de</strong>n Stil <strong>de</strong>s Verb<strong>in</strong>dungsstücks zwischen zwei L<strong>in</strong>iensegmenten festlegt<br />
Beson<strong>de</strong>rs bei breiten L<strong>in</strong>ie ist es <strong>in</strong>teressant, wie die L<strong>in</strong>ie en<strong>de</strong>t. Hier läßt sich aus<br />
CAP-BUTT (ke<strong>in</strong>e Abschlußpunkte), CAP_ROUND (Anzeige von Kreisen an bei<strong>de</strong>n<br />
En<strong>de</strong>n) und CAP_SQUARE auswählen.<br />
Die möglichen Stile für Verb<strong>in</strong>dungselemente s<strong>in</strong>d JOIN_MITER (Abschluß von<br />
L<strong>in</strong>ien so, daß sie senkrecht aufe<strong>in</strong>an<strong>de</strong>r stehen), JOIN_ROUND (Abschluß <strong>de</strong>r L<strong>in</strong>ien<br />
durch abgerun<strong>de</strong>te Ecken) und JOIN-BEVEL (E<strong>in</strong>e L<strong>in</strong>ie wird zwischen <strong>de</strong>n äußeren<br />
Eckpunkten gezogen).<br />
259 Beschreibung quadratischer und kubischer Kurvensegmente. Das s<strong>in</strong>d Kurven, die durch zwei Endpunkte<br />
und durch Kontrollpunkte dazwischen gegeben s<strong>in</strong>d. Kubische Kurvensegmente wer<strong>de</strong>n auch Bézier-Kurven<br />
genannt.<br />
292
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp 260 .: Das folgen<strong>de</strong> Applet zeigt Verb<strong>in</strong>dungselemente zwischen L<strong>in</strong>ien<br />
import java.awt.*;<br />
import java.applet.*;<br />
import java.awt.geom.*;<br />
public class StrokeDemo extends Applet<br />
{<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2d = (Graphics2D) g;<br />
BasicStroke pen1 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen1);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(10f,10f,210f,10f));<br />
BasicStroke pen2 = new BasicStroke(10.0f,BasicStroke.CAP_ROUND,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen2);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(10f,30f,210f,30f));<br />
BasicStroke pen3 = new BasicStroke(10.0f,BasicStroke.CAP_SQUARE,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen3);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(10f,50f,210f,50f));<br />
BasicStroke pen4 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen4);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(10f,70f,100f,70f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(100f,70f,100f,120f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(100f,120f,10f,120f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(10f,120f,10f,70f));<br />
BasicStroke pen5 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_BEVEL);<br />
g2d.setStroke(pen5);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(120f,70f,210f,70f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(210f,70f,210f,120f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(210f,120f,120f,120f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(120f,120f,120f,70f));<br />
BasicStroke pen6 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen6);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(30f,140f,10f,160f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(30f,140f,50f,160f));<br />
BasicStroke pen7 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_BEVEL);<br />
g2d.setStroke(pen7);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(90f,140f,70f,160f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(90f,140f,110f,160f));<br />
BasicStroke pen8 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_ROUND);<br />
g2d.setStroke(pen8);<br />
g2d.draw(new L<strong>in</strong>e2D.Float(150f,140f,130f,160f));<br />
g2d.draw(new L<strong>in</strong>e2D.Float(150f,140f,170f,160f));<br />
float dash[] = {10, 2};<br />
BasicStroke pen9 = new BasicStroke(2.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_MITER,<br />
1,<br />
dash,0);<br />
g2d.setStroke(pen9);<br />
g2d.draw(new Rectangle2D.Float(10f,180f,50f,50f));<br />
BasicStroke pen10 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
260 pr43100<br />
293
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
BasicStroke.JOIN_ROUND);<br />
g2d.setStroke(pen10);<br />
g2d.draw(new Rectangle2D.Float(10f,250f,60f,70f));<br />
BasicStroke pen11 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_BEVEL);<br />
g2d.setStroke(pen11);<br />
g2d.draw(new Rectangle2D.Float(90f,250f,60f,70f));<br />
BasicStroke pen12 = new BasicStroke(10.0f,BasicStroke.CAP_BUTT,<br />
BasicStroke.JOIN_MITER);<br />
g2d.setStroke(pen11);<br />
g2d.draw(new Rectangle2D.Float(170f,250f,60f,70f));<br />
}<br />
}<br />
Abb.<br />
294
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.3.3 Koord<strong>in</strong>atensysteme und Transformation<br />
Das <strong>Java</strong> 2D-API unterschei<strong>de</strong>t zwischen<br />
- <strong>de</strong>m user coord<strong>in</strong>ate space (Koord<strong>in</strong>atenraum <strong>de</strong>s Benutzers)<br />
und<br />
- <strong>de</strong>m <strong>de</strong>vice coord<strong>in</strong>ate space (Koord<strong>in</strong>atensystem <strong>de</strong>s Ausgabegeräts)<br />
Zu <strong>de</strong>n möglichen Transformationen gehören<br />
- die Drehung (rotate(), setToRotation())<br />
- die Skalierung (scale(), setToScale())<br />
- die Verschiebung (translate(), setToTranslation())<br />
- die Verzerrung (shear(), setToShear())<br />
Das folgen<strong>de</strong> Beispiel 261 zeigt e<strong>in</strong> Rechteck, das zunächst im Ursprung <strong>de</strong>s<br />
Koord<strong>in</strong>atensystems (L<strong>in</strong>ke obere Ecke) gezeichnet wird. Anschließend wird <strong>de</strong>r<br />
Koord<strong>in</strong>atenraum durch sukzessive Anwendung von Transformationen<br />
- verschoben<br />
- verschoben und gedreht<br />
- verschoben, gedreht und skaliert<br />
- verschoben, gedreht, skaliert und verzerrt<br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.geom.*;<br />
public class TransformBsp extends JPanel<br />
{<br />
public void pa<strong>in</strong>tComponent(Graphics g)<br />
{<br />
clear(g);<br />
Graphics2D g2d = (Graphics2D) g;<br />
Rectangle e<strong>in</strong>Rechteck =<br />
new Rectangle(getInsets().left,<br />
getInsets().top,50,50);<br />
g2d.draw(e<strong>in</strong>Rechteck);<br />
// neues Transformationsmo<strong>de</strong>ll erzeugen<br />
Aff<strong>in</strong>eTransform dieTransformation = new Aff<strong>in</strong>eTransform();<br />
// Koord<strong>in</strong>atenraum um 50 x-, 50 y-E<strong>in</strong>heiten verschieben<br />
dieTransformation.translate(50.0,50.0);<br />
g2d.transform(dieTransformation);<br />
g2d.setColor(Color.lightGray);<br />
g2d.fill(e<strong>in</strong>Rechteck);<br />
// Koord<strong>in</strong>atenraum um 30 Grad gegen <strong>de</strong>r Uhrzeigers<strong>in</strong>n drehen<br />
dieTransformation.rotate(-Math.PI/12.0);<br />
g2d.transform(dieTransformation);<br />
g2d.setColor(g2d.getColor().darker());<br />
g2d.fill(e<strong>in</strong>Rechteck);<br />
// Koord<strong>in</strong>atenraum um die Faktoren 1.33 * x, 0.66 * y skalieren<br />
dieTransformation.scale(1.33f,0.66f);<br />
g2d.transform(dieTransformation);<br />
g2d.setColor(Color.black);<br />
g2d.fill(e<strong>in</strong>Rechteck);<br />
// Koord<strong>in</strong>atensystem um die Faktoren 0.1 * x, 0.1 * y verzerren<br />
261 vgl. pr43100<br />
295
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
dieTransformation.shear(0.1f,0.1f);<br />
g2d.transform(dieTransformation);<br />
g2d.setColor(Color.black);<br />
g2d.fill(e<strong>in</strong>Rechteck);<br />
}<br />
protected void clear(Graphics g)<br />
{<br />
super.pa<strong>in</strong>tComponent(g);<br />
// loescht die Pixelmap <strong>de</strong>s Bildschirms<br />
// per Default gibt es Double Buffer<strong>in</strong>g<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
TransformBsp tbsp = new TransformBsp();<br />
Str<strong>in</strong>g titel = tbsp.getClass().toStr<strong>in</strong>g();<br />
if (titel.<strong>in</strong><strong>de</strong>xOf("class") != -1)<br />
titel = titel.substr<strong>in</strong>g(6);<br />
JFrame frame = new JFrame(titel);<br />
frame.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 />
frame.getContentPane().add(tbsp,Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setSize(380,250);<br />
frame.setVisible(true);<br />
}<br />
}<br />
Abb.: Transformation e<strong>in</strong>es Rechtecks.<br />
Nach je<strong>de</strong>r Transformation wird das Rechteck neu gezeichnet.<br />
Aff<strong>in</strong>e Transformationen. Sie können durch e<strong>in</strong>fache Transformationsmatrizen<br />
beschrieben wer<strong>de</strong>n, z.B. Translation e<strong>in</strong>es Punktes (x,y) um (dx,dy):<br />
⎛1<br />
⎜<br />
⎜0<br />
⎜<br />
⎝0<br />
0<br />
1<br />
0<br />
dx⎞<br />
⎛ x⎞<br />
⎛ x + dx ⎞<br />
⎟ ⎜ ⎟ ⎜ ⎟<br />
dy⎟<br />
⋅ ⎜ y⎟<br />
= ⎜ y + dy⎟<br />
1 ⎟ ⎜ ⎟ ⎜ ⎟<br />
⎠ ⎝ 1⎠<br />
⎝ 1 ⎠<br />
296
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp. 262 : Das Haus <strong>de</strong>s Nikolaus.<br />
Gegeben ist die folgen<strong>de</strong> pa<strong>in</strong>t()- Metho<strong>de</strong><br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2d = (Graphics2D) g;<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form (Verwen<strong>de</strong> Even-Odd-Regel)<br />
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);<br />
path.moveTo(-25,50);<br />
path.l<strong>in</strong>eTo(-25.0f,0.0f); path.l<strong>in</strong>eTo(0.0f,-30.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(-25.0f,0.0f);<br />
path.l<strong>in</strong>eTo(25.0f,50.0f); path.l<strong>in</strong>eTo(-25.0f,50.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(25.0f,50.0f);<br />
path.closePath();<br />
// Schliessen<br />
g2d.draw(path);<br />
}<br />
Die Implementierung dieser pa<strong>in</strong>t()-Metho<strong>de</strong> zeigt das folgen<strong>de</strong> Fenster an:<br />
E<strong>in</strong>e Translation um (100,100) führt zu <strong>de</strong>m folgen<strong>de</strong>n Fenster:<br />
Diese Form wur<strong>de</strong> durch Implementieren <strong>de</strong>r folgen<strong>de</strong> pa<strong>in</strong>t()-Metho<strong>de</strong> erreicht:<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2d = (Graphics2D) g;<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form (Verwen<strong>de</strong> Even-Odd-Regel)<br />
262 pr43100<br />
297
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);<br />
path.moveTo(-25,50);<br />
path.l<strong>in</strong>eTo(-25.0f,0.0f); path.l<strong>in</strong>eTo(0.0f,-30.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(-25.0f,0.0f);<br />
path.l<strong>in</strong>eTo(25.0f,50.0f); path.l<strong>in</strong>eTo(-25.0f,50.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(25.0f,50.0f);<br />
path.closePath();<br />
// Schliessen<br />
// Transformation<br />
Aff<strong>in</strong>eTransform at = new Aff<strong>in</strong>eTransform();<br />
at.setToTranslation(100.0f,100.0f);<br />
g2d.transform(at);<br />
g2d.draw(path);<br />
}<br />
Zusätzlich zur Translation soll das Haus noch um 45 Grad im Uhrzeigers<strong>in</strong>n gedreht wer<strong>de</strong>n. Dabei<br />
muß unterschie<strong>de</strong>n wer<strong>de</strong>n zwischen <strong>de</strong>m Setzen e<strong>in</strong>er e<strong>in</strong>er Aff<strong>in</strong>en Transformation und <strong>de</strong>m<br />
Erweitern e<strong>in</strong>er Aff<strong>in</strong>en Transformation.<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2d = (Graphics2D) g;<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form (Verwen<strong>de</strong> Even-Odd-Regel)<br />
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);<br />
path.moveTo(-25,50);<br />
path.l<strong>in</strong>eTo(-25.0f,0.0f); path.l<strong>in</strong>eTo(0.0f,-30.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(-25.0f,0.0f);<br />
path.l<strong>in</strong>eTo(25.0f,50.0f); path.l<strong>in</strong>eTo(-25.0f,50.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(25.0f,50.0f);<br />
path.closePath();<br />
// Schliessen<br />
// Transformation<br />
Aff<strong>in</strong>eTransform at = new Aff<strong>in</strong>eTransform();<br />
// Setzen <strong>de</strong>r aff<strong>in</strong>en Transformation<br />
at.setToTranslation(100.0f,100.0f);<br />
// Erweitern <strong>de</strong>r aff<strong>in</strong>en Transformation<br />
at.rotate(Math.PI/4);<br />
g2d.transform(at);<br />
g2d.draw(path);<br />
}<br />
Die Geometrie vom Haus <strong>de</strong>s Nikolaus soll vergrößert wer<strong>de</strong>n.<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
Graphics2D g2d = (Graphics2D) g;<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form (Verwen<strong>de</strong> Even-Odd-Regel)<br />
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);<br />
298
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
path.moveTo(-25,50);<br />
path.l<strong>in</strong>eTo(-25.0f,0.0f); path.l<strong>in</strong>eTo(0.0f,-30.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(-25.0f,0.0f);<br />
path.l<strong>in</strong>eTo(25.0f,50.0f); path.l<strong>in</strong>eTo(-25.0f,50.0f);<br />
path.l<strong>in</strong>eTo(25.0f,0.0f); path.l<strong>in</strong>eTo(25.0f,50.0f);<br />
path.closePath();<br />
// Schliessen<br />
// Transformation<br />
Aff<strong>in</strong>eTransform at = new Aff<strong>in</strong>eTransform();<br />
// Setzen <strong>de</strong>r aff<strong>in</strong>en Transformation<br />
at.setToTranslation(100.0f,100.0f);<br />
// Erweitern <strong>de</strong>r aff<strong>in</strong>en Transformation<br />
at.rotate(Math.PI/4);<br />
// Skalieren<br />
at.scale(1.5f,1.5f);<br />
g2d.transform(at);<br />
// Zeichnen<br />
g2d.draw(path);<br />
}<br />
Das Fenster zeigt: Die Skalierung <strong>in</strong> <strong>Java</strong>2D bee<strong>in</strong>flusst auch die Stroke- und Pa<strong>in</strong>t-Eigenschaften,<br />
d.h. bei e<strong>in</strong>er Vergrößerung wird auch die L<strong>in</strong>iendicke größer.<br />
Die vollständige Transformation kann durch dir folgen<strong>de</strong>Transformationsmatrix beschrieben wer<strong>de</strong>n<br />
(Kompostion von Transformationen):<br />
⎛1<br />
⎜<br />
⎜0<br />
⎜<br />
⎝0<br />
0<br />
1<br />
0<br />
dx⎞<br />
⎛cosα<br />
⎟ ⎜<br />
dy⎟<br />
⋅ ⎜ 0<br />
1 ⎟ ⎜<br />
⎠ ⎝ 0<br />
0<br />
s<strong>in</strong>α<br />
0<br />
0⎞<br />
⎛ sx<br />
⎟ ⎜<br />
0⎟<br />
⋅ ⎜ 0<br />
1⎟<br />
⎜<br />
⎠ ⎝ 0<br />
0<br />
sy<br />
0<br />
0⎞<br />
⎟<br />
0⎟<br />
⋅ geom _ objekt<br />
1⎟<br />
⎠<br />
299
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.3.4 <strong>Java</strong>2D-Pipel<strong>in</strong>e<br />
<strong>Java</strong>2D stellt geometische Objekte über e<strong>in</strong>e "Ren<strong>de</strong>r-"Pipel<strong>in</strong>e dar:<br />
fill()<br />
Transformation<br />
Shapes draw() Stroke<br />
Text drawStr() Font<br />
H<strong>in</strong>ts<br />
Rasterisierer<br />
Images drawImage() Ren<strong>de</strong>r<strong>in</strong>g H<strong>in</strong>ts<br />
Clipp<strong>in</strong>g Pa<strong>in</strong>t Composition Output Device<br />
Abb.: <strong>Java</strong>2D-Pipel<strong>in</strong>e<br />
Geometrische Objekte können neben ihrer Form (Shape, z.B. Rechteck) durch drei<br />
weitere Parameter beschrieben wer<strong>de</strong>n: Translation, Rotation, Skalierung. Die<br />
Anwendung dieser Parameter auf e<strong>in</strong> geometrisches Objekt wird als Transformation<br />
bezeichnet.<br />
Kont<strong>in</strong>uierliche Shapes wer<strong>de</strong>n vom Rasterisierer <strong>in</strong> diskrete Rasterbelegungen<br />
umgewan<strong>de</strong>lt. Man unterschei<strong>de</strong>t Rasterisierung mit o<strong>de</strong>r ohne Alias<strong>in</strong>g:<br />
- Alias<strong>in</strong>g: Raster-Pixel wird als belegt gekennzeichnet, wenn das Objekt meht als x% <strong>de</strong>s Pixels<br />
belegt<br />
- Antialias<strong>in</strong>g: <strong>de</strong>m Pixel wird <strong>de</strong>r Belegungsfaktor x zugewiesen und als Transparenzwert <strong>in</strong>terpretiert.<br />
Ren<strong>de</strong>r<strong>in</strong>g H<strong>in</strong>ts s<strong>in</strong>d H<strong>in</strong>weise o<strong>de</strong>r Wünsche an <strong>Java</strong>2D, welche Qualität bzw.<br />
welche Performance man gerne erreichen wür<strong>de</strong>. <strong>Java</strong>2D entschei<strong>de</strong>t dann selber,<br />
welche dieser Wünsche erfüllt wer<strong>de</strong>n (können).<br />
Die Ausgabe von <strong>Java</strong>2D erfolgt typischerweise <strong>in</strong> e<strong>in</strong> Fenster. Dieses Fenster zeigt<br />
nur e<strong>in</strong>en Ausschnitt <strong>de</strong>r potentiell unbegrenzten (virtuellen) <strong>Java</strong>2D-Zeichenfläche.<br />
Gemalt wer<strong>de</strong>n soll natürlich nur das, was auch tatsächlich <strong>in</strong> diesem sichtbaren<br />
Ausschnitt liegt. Dieses Zuschnei<strong>de</strong>n auf e<strong>in</strong>en Bereich wird als Clipp<strong>in</strong>g bezeichnet.<br />
<strong>Java</strong>2D erlaubt neben <strong>de</strong>m normalen Clipp<strong>in</strong>g auf e<strong>in</strong>em rechteckigen (Fenster-)<br />
Bereich auch das Clipp<strong>in</strong>g auf beliebige <strong>Java</strong>2D-Flächen.<br />
Im Pa<strong>in</strong>t-Schritt wer<strong>de</strong>n Farbe und Transparenz <strong>de</strong>r Pixel festgelegt. Dazu gehört<br />
u.a.:<br />
- die Ausprägung <strong>de</strong>r Umrissl<strong>in</strong>ie (durchgehend, gestrichelt, …)<br />
- die Art <strong>de</strong>r Füllung (feste Farbe, Farbverlauf, Muster, Bitmap, …)<br />
Falls e<strong>in</strong> Image gemalt wer<strong>de</strong>n soll, entfällt dieser Schritt, da alle Informationen<br />
implizit im Image enthalten s<strong>in</strong>d.<br />
300
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
<strong>Java</strong>2D erweitert das H<strong>in</strong>zufügen von Objekten um sog. Kompostionsregeln<br />
(bekannt als Porter-Duff-Regeln). Neben <strong>de</strong>r Porter-Duff-Komposition, die e<strong>in</strong><br />
Source-Objekt mit <strong>de</strong>r gesamten Zeichenfläche verknüpft, gibt es noch die sog.<br />
CAG-Komposition (Constructive Area Geometry). CAG verknüpft jeweils 2 (CAG-)<br />
Objekte zu e<strong>in</strong>em neuen CAG-Objekt.<br />
4.3.5 Farbmanagement unter <strong>Java</strong> 2D<br />
Die Klasse Color mit <strong>de</strong>m Interface Pa<strong>in</strong>t<br />
E<strong>in</strong> Objekt <strong>de</strong>r Klasse Color stellt e<strong>in</strong>e Farbe im RGB-Farbschema dar. Color<br />
implementiert das neue Interface Pa<strong>in</strong>t (Zeichenfarbe).<br />
><br />
Pa<strong>in</strong>t<br />
public static Color black;<br />
public static Color blue;<br />
public static Color cyan;<br />
…<br />
public static Color white;<br />
public static Color yellow;<br />
Color GradientPa<strong>in</strong>t TexturePa<strong>in</strong>t<br />
><br />
public Color(float r, float g, float b)<br />
public Color(<strong>in</strong>t rgb)<br />
public Color(<strong>in</strong>t rgba,boolean hasalppha)<br />
public Color(<strong>in</strong>t r,<strong>in</strong>t g,<strong>in</strong>t b)<br />
public Color(<strong>in</strong>t r,<strong>in</strong>tg,<strong>in</strong>t b,<strong>in</strong>t a)<br />
><br />
public Color brighter()<br />
public Color darker()<br />
public boolean equals()<br />
public <strong>in</strong>t getAlpha()<br />
public <strong>in</strong>t getBlue()<br />
…<br />
public static Color getColor(Str<strong>in</strong>g nm)<br />
public static getHSBColor(float h,float s,<br />
float b)<br />
public <strong>in</strong>t getRGB()<br />
public <strong>in</strong>t getTransparency()<br />
public static <strong>in</strong>t HSBtoRGB(float hue,<br />
float saturation,float brightness)<br />
public static float RGBtoHSB(<strong>in</strong>t r,<strong>in</strong>t g,<strong>in</strong>t b,<br />
float[] hsbwerte)<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
301
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Die Klasse Color<br />
Farbübergänge<br />
<strong>Java</strong> 2D erlaubt die Verwendung von Farbübergängen (Gradienten) und Mustern zur<br />
Füllung beliebiger Formen. Dazu existieren zwei Klassen, die die Schnittstelle Pa<strong>in</strong>t<br />
implementieren:<br />
- GradientPa<strong>in</strong>t (repäsentiert e<strong>in</strong>en glatten Übergang von e<strong>in</strong>er Farbe zu e<strong>in</strong>er an<strong>de</strong>ren)<br />
- TexturePa<strong>in</strong>t für Füllmuster auf <strong>de</strong>r Basis e<strong>in</strong>er Bilddatei, die das Muster vorgibt.<br />
public class GradientPa<strong>in</strong>t extends Object implements Pa<strong>in</strong>t<br />
Konstruktoren.<br />
public GradientPa<strong>in</strong>t(float x1,float y1,Color c1,float x2,float y2,Color c2)<br />
public GradientPa<strong>in</strong>t(float x1,float y1,Color c1,float x2,float y2,<br />
Color c2,boolean cyclic)<br />
// c1 ist die Farbe am ersten Punkt(x1,y1), c2 ist die Farbe am zweiten Punkt (x2,y2). cyclic ist true,<br />
// falls <strong>de</strong>r Übergang zwischen <strong>de</strong>n Farben wie<strong>de</strong>rholt wer<strong>de</strong>n soll<br />
Der aktuelle Gradient wird über setPa<strong>in</strong>t() <strong>de</strong>s Graphics2D-Kontextes gesetzt.<br />
Bsp. 263 : E<strong>in</strong> Kreis wird mit e<strong>in</strong>em Farbübergang ausgestattet.<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.geom.*;<br />
public class GradientPa<strong>in</strong>tBsp extends JPanel<br />
{<br />
private Ellipse2D.Double kreis<br />
= new Ellipse2D.Double(10,10,350,350);<br />
private GradientPa<strong>in</strong>t gradient<br />
= new GradientPa<strong>in</strong>t(0,0,Color.red,175,175,Color.yellow,true);<br />
public void pa<strong>in</strong>tComponent(Graphics g)<br />
{<br />
clear(g);<br />
Graphics2D g2d = (Graphics2D) g;<br />
g2d.setPa<strong>in</strong>t(gradient);<br />
g2d.fill(getCircle());<br />
g2d.setPa<strong>in</strong>t(Color.black);<br />
g2d.draw(getCircle());<br />
}<br />
protected void clear(Graphics g)<br />
{<br />
super.pa<strong>in</strong>tComponent(g);<br />
// loescht die Pixelmap <strong>de</strong>s Bildschirms<br />
// per Default gibt es Double Buffer<strong>in</strong>g<br />
}<br />
protected Ellipse2D.Double getCircle()<br />
{<br />
return (kreis);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
GradientPa<strong>in</strong>tBsp gbsp = new GradientPa<strong>in</strong>tBsp();<br />
Str<strong>in</strong>g titel = gbsp.getClass().toStr<strong>in</strong>g();<br />
if (titel.<strong>in</strong><strong>de</strong>xOf("class") != -1)<br />
263 pr43100<br />
302
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
titel = titel.substr<strong>in</strong>g(6);<br />
JFrame frame = new JFrame(titel);<br />
frame.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 />
frame.getContentPane().add(gbsp,Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setSize(380,400);<br />
frame.setVisible(true);<br />
}<br />
}<br />
Abb.: Ausstatten e<strong>in</strong>er Form mit e<strong>in</strong>em Farbgradienten<br />
public class TexturePa<strong>in</strong>t extends Object implements Pa<strong>in</strong>t<br />
Konstruktor.<br />
public TexturePa<strong>in</strong>t(BufferedImage texture,Rectangle2D anchor)<br />
// e<strong>in</strong> Bild wird über e<strong>in</strong>e Form ge<strong>de</strong>ckt.<br />
Metho<strong>de</strong>n.<br />
public Pa<strong>in</strong>tContext createContext(ColorMo<strong>de</strong>l cm, Rectangle <strong>de</strong>viceBounds,<br />
Rectangle2D userBounds, Aff<strong>in</strong>eTransform xForm, Ren<strong>de</strong>r<strong>in</strong>g h<strong>in</strong>ts)<br />
public BufferedImage getImage()<br />
public <strong>in</strong>t getTransparency()<br />
Bsp. 264 : E<strong>in</strong> Kreis wird mit e<strong>in</strong>em Füllmuster abge<strong>de</strong>ckt.<br />
264 pr43100<br />
303
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import java.awt.geom.*;<br />
import java.awt.image.*;<br />
public class TexturePa<strong>in</strong>tBsp extends JPanel<br />
{<br />
private Ellipse2D.Double kreis<br />
= new Ellipse2D.Double(10,10,350,350);<br />
public void pa<strong>in</strong>tComponent(Graphics g)<br />
{<br />
clear(g);<br />
Graphics2D g2d = (Graphics2D) g;<br />
// g2d.fill(kreis);<br />
// g2d.draw(quadrat);<br />
BufferedImage buffImage =<br />
new BufferedImage(10,10,BufferedImage.TYPE_INT_RGB);<br />
Graphics2D gg = buffImage.createGraphics();<br />
gg.setColor(Color.yellow);<br />
gg.fillRect(0,0,10,10);<br />
gg.setColor( Color.black ); // draw <strong>in</strong> black<br />
gg.drawRect(1,1,6,6); // draw a rectangle<br />
gg.setColor(Color.blue ); // draw <strong>in</strong> blue<br />
gg.fillRect(1,1,3,3); // draw a filled rectangle<br />
gg.setColor(Color.red ); // draw <strong>in</strong> red<br />
gg.fillRect(4,4,3,3); // draw a filled rectangle<br />
g2d.fill(<br />
new RoundRectangle2D.Double(<br />
155, 30, 75, 100, 50, 50 ));<br />
// pa<strong>in</strong>t buffImage onto the Frame<br />
g2d.setPa<strong>in</strong>t(new TexturePa<strong>in</strong>t(buffImage, new Rectangle(10,10)));<br />
g2d.fill(getCircle());<br />
g2d.setPa<strong>in</strong>t(Color.black);<br />
g2d.draw(getCircle());<br />
}<br />
protected void clear(Graphics g)<br />
{<br />
super.pa<strong>in</strong>tComponent(g);<br />
// loescht die Pixelmap <strong>de</strong>s Bildschirms<br />
// per Default gibt es Double Buffer<strong>in</strong>g<br />
}<br />
protected Ellipse2D.Double getCircle()<br />
{<br />
return (kreis);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
TexturePa<strong>in</strong>tBsp tbsp = new TexturePa<strong>in</strong>tBsp();<br />
Str<strong>in</strong>g titel = tbsp.getClass().toStr<strong>in</strong>g();<br />
if (titel.<strong>in</strong><strong>de</strong>xOf("class") != -1)<br />
titel = titel.substr<strong>in</strong>g(6);<br />
JFrame frame = new JFrame(titel);<br />
frame.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 />
frame.getContentPane().add(tbsp,Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setSize(380,400);<br />
frame.setVisible(true);<br />
}<br />
}<br />
304
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Füllen e<strong>in</strong>er Form mit e<strong>in</strong>em Füllmuster aus e<strong>in</strong>er Bilddatei<br />
Transparentes Zeichnen mit Hilfe <strong>de</strong>r Klasse AlphaComposite<br />
Für je<strong>de</strong> geometrische Form kann e<strong>in</strong> Transparenzwert ("Alphakanal") angegeben<br />
wer<strong>de</strong>n, <strong>de</strong>r angibt, wie stark "<strong>de</strong>ckend" gezeichnet wer<strong>de</strong>n soll. Dazu <strong>in</strong>stanziert<br />
man e<strong>in</strong> Objekt von AlphaComposite und setzt <strong>de</strong>n entsprechen<strong>de</strong>n<br />
Zeichenparameter mit <strong>de</strong>r Metho<strong>de</strong> setComposite() <strong>de</strong>s Graphics2D-Kontextes.<br />
Bsp. 265 : E<strong>in</strong> rotes, halbtransparentes Rechteck liegt über e<strong>in</strong>em Muster.<br />
import java.awt.*;<br />
import java.applet.*;<br />
import java.awt.geom.*;<br />
public class PolyTransp extends Applet<br />
{<br />
public void pa<strong>in</strong>t(Graphics g)<br />
{<br />
// Erzeuegen e<strong>in</strong>es Graphics2D-Objekt<br />
Graphics2D g2d = (Graphics2D) g;<br />
g2d.setColor(Color.blue);<br />
// Def<strong>in</strong>ition <strong>de</strong>r Form<br />
GeneralPath e<strong>in</strong>Pfad = new GeneralPath();<br />
// Startpunkt festlegen (Ursprung <strong>de</strong>r sichtbaren<br />
// Zeichenflaeche <strong>de</strong>s Fensters<br />
e<strong>in</strong>Pfad.moveTo(getInsets().left,getInsets().top);<br />
for (<strong>in</strong>t i = 1, j = 10;i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
// <strong>de</strong>r Pfad wird geschlossen<br />
e<strong>in</strong>Pfad.closePath();<br />
// Zeichnen (blau) <strong>de</strong>s Umrisses vom PfadObjekt<br />
g2d.setColor(Color.blue);<br />
g2d.draw(e<strong>in</strong>Pfad);<br />
// neues Gradientenobjekt<br />
GradientPa<strong>in</strong>t <strong>de</strong>rFarbGradient =<br />
new GradientPa<strong>in</strong>t(getInsets().left,<br />
// Startpunkt<br />
getInsets().top,<br />
// Gradient<br />
new Color(255,255,255), // Farbe<br />
getSize().width,<br />
// Endpunkt<br />
getSize().height,<br />
// Gradient<br />
new Color(0,0,0));<br />
// Endfarbe<br />
// Gradient festlegen<br />
g2d.setPa<strong>in</strong>t(<strong>de</strong>rFarbGradient);<br />
// Pfad fuellen<br />
g2d.fill(e<strong>in</strong>Pfad);<br />
// Farbe festlegen (verdraengt <strong>de</strong>n Gradienten)<br />
g2d.setColor(Color.red);<br />
// Instanz e<strong>in</strong>es Alphakanals la<strong>de</strong>n (Wert: 50 Prozent = 0.5)<br />
AlphaComposite transparenzModus =<br />
AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f);<br />
// Transparenzwert festlegen<br />
g2d.setComposite(transparenzModus);<br />
// Zeichnen e<strong>in</strong>es Rechtecks (50 Pixel Rand an allen Seiten)<br />
g2d.fillRect(getInsets().left + 50,<br />
getInsets().top + 50,<br />
getSize().width - getInsets().right - 100,<br />
getSize().height - getInsets().bottom - 100);<br />
// g2d.setColor(Color.red);<br />
// g2d.fill(e<strong>in</strong>Pfad);<br />
}<br />
}<br />
Abb.: Transparente Überlagerung von Formen<br />
Wenn zwei e<strong>in</strong>an<strong>de</strong>r überlappen<strong>de</strong> Formen dargestellt wer<strong>de</strong>n sollen, muß geklärt<br />
wer<strong>de</strong>n, wie die Objekte sich zue<strong>in</strong>an<strong>de</strong>r verhalten sollen. Hierzu gibt es die<br />
Composite- und CompositeContext-Interfaces. E<strong>in</strong>e Implementierung dazu ist<br />
die AlphaComposite-Klasse, <strong>in</strong> <strong>de</strong>r die SRC_OVER-Regel die meistgenutzte ist.<br />
306
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
4.3.6 Text und Fonts unter <strong>Java</strong>2D<br />
Character, Glyphs 266 und Fonts<br />
E<strong>in</strong> Str<strong>in</strong>g lässt sich auf <strong>de</strong>r Ebene <strong>de</strong>r e<strong>in</strong>zelnen Zeichen auf vielfältige Art und<br />
Weise manipulieren, z.B. durch<br />
- verschie<strong>de</strong>ne Formatierungen<br />
- Ausrichtung<br />
- Position<br />
- Schriftart<br />
- Metrik<br />
- Größe<br />
- Umrisse<br />
Je<strong>de</strong>s Font-Objekt umfasst diese Attribute, die direkt über von <strong>de</strong>r Font-Klasse zur<br />
Verfügung gestellte Metho<strong>de</strong>n ansprechbar s<strong>in</strong>d.<br />
<strong>Java</strong>2D enthält e<strong>in</strong>e erweiterte Font-Klasse. die erheblich weitgehen<strong>de</strong>re<br />
Möglichkeiten zur Kontrolle von Schriftarten bereitstellt.<br />
Bsp. 267 : Das folgen<strong>de</strong> Programm listet die von <strong>Java</strong>2D bereitgestellten Fonts auf.<br />
import java.awt.*;<br />
/** Lists the names of all available fonts. */<br />
public class ListFonts<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
GraphicsEnvironment env =<br />
GraphicsEnvironment.getLocalGraphicsEnvironment();<br />
Str<strong>in</strong>g[] fontNames = env.getAvailableFontFamilyNames();<br />
System.out.pr<strong>in</strong>tln("Available Fonts:");<br />
for(<strong>in</strong>t i = 0; i < fontNames.length; i++)<br />
System.out.pr<strong>in</strong>tln(" " + fontNames[i]);<br />
}<br />
}<br />
Transformations- und Zeichentechnik<br />
Die Transformations- und Zeichentechnik von <strong>Java</strong>2D kann auch auf Textstr<strong>in</strong>gs<br />
angewen<strong>de</strong>t wer<strong>de</strong>n.<br />
Bsp. 268 : Rotation e<strong>in</strong>es Textstr<strong>in</strong>gs<br />
import java.awt.*;<br />
import java.awt.geom.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class RotationBsp extends JPanel<br />
{<br />
private Ellipse2D.Double kreis<br />
= new Ellipse2D.Double(10,10,350,350);<br />
private GradientPa<strong>in</strong>t gradient<br />
= new GradientPa<strong>in</strong>t(0,0,Color.red,175,175,Color.yellow,true);<br />
private Color[] farben = { Color.white, Color.black };<br />
public RotationBsp()<br />
266 Die Vere<strong>in</strong>igung von <strong>de</strong>m Zeichen selbst und se<strong>in</strong>em exakten Aussehen wird Glyph genannt<br />
267 pr43100<br />
268 pr43100<br />
307
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
GraphicsEnvironment env =<br />
GraphicsEnvironment.getLocalGraphicsEnvironment();<br />
env.getAvailableFontFamilyNames();<br />
setFont(new Font("Book Antiqua", Font.PLAIN, 90));<br />
}<br />
protected void clear(Graphics g)<br />
{<br />
super.pa<strong>in</strong>tComponent(g);<br />
// loescht die Pixelmap <strong>de</strong>s Bildschirms<br />
// per Default gibt es Double Buffer<strong>in</strong>g<br />
}<br />
protected Ellipse2D.Double getCircle()<br />
{<br />
return (kreis);<br />
}<br />
public void pa<strong>in</strong>tComponent(Graphics g)<br />
{<br />
clear(g);<br />
Graphics2D g2d = (Graphics2D) g;<br />
g2d.setPa<strong>in</strong>t(gradient);<br />
g2d.fill(getCircle());<br />
g2d.setPa<strong>in</strong>t(Color.black);<br />
g2d.draw(getCircle());<br />
g2d.translate(185.0,185.0);<br />
for (<strong>in</strong>t i = 0; i < 16; i++)<br />
{<br />
g2d.rotate(Math.PI/8.0);<br />
g2d.setPa<strong>in</strong>t(farben[i%2]);<br />
g2d.drawStr<strong>in</strong>g("<strong>Java</strong>",0,0);<br />
}<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
RotationBsp rotationBsp = new RotationBsp();<br />
Str<strong>in</strong>g titel = rotationBsp.getClass().toStr<strong>in</strong>g();<br />
if (titel.<strong>in</strong><strong>de</strong>xOf("class") != -1)<br />
titel = titel.substr<strong>in</strong>g(6);<br />
JFrame frame = new JFrame(titel);<br />
frame.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 />
frame.getContentPane().add(rotationBsp,Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setSize(380,400);<br />
frame.setVisible(true);<br />
}<br />
}<br />
308
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.:<br />
4.3.7 2D Bildverarbeitung<br />
Zeichnen e<strong>in</strong>es Bilds.<br />
Mit Hilfe <strong>de</strong>r Graphics2d-Metho<strong>de</strong><br />
public boolean drawImage(BufferedImage image, BufferedImageOp filter,<br />
<strong>in</strong>t left, <strong>in</strong>t top)<br />
kann e<strong>in</strong> BufferedImage ab <strong>de</strong>r oberen l<strong>in</strong>ken Ecke (left,top) gezeichnet<br />
wer<strong>de</strong>n.<br />
Erstellen e<strong>in</strong>es BufferedImage aus e<strong>in</strong>em Image-File.<br />
public static BufferedImage getBufferedImage(Str<strong>in</strong>g imageFile, Component c)<br />
{<br />
Image image = c.getToolkit().getImage(imageFile);<br />
MediaTracker tracker = new MediaTracker(c); // nutzt MediaTracker<br />
tracker.addImage(image,0);<br />
try {<br />
tracker.waitForAll();<br />
}<br />
catch (InterruptedException ie) { }<br />
BufferedImage bufferedImage = new BufferedImage(image.getWidth(c),<br />
image.getHeight(c),BufferedImage.TYPE_INT_RGB);<br />
Graphics2D g2d = bufferedImage.createGraphics();<br />
g2d.drawImage(image,0,0,c);<br />
return bufferedImage);<br />
}<br />
309
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
BufferedImage-Objekte<br />
E<strong>in</strong> BufferedImage-Objekt besteht aus e<strong>in</strong>em Raster-Objekt und e<strong>in</strong>em ColorMo<strong>de</strong>l-<br />
Objekt.<br />
Der Raster kümmert sich um die Bildverwaltung, wobei <strong>de</strong>r DataBuffer die Bilddaten<br />
enthält und das SampleMo<strong>de</strong>l angibt, wie die Bilddaten zu <strong>in</strong>terpretien s<strong>in</strong>d.<br />
Das ColorMo<strong>de</strong>l gibt an, wie die Pixeldaten <strong>in</strong> Bezug auf ihre Farben ausgewertet<br />
wer<strong>de</strong>n sollen. E<strong>in</strong> BufferedImage kann als OffScreen-Puffer dienen. Damit kann<br />
man das Objekt schon im Speicher ren<strong>de</strong>rn, bevor man das Bild o<strong>de</strong>r nur <strong>de</strong>n<br />
benötigten Ausschnitt auf <strong>de</strong>n Bildschirm kopiert.<br />
4.3.8 Animationen mit <strong>Java</strong>2D<br />
Man kann mit <strong>Java</strong>2D e<strong>in</strong>fache Animationen erstellen, z.B.:<br />
310
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5. AWT<br />
5.1 Bestandteile <strong>de</strong>s AWT<br />
In <strong>Java</strong> wird die Kommunikation mit <strong>de</strong>m Anwen<strong>de</strong>r hauptsächlich über e<strong>in</strong> eigenes<br />
Konzept realisiert – <strong>de</strong>m Abstract W<strong>in</strong>dow<strong>in</strong>g Toolkit. Das AWT besitzt zur<br />
Kommunikation mit <strong>de</strong>m Anwen<strong>de</strong>r e<strong>in</strong> Application Programm<strong>in</strong>g Interface (API).<br />
Darüber können allgeme<strong>in</strong>e Komponenten <strong>de</strong>r Benutzeroberfläche, z.B.<br />
Schaltflächen o<strong>de</strong>r Menüs, plattformunabhängig genutzt wer<strong>de</strong>n.<br />
5.2 Die AWT-Komponenten<br />
Die AWT stellt Komponenten für <strong>de</strong>n Anwen<strong>de</strong>r bereit. Die von Anfang an<br />
vorhan<strong>de</strong>nen Komponenten 269 <strong>de</strong>s AWT s<strong>in</strong>d: Schaltflächen (Buttons), Labels,<br />
Kontrollkästchen (Checkbuttons), Optionsfel<strong>de</strong>r (Radiobuttons), Listen,<br />
Auswahlfel<strong>de</strong>r, Textfel<strong>de</strong>r, 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 <strong>de</strong>r AWT s<strong>in</strong>d Layout-Manager. E<strong>in</strong> Layout-Manager ist <strong>in</strong><br />
je<strong>de</strong>m Conta<strong>in</strong>er enthalten. Er f<strong>in</strong><strong>de</strong>t – angepaßt an die jeweilige Situation –<br />
automatisch heraus, an welche Stelle die Komponenten am besten passen. Der AWT<br />
stellt 5 verschie<strong>de</strong>ne Typen von Layout-Managern zur Verfügung: Flow-, Bor<strong>de</strong>r-,<br />
Grid-, Gridbag-Layout.<br />
Schließlich stellt AWT die Mittel zur Reaktion auf Ereignisse zur Verfügung, die vom<br />
Anwen<strong>de</strong>r über Komponenten ausgelöst wer<strong>de</strong>n können.<br />
Die Wurzel fast aller AWT-Komponenten ist die Klasse Component. Sie enthält die<br />
grundlegen<strong>de</strong>n 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 />
269 <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änzen<strong>de</strong>n Komponenten.<br />
311
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.2.1 Schaltflächen (Buttons)<br />
Component<br />
Button<br />
><br />
public Button()<br />
public Button(Str<strong>in</strong>g label)<br />
><br />
public void addActionListener(ActionListener l)<br />
public void addNotify()<br />
public Str<strong>in</strong>g getActionCommand()<br />
public Str<strong>in</strong>g getLabel()<br />
protected Str<strong>in</strong>g paramStr<strong>in</strong>g()<br />
protected void processActionEvent(ActionEvent e)<br />
protected void processEvent(AWTEvent e)<br />
public void removeActionListener(ActionListener l)<br />
public void setActionCommand(Str<strong>in</strong>g kommando)<br />
public void setLabel(Str<strong>in</strong>g label)<br />
Abb. Die Klasse Button<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> <strong>de</strong>r Fensterklasse auslösen. Mit<br />
<strong>de</strong>n folgen<strong>de</strong>n Konstruktoren kann e<strong>in</strong>e Schaltfläche erstellt wer<strong>de</strong>n:<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 <strong>de</strong>r durch das Str<strong>in</strong>g-Objekt<br />
bezeichneten Beschriftung.<br />
In e<strong>in</strong>em Applet 270 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 wie<strong>de</strong>r<br />
verän<strong>de</strong>rt wer<strong>de</strong>n. Dazu dient die Metho<strong>de</strong>: public void setLabel(Str<strong>in</strong>g<br />
label). Welche Beschriftung die Schaltfläche angenommen hat, ermittelt die<br />
Metho<strong>de</strong> 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, sen<strong>de</strong>t 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 <strong>de</strong>n 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 <strong>de</strong>r Metho<strong>de</strong> public<br />
void actionPerformed(ActionEvent ae) ,die die Metho<strong>de</strong><br />
getActionCommand aufrufen kann, mit <strong>de</strong>r die Beschriftung <strong>de</strong>s Button abgefragt<br />
wer<strong>de</strong>n kann. Falls das Action-Kommando nicht mit <strong>de</strong>r Beschriftung i<strong>de</strong>ntisch ist,<br />
270 Abgeleitet von <strong>de</strong>r Panel-Klasse<br />
312
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
kann es <strong>in</strong> <strong>de</strong>r Button-Klasse durch „public void setActionCommand(Str<strong>in</strong>g<br />
kommando)“ geän<strong>de</strong>rt wer<strong>de</strong>n.<br />
Bsp.: Setzen von H<strong>in</strong>tergrundfarben nach verschie<strong>de</strong>nen Buttonklicks 271<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 />
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 Bor<strong>de</strong>rLayout(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 />
271 pr52105<br />
313
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Reaktionen auf die Betätigung von Schaltflächen (JDK 1.0). Die Komponenten<br />
<strong>in</strong>nerhalb <strong>de</strong>r AWT-Oberfläche besitzen e<strong>in</strong>e action()-Metho<strong>de</strong>, die aufgerufen<br />
wird, wenn bei e<strong>in</strong>er Komponente e<strong>in</strong>e Aktion ausgführt wur<strong>de</strong>. Beim Betätigen<br />
(Auslösen) e<strong>in</strong>er Schaltfläche wird die action()-Metho<strong>de</strong> aufgerufen. Die<br />
action()-Metho<strong>de</strong> gehört zu <strong>de</strong>n Ereignisbehandlungsmetho<strong>de</strong>n <strong>de</strong>s Event<br />
Handl<strong>in</strong>g. Die Syntax <strong>de</strong>r action()-Metho<strong>de</strong> ist bei allen Komponenten i<strong>de</strong>ntisch:<br />
public boolean action(Event ereignis, Object welcheAktion).<br />
Ereignis: Ereignis, das bei <strong>de</strong>r Komponente aufgetreten ist<br />
welcheAktion: steht für das, was geschehen ist<br />
Bei Schaltflächen ist die Art <strong>de</strong>r Aktion (welcheAktion) ganz e<strong>in</strong>fach über das Label<br />
(Beschriftung) <strong>de</strong>r Schaltfläche auszuwerten, die ausgelöst wur<strong>de</strong>. Der „Event“-<br />
Parameter enthält spezifische Informationen über die Aktion, z.B.:<br />
event.target (Komponente, bei <strong>de</strong>r die Aktion e<strong>in</strong>getreten ist)<br />
event.when (Zeitpunkt, zu <strong>de</strong>m die Aktion geschehen ist)<br />
Mit <strong>de</strong>m <strong>in</strong>stanceof-Operator kann die event.target-Variable überprüft wer<strong>de</strong>n,<br />
ob die Aktion auch für das Objekt erfolgt, das gewünscht wird.<br />
Bsp.: Setzen von H<strong>in</strong>tergrundfarben nach verschie<strong>de</strong>nen Buttonklicks 272<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); this.setLayout(new Bor<strong>de</strong>rLayout(15,15));<br />
Panel p = new Panel();<br />
p.setLayout(new FlowLayout(FlowLayout.CENTER,15,15));<br />
p.add(new Button("Rot")); p.add(new Button("Blau"));<br />
p.add(new Button("Gruen")); p.add(new Button("Gelb"));<br />
p.add(new Button("Schwarz")); 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) aen<strong>de</strong>reFarbe((Str<strong>in</strong>g) arg);<br />
return true;<br />
}<br />
void aen<strong>de</strong>reFarbe(Str<strong>in</strong>g knopfName)<br />
{<br />
// Aen<strong>de</strong>rn <strong>de</strong>r H<strong>in</strong>tergrundfarbe<br />
if (knopfName.equals("Rot"))<br />
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 />
272 vgl. pr52105<br />
314
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.2.2 Labels<br />
Labels s<strong>in</strong>d Zeichenketten zur Beschriftung an<strong>de</strong>rer Komponenten <strong>de</strong>r<br />
Benutzeroberfläche. E<strong>in</strong> Label umfaßt e<strong>in</strong>e Zeile Text, die auf <strong>de</strong>m Bildschirm<br />
angezeigt wird und vom Programm verän<strong>de</strong>r wer<strong>de</strong>n kann.<br />
Konstruktoren.<br />
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 <strong>de</strong>s Texts. Hier kann e<strong>in</strong>e <strong>de</strong>r Konstanten<br />
Label.LEFT, Label.RIGHT, Label.CENTER übergeben wer<strong>de</strong>n.<br />
Metho<strong>de</strong>n.<br />
public void setText(Str<strong>in</strong>g text)<br />
// Zugriff auf die Textzeile <strong>de</strong>s Label<br />
public Str<strong>in</strong>g getText()<br />
// Zugriff auf die Textzeile <strong>de</strong>s Label<br />
public void setAlignment(<strong>in</strong>t ausrichten)<br />
// Ausrichten <strong>de</strong>r Textzeile<br />
public <strong>in</strong>t getAlignment()<br />
// Ausrichten <strong>de</strong>r Textzeiele<br />
5.2.3 Kontrollkästchen und Optionsfel<strong>de</strong>r<br />
Erzeugen von Kontrollkästchen. E<strong>in</strong> Kontrollkästchen (Checkbutton / Checkbox)<br />
hat zwei Bestandteile: e<strong>in</strong> Label (Text, <strong>de</strong>r neben <strong>de</strong>m 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 />
wur<strong>de</strong> o<strong>de</strong>r nicht 273 ). 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 <strong>de</strong>s Anfangszustands<br />
- Checkbox(Str<strong>in</strong>g label, CheckboxGroup cbg, boolean zustand)<br />
(Kontrollkästchen, das jenach gesetzter boolescher Zustandsvariable vorselektiert (true) ist o<strong>de</strong>r<br />
nicht (false). Das mittlere Argument ist bei Kontrollkästchen immer auf Null gesetzt. Falls das nicht<br />
<strong>de</strong>r Fall ist, dient <strong>de</strong>r 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 Metho<strong>de</strong><br />
add(), z.B.: add(new Checkbox("<strong>Java</strong>"));.<br />
Überprüfen und Setzen von Kontrollkästchen. Mit <strong>de</strong>r Metho<strong>de</strong> public boolean<br />
getState() kann überprüft wer<strong>de</strong>n, ob e<strong>in</strong> Kontrollkästchen angeglickt wur<strong>de</strong>. Die<br />
Metho<strong>de</strong> public void setState(boolean zustand) setzt <strong>de</strong>n Status (true<br />
für gesetzt). Die getlabel()-Metho<strong>de</strong> fragt das Label <strong>de</strong>s jeweiligen<br />
Kontrollkästchens ab.<br />
Reaktion auf Zustandsän<strong>de</strong>rungen. E<strong>in</strong>e Checkbox generiert e<strong>in</strong> Item-Event, wenn<br />
die Markierung vom Anwen<strong>de</strong>r gesetzt o<strong>de</strong>r zurückgenommen wird. Zur Reaktion auf<br />
dieses Event ist durch <strong>de</strong>n Aufruf von addItemListener e<strong>in</strong> Objekt, das das<br />
Interface ItemListener implementiert, bei <strong>de</strong>r Checkbox zu registrieren. In<br />
273 Standardmäßig ist die Box ausgeschaltet (Wert ist false o<strong>de</strong>r „off“).<br />
315
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
diesem Fall wird e<strong>in</strong> Ereignisempfänger die Metho<strong>de</strong> itemStateChanged mit e<strong>in</strong>em<br />
Argument vom Typ ItemEvent aufgerufen:<br />
public abstract void itemStateChanged(ItemEvent e)<br />
Über das ItemEvent kann die Metho<strong>de</strong> getItemSelectable aufgerufen wer<strong>de</strong>n,<br />
mit <strong>de</strong>r ermittelt wer<strong>de</strong>n kann, durch welche Checkbox das Ereignis ausgelöst wur<strong>de</strong>:<br />
public ItemSelectable getItemSelectable().<br />
Der Rückgabewert kann <strong>in</strong> e<strong>in</strong> Objekt <strong>de</strong>s Typs Checkbox konvertiert wer<strong>de</strong>n. Durch<br />
Aufruf von getState() kann <strong>de</strong>r aktuelle Zustand bestimmt wer<strong>de</strong>n.<br />
Bsp.:<br />
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 />
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 />
{ System.exit(0); }<br />
});<br />
f.setSize(100,150); 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 (Optionsfel<strong>de</strong>r), von <strong>de</strong>n genau immer e<strong>in</strong>er aktiviert wird.<br />
Wird e<strong>in</strong>e an<strong>de</strong>rer Button aktiviert, so än<strong>de</strong>r er se<strong>in</strong>en <strong>in</strong>ternen Status auf „true“ und<br />
<strong>de</strong>r zuvor gesetzte wird „false“. E<strong>in</strong>e CheckboxGroup ist nichts An<strong>de</strong>res als e<strong>in</strong>e<br />
Checkbox, <strong>de</strong>ren CheckboxGroup-Parameter gesetzt ist.<br />
Erzeugen von Optionsfel<strong>de</strong>rn (Radiobuttons). Erfor<strong>de</strong>rlich ist zunächst e<strong>in</strong>e<br />
Checkbox-Gruppe, die über die betreffen<strong>de</strong>n Konstruktoren erstellt wer<strong>de</strong>n kann.<br />
Dieser Gruppe wer<strong>de</strong>n die e<strong>in</strong>zelnen Optionsfel<strong>de</strong>r h<strong>in</strong>zugefügt.<br />
316
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Plazieren von Optionsfel<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>em Conta<strong>in</strong>er. Auch Optionsfel<strong>de</strong>r müssen wie<br />
alle Komponenten nach <strong>de</strong>r Erzeugung <strong>in</strong> e<strong>in</strong>en Conta<strong>in</strong>er gebracht wer<strong>de</strong>n. Das<br />
geschieht über die Metho<strong>de</strong> add().<br />
Setzen und Überprüfen von Optionsfel<strong>de</strong>rn. Die Metho<strong>de</strong>n getState() und<br />
getLabel() funktionieren auch bei Optionsfel<strong>de</strong>rn. Zum Zugriff auf die Gruppe<br />
e<strong>in</strong>es Optionsfelds und zum Än<strong>de</strong>rn gibt es die Metho<strong>de</strong>n:<br />
public CheckboxGroup getCheckboxGroup()<br />
public void setCheckboxGroup(CheckboxGroup g)<br />
Zum Holen und Setzen <strong>de</strong>s momentan ausgewählten Optionsfelds dienen<br />
public Checkbox getCurrent()<br />
public void setCurrent(Checkbox box)<br />
Bsp.:<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class PR52302 extends Frame<br />
{<br />
CheckboxGroup cbg = new CheckboxGroup();<br />
public PR52302()<br />
{<br />
setLayout(new GridLayout(3,1));<br />
setBackground(Color.lightGray);<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); add(cb2); 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 />
{ System.out.pr<strong>in</strong>tln("rot"); }<br />
}<br />
if (cb.getLabel() == "blau")<br />
{<br />
if (cb.getState())<br />
{ System.out.pr<strong>in</strong>tln("blau"); }<br />
}<br />
if (cb.getLabel() == "gruen")<br />
{<br />
if (cb.getState())<br />
{ System.out.pr<strong>in</strong>tln("gruen"); }<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 />
{ System.exit(0); }<br />
});<br />
317
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
f.setSize(100,150); f.setVisible(true);<br />
}<br />
}<br />
Reaktionen auf Kontrollfel<strong>de</strong>r und Radiobuttons im JDK1.0. Kontrollfel<strong>de</strong>r und<br />
Radiobuttons verfügen wie alle Komponenten über die action()-Metho<strong>de</strong>. Sie wird<br />
bei e<strong>in</strong>er Auswahl aufgerufen, sobald e<strong>in</strong> Feld selektiert wird.<br />
Bsp. 274 :<br />
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 />
{<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 o<strong>de</strong>r Radiobutton<br />
if (!(e.target <strong>in</strong>stanceof Checkbox))<br />
return false;<br />
// Instanz <strong>de</strong>r Ereignisse<br />
Checkbox welcheAuswahl = (Checkbox) e.target;<br />
// Status <strong>de</strong>s Radiobuttons zur Kontrolle<br />
boolean CheckboxStatus = welcheAuswahl.getState();<br />
// Auswahl Blau<br />
if (welcheAuswahl.getLabel() == "Blau")<br />
{<br />
if (CheckboxStatus) setBackground(Color.blue); return true;<br />
}<br />
// Auswahl Rot<br />
if (welcheAuswahl.getLabel() == "Rot")<br />
{<br />
if (CheckboxStatus) setBackground(Color.red); return true;<br />
}<br />
// Auswahl Gruen<br />
if (welcheAuswahl.getLabel() == "Gruen")<br />
{<br />
if (CheckboxStatus) setBackground(Color.green); return true;<br />
}<br />
if (welcheAuswahl.getLabel() == "Gelb")<br />
{<br />
if (CheckboxStatus) setBackground(Color.yellow);<br />
return true;<br />
}<br />
return false; // ke<strong>in</strong>e <strong>de</strong>r Optionen wird aufgefangen<br />
}<br />
}<br />
274 pr54305<br />
318
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.2.4 Auswahlmenüs<br />
Es han<strong>de</strong>lt sich um Popup- bzw. Pulldown-Menüs, die sich beim Anklicken öffnen<br />
und mehrere auszuwählen<strong>de</strong> Optionen anzeigen, von <strong>de</strong>nen dann e<strong>in</strong>e Option<br />
ausgewählt wer<strong>de</strong>n kann.<br />
Konstruktor: public Choice()<br />
// erstellt e<strong>in</strong> Choice-Objekt mit e<strong>in</strong>er leeren Liste.<br />
Bearbeiten <strong>de</strong>r Liste (Combobox) zum Auswahlmenü: public void<br />
addItem(Str<strong>in</strong>g item) Je<strong>de</strong>r Aufruf von addItem hängt das übergeben<strong>de</strong><br />
Element „item“ an das En<strong>de</strong> <strong>de</strong>r Liste an. Die Elemente wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r Reihenfolge<br />
<strong>de</strong>r Aufrufe von addItem e<strong>in</strong>gefügt.<br />
Zugriff auf die Elemente <strong>de</strong>r Combobox: public <strong>in</strong>t getSelectedIn<strong>de</strong>x()<br />
liefert <strong>de</strong>n In<strong>de</strong>x <strong>de</strong>s ausgewählten Elements. Durch Übergabe dieses Werts (an<br />
„getItem“ kann das aktuelle Element beschafft wer<strong>de</strong>n: 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 <strong>de</strong>r <strong>in</strong>ternen Nummer (In<strong>de</strong>x) das ausgewählte Element beschafft wer<strong>de</strong>n.<br />
Programmseitige Auswahl e<strong>in</strong>es Elements:<br />
public void select(<strong>in</strong>t)<br />
// Auswahl über <strong>de</strong>n In<strong>de</strong>x<br />
public void select(Str<strong>in</strong>g s)<br />
// Auswahl über <strong>de</strong>n angegebenen Wert von Str<strong>in</strong>g<br />
Ereignisbehandlung. Ebenso wie e<strong>in</strong>e Checkbox sen<strong>de</strong>t auch e<strong>in</strong> Choice-Element<br />
„Item“-Ereignisse, wenn e<strong>in</strong> Element ausgewählt wur<strong>de</strong>. 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 gesen<strong>de</strong>t, wenn e<strong>in</strong> Element ausgewählt wur<strong>de</strong>. In diesem Fall wird e<strong>in</strong><br />
Ereignisempfänger die Metho<strong>de</strong> itemStateChanged mit e<strong>in</strong>em Argument vom Typ<br />
ItemEvent aufrufen: public abstract void<br />
itemStateChanged(ItemEvent e). Das „ItemEvent“ stellt die Metho<strong>de</strong><br />
public ItemSelectable getItemSelectable() zur Verfügung, mit <strong>de</strong>r<br />
ermittelt wer<strong>de</strong>n kann, durch welches Choice-Element das Ereignis ausgewählt<br />
wur<strong>de</strong>. 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 />
319
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<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 />
{ System.exit(0); }<br />
});<br />
f.setBackground(Color.lightGray);<br />
f.setVisible(true);<br />
}<br />
5.2.5 Listenfel<strong>de</strong>r<br />
E<strong>in</strong>e Instanz <strong>de</strong>r Klasse List ist e<strong>in</strong>e listenartige Darstellung von Werten, aus <strong>de</strong>nen<br />
Anwen<strong>de</strong>r e<strong>in</strong>en o<strong>de</strong>r mehrere auswählen kann. An<strong>de</strong>rs als e<strong>in</strong> Choice-Element ist<br />
e<strong>in</strong> Element <strong>de</strong>r Klasse List ständig <strong>in</strong> voller Größe auf <strong>de</strong>m Bildschirm sichtbar.<br />
Erzeugen von Listenfel<strong>de</strong>rn.<br />
public List()<br />
// legt e<strong>in</strong>e leere Liste an, <strong>de</strong>ren dargestellte Größe durch <strong>de</strong>n<br />
// Layoutmanager begrenzt wird.<br />
public List(<strong>in</strong>t groesse)<br />
// Der Parameter groesse legt die Anzahl <strong>de</strong>r angezeigten Zeilen fest.<br />
public List(<strong>in</strong>t groesse, boolean multiselect)<br />
// ist multiselect "true", kann <strong>de</strong>r Anwen<strong>de</strong>r nicht nur e<strong>in</strong> Element,<br />
// son<strong>de</strong>rn auch an<strong>de</strong>re 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[] getSelectedIn<strong>de</strong>xes()<br />
// liefert e<strong>in</strong>en Array mit <strong>de</strong>n In<strong>de</strong>xpositionen <strong>de</strong>r ausgewählten<br />
// Elemente.<br />
public Str<strong>in</strong>g[] getSelectedItems()<br />
// liefert e<strong>in</strong>e Liste <strong>de</strong>r Werte.<br />
Auswahl e<strong>in</strong>zelner Elemente.<br />
public void select(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public void <strong>de</strong>select(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
Entfernen, Verän<strong>de</strong>rn von Elementen.<br />
public void <strong>de</strong>lItem(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// löscht das Element an <strong>de</strong>r Position <strong>in</strong><strong>de</strong>x<br />
public void remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// löscht das Element an <strong>de</strong>r Position <strong>in</strong><strong>de</strong>x<br />
public void replaceItem(Str<strong>in</strong>g neuerWert,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// ersetzt das Element an <strong>de</strong>r Position <strong>in</strong><strong>de</strong>x durch die Postion<br />
// neuerWert.<br />
Item- und Action-Ereignisse. E<strong>in</strong> Listenelement sen<strong>de</strong>t Item- und Action-<br />
Ereignisse. E<strong>in</strong> Action-Ereignis wird generiert, wenn e<strong>in</strong> Listenelement durch<br />
Doppelklick ausgewählt wur<strong>de</strong>. E<strong>in</strong> Item-Ereignis wird ausgelöst, nach<strong>de</strong>m <strong>in</strong> <strong>de</strong>r<br />
Liste e<strong>in</strong> Element ausgewählt wur<strong>de</strong>.<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 />
320
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<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: " + 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 Textfel<strong>de</strong>r<br />
Das AWT verfügt über Klassen zur E<strong>in</strong>gabe von Text (Klasse TextField für<br />
Textfel<strong>de</strong>r und Klasse TextArea für Textbereiche). Textfel<strong>de</strong>r begrenzen die Menge<br />
<strong>de</strong>s e<strong>in</strong>zugeben<strong>de</strong>n Textes und können nicht gescrollt wer<strong>de</strong>n. In Textbereichen<br />
können mehrere Zeilen verarbeitet wer<strong>de</strong>n, außer<strong>de</strong>m s<strong>in</strong>d Textbereiche scrollbar.<br />
TextField<br />
E<strong>in</strong> TextField dient zur Darstellung von Text. Anwen<strong>de</strong>r und Programm können <strong>de</strong>n<br />
dargestellten Text e<strong>in</strong>lesen und verän<strong>de</strong>rn.<br />
Erzeugen von Textfel<strong>de</strong>rn. Es stehen folgen<strong>de</strong> Konstruktoren zur Verfügung:<br />
321
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public TextField()<br />
erzeugt e<strong>in</strong> leeren Textfeld, <strong>in</strong> das <strong>de</strong>r Anwen<strong>de</strong>r Text e<strong>in</strong>geben kann.<br />
public TextField(<strong>in</strong>t anzSpalten)<br />
Erzeugt e<strong>in</strong> leeres Textfeld bestimmter Breite. Die Anzahl e<strong>in</strong>zugeben<strong>de</strong>r Zeichen ist nicht begrenzt.<br />
Ist <strong>de</strong>r Text länger, so scrollt er <strong>in</strong>nerhalb <strong>de</strong>s Textfelds<br />
public TextField(Str<strong>in</strong>g text)<br />
Über <strong>de</strong>n Parameter text kann e<strong>in</strong>e Zeichenkette vorgegeben wer<strong>de</strong>n, die beim aufruf <strong>de</strong>s Textfelds<br />
vorgelegt wird.<br />
public TextField(Str<strong>in</strong>g text, <strong>in</strong>t anzSpalten)<br />
Metho<strong>de</strong>n zum Zugriff bzw. Verän<strong>de</strong>rn von Textfel<strong>de</strong>rn.<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 <strong>de</strong>r darstellbaren Zeichen e<strong>in</strong>es Textfelds abgefragt und mit<br />
public void setColumns(<strong>in</strong>t anzSpalten)<br />
verän<strong>de</strong>rt wer<strong>de</strong>n.<br />
Markieren von Text.<br />
public void selectAll()<br />
//markiert <strong>de</strong>n kompletten Bereich<br />
public void select(<strong>in</strong>t erstes, <strong>in</strong>t letztes)<br />
//markiert <strong>de</strong>n 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 getSelectionEnd()<br />
kann die aktuelle Auswahl abgefragt wer<strong>de</strong>n. 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 wer<strong>de</strong>n.<br />
Bearbeiten von Textfel<strong>de</strong>rn.<br />
Über<br />
public void setEditable(boolean erlaubt)<br />
// Aufruf mit Parameter false unterb<strong>in</strong><strong>de</strong>t weitere E<strong>in</strong>gaben<br />
bzw.<br />
public boolean isEditable() // Abfrage <strong>de</strong>s aktuellen Status<br />
kann man die Verän<strong>de</strong>rung von Text verh<strong>in</strong><strong>de</strong>rn. Mit<br />
public void setEchoChar(char z)<br />
(Übergabe e<strong>in</strong>es Zeichens, das beim Tastendruck anstelle <strong>de</strong>s vom anwen<strong>de</strong>r e<strong>in</strong>gegebenen<br />
Zeichens ausgegeben wird)<br />
bzw.<br />
public char getEchoChar()<br />
besteht die Möglichkeit ver<strong>de</strong>ckter 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 <strong>de</strong>r Enter-Taste <strong>in</strong>nerhalb <strong>de</strong>s<br />
Textfelds. Die Metho<strong>de</strong> Str<strong>in</strong>g getActionCommand() <strong>de</strong>s Action-Events liefert<br />
<strong>de</strong>n Inhalt <strong>de</strong>s Textfelds.<br />
Generieren e<strong>in</strong>es Text-Ereignisses bei je<strong>de</strong>r Än<strong>de</strong>rung im Textfeld. E<strong>in</strong> Empfänger<br />
kann mit <strong>de</strong>r Metho<strong>de</strong> addTextListener vom Textfeld registriert wer<strong>de</strong>n. 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 Metho<strong>de</strong><br />
322
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
textValueChanged mit e<strong>in</strong>em „TextEvent“ als Parameter aufgerufen.<br />
„TextEvent“ ist aus „AWTEvent“ abgeleitet und erbt die Metho<strong>de</strong>n getID(),<br />
getSource(). Typischerweise wird <strong>in</strong>nerhalb von public void<br />
textValueChanged(TextEvent e) mit getSource() das zugehörige Textfeld<br />
beschafft und mit getText() auf se<strong>in</strong>en Inhalt zugegriffen.<br />
Bsp.:<br />
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 />
t1.setText("E<strong>in</strong>gefuegt durch Button 2: " + s);<br />
t1.setEditable(false);<br />
}<br />
323
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
TextArea<br />
Mit dieser Klasse können mehrzeilige Textfel<strong>de</strong>r erzeugt wer<strong>de</strong>n. Zusätzlich kann <strong>de</strong>r<br />
Text <strong>in</strong> allen Richtungen „scrollen“, so daß auch größere Texte bequem bearbeitet<br />
wer<strong>de</strong>n 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<br />
//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 scrollbars)<br />
//erzeugt e<strong>in</strong> TextArea-Objekt, <strong>in</strong> <strong>de</strong>m über scrollbars die Ausstattung <strong>de</strong>r TextArea mit<br />
//Schieberegistern festgelegt wer<strong>de</strong>n kann. Dazu stellt TextArea die Konstanten<br />
//SCROLLBARS_BOTH, SCROLLBARS_NONE, SCROLLBARS_VERTICAL_ONLY,<br />
//SCROLLBARS_HORIZONTAL_ONLY zur Verfügung, die als Argumente übergeben wer<strong>de</strong>n können.<br />
Zusätzliche <strong>in</strong> <strong>de</strong>r Klasse bereitgestellte Metho<strong>de</strong>n zum Verän<strong>de</strong>rn von Teilen <strong>de</strong>s<br />
Texts. Neben <strong>de</strong>n bereits <strong>in</strong> <strong>de</strong>r Klasse TextField angegebenen Metho<strong>de</strong>n stehen zur<br />
Verfügung:<br />
public void <strong>in</strong>sert(Str<strong>in</strong>g str, <strong>in</strong>t pos)<br />
//verän<strong>de</strong>rt die Zeichenkette str ab Position pos. Der dah<strong>in</strong>ter stehen<strong>de</strong> Text wird entsprechend<br />
//nach h<strong>in</strong>ten verschoben.<br />
public void append(Str<strong>in</strong>g str)<br />
//hängt <strong>de</strong>n ü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 en<strong>de</strong>)<br />
//ersetzt <strong>de</strong>n Text zwischen start und end durch <strong>de</strong>n Str<strong>in</strong>g text.<br />
Sen<strong>de</strong>n von Text-Events. E<strong>in</strong> Objekt <strong>de</strong>r Klasse TextArea sen<strong>de</strong>t Text-Events,<br />
so wie es bei TextField beschrieben wur<strong>de</strong>.<br />
5.2.7 Schieber und Bildlaufleisten<br />
Listen und Textbereiche besitzen standardmäßig die Eigenschaft bei Bedarf nicht <strong>in</strong><br />
<strong>de</strong>n Anzeigebereich passen<strong>de</strong>n Inhalt über Bildlaufleisten und Schieber zu scrollen.<br />
Bildlaufleisten können auch <strong>in</strong>dividuell erstellt wer<strong>de</strong>n 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 />
324
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Der Schieberegler kann horizotal und vertikal angeordnet wer<strong>de</strong>n und besitzt e<strong>in</strong>en<br />
Schieber, <strong>de</strong>ssen Größe verän<strong>de</strong>rlich 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>an<strong>de</strong>r verbun<strong>de</strong>n. Än<strong>de</strong>rt<br />
<strong>de</strong>r Anwen<strong>de</strong>r die Position <strong>de</strong>s Schiebers, än<strong>de</strong>rt sich automatisch auch se<strong>in</strong> <strong>in</strong>terner<br />
Wert. Wird vom Programm <strong>de</strong>r Wert verän<strong>de</strong>rt, führt das automatisch zu e<strong>in</strong>er<br />
Positionierung <strong>de</strong>s Schiebers. Zur Än<strong>de</strong>rung <strong>de</strong>s aktuellen Werts e<strong>in</strong>er Bildlaufleiste<br />
können drei verschie<strong>de</strong>n Teile <strong>de</strong>r Bildlaufleiste verwen<strong>de</strong>t wer<strong>de</strong>n:<br />
- Pfeile an bei<strong>de</strong>n En<strong>de</strong>n zum Erhöhen / Erniedrigen <strong>de</strong>s Werts um e<strong>in</strong>e E<strong>in</strong>heit (standardmäßig 1)<br />
- E<strong>in</strong> Bereich <strong>in</strong> <strong>de</strong>r 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> <strong>de</strong>r Mitte, <strong>de</strong>r <strong>de</strong>n momentan gewählten Wert anzeigt. Durch<br />
Verschieben <strong>de</strong>s Bildlauffelds mit <strong>de</strong>m Mauszeiger kann <strong>in</strong>nerhalb <strong>de</strong>r Bildlaufleiste e<strong>in</strong> an<strong>de</strong>rer<br />
Wert gewählt wer<strong>de</strong>n.<br />
Nötig ist nur die Festlegung e<strong>in</strong>es Höchst- und M<strong>in</strong><strong>de</strong>stwerts für die Bildlaufleiste. Der<br />
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><strong>de</strong>stwert.<br />
public Scrollbar(<strong>in</strong>t orientierung)<br />
//orientierung bezeichnet die Ausrichtung und kann über Scrollbar.HORIZONTAL bzw.<br />
//Scrollbar.VERTICAL festgelegt wer<strong>de</strong>n.<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, <strong>in</strong>t<br />
maximum)<br />
//orientierung...bestimmt die Ausrichtung <strong>de</strong>s Schiebereglers<br />
//wert...Anfangswert <strong>de</strong>s Schiebereglers (Wert zwischen <strong>de</strong>m Höchst- und M<strong>in</strong><strong>de</strong>stwert<br />
//bh...Breite bzw. Höhe <strong>de</strong>r <strong>de</strong>m Schieberegler zugeteilten Box (Seite)<br />
//m<strong>in</strong>imum, maximum...bezeichnet <strong>de</strong>n M<strong>in</strong><strong>de</strong>st-, Höchstwert <strong>de</strong>s Schiebereglers<br />
Metho<strong>de</strong>n <strong>de</strong>r Scrollbar-Klasse versorgen die Handhabung <strong>de</strong>r Werte <strong>de</strong>s<br />
Schiebereglers:<br />
Metho<strong>de</strong><br />
Be<strong>de</strong>utung<br />
public <strong>in</strong>t getValue()<br />
Zugriff auf <strong>de</strong>n aktuellen Wert <strong>de</strong>s Schiebereglers<br />
public void setValue(<strong>in</strong>t wert) Setzt <strong>de</strong>n aktuellen Wert <strong>de</strong>s Schiebereglers<br />
public <strong>in</strong>t getOrientation()<br />
Bestimmt die Ausrichtung <strong>de</strong>s Schiebereglers<br />
public <strong>in</strong>t getM<strong>in</strong>imum()<br />
Zugriff auf <strong>de</strong>n M<strong>in</strong><strong>de</strong>stwert<br />
public <strong>in</strong>t getMaximum()<br />
Zugriff auf <strong>de</strong>n Höchstwert<br />
public <strong>in</strong>t getUnitIncrement() Zugriff <strong>de</strong>r Parameter, die die Stärke <strong>de</strong>r Verän<strong>de</strong>rung <strong>de</strong>s<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än<strong>de</strong>rung <strong>de</strong>r Parameter, die die Stärke <strong>de</strong>r<br />
Verän<strong>de</strong>rung <strong>de</strong>s Werts beim Klicken auf die Buttons<br />
zwischen Schieber und Button bestimmen<br />
public <strong>in</strong>t getBlockIncrement() Zugriff <strong>de</strong>r Parameter, die die Stärke <strong>de</strong>r Verän<strong>de</strong>rung <strong>de</strong>s<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än<strong>de</strong>rung <strong>de</strong>r Parameter, die die Stärke <strong>de</strong>r<br />
Verän<strong>de</strong>rung <strong>de</strong>s Werts beim Klicken auf die Schaltfläche<br />
zwischen Schieber und Button bestimmen<br />
Ereignisse. E<strong>in</strong> Scrollbar sen<strong>de</strong>t 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 <strong>de</strong>r Metho<strong>de</strong>:<br />
325
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public abstract void adjustmentValueChanged(AdjustmentEvent e),<br />
die e<strong>in</strong> AdjustmentEvent übergeben bekommt. Dieses besitzt die Meto<strong>de</strong><br />
getAdjustable(), mit <strong>de</strong>r <strong>de</strong>r auslösen<strong>de</strong> Scrollbar bestimmt wer<strong>de</strong>n kann.<br />
Zusätzlich gibt es die Metho<strong>de</strong> getAdjustmentType(), die Auskunft darüber gibt,<br />
welche Benutzeraktion zur Auslösung <strong>de</strong>s Ereignisses führte.<br />
Konstanten, die von getAdjustmentType<br />
zurückgegeben wer<strong>de</strong>n<br />
AdjustmentEvent.UNIT_INCREMENT<br />
AdjustmentEvent.UNIT_DECREMENT<br />
AdjustmentEvent.BLOCK_INCREMENT<br />
AdjustmentEvent.BLOCK_DECREMENT<br />
AdjustmentEvent.TRACK<br />
Be<strong>de</strong>utung<br />
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 />
Der Wert durch Klicken e<strong>in</strong>es „Button“ um e<strong>in</strong>e<br />
E<strong>in</strong>heit erniedrigt.<br />
Der Wert wur<strong>de</strong> durch Klicken <strong>de</strong>r Schaltfläche<br />
zwischen Button und Schieber um e<strong>in</strong>e Seite erhöht<br />
Der Wert wur<strong>de</strong> durch Klicken <strong>de</strong>r Schaltfläche<br />
zwischen Button und Schieber um e<strong>in</strong>e Seite<br />
verm<strong>in</strong><strong>de</strong>rt<br />
Der Wert wur<strong>de</strong> durch Ziehen <strong>de</strong>s Schiebers<br />
verän<strong>de</strong>rt<br />
Bsp.:<br />
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 Bor<strong>de</strong>rLayout());<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 />
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 />
326
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
{ System.exit(0); }<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 unterschei<strong>de</strong>t 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> <strong>de</strong>r Lage, e<strong>in</strong>e virtuelle Ausgabefläche zu verwalten, die größer ist als die auf <strong>de</strong>m<br />
Bildschirm zur Verfügung stehen<strong>de</strong> 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 <strong>de</strong>m<br />
Bildschirm). Falls die benötigte Ausgabefläche größer ist als die anzeigbare, blen<strong>de</strong>t<br />
e<strong>in</strong> ScrollPane automatisch die erfor<strong>de</strong>rlichen 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 <strong>de</strong>f<strong>in</strong>iert die Strategie zur Anzeige <strong>de</strong>r Schieberegler entsprechend<br />
327
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
//<strong>de</strong>n <strong>in</strong> <strong>de</strong>r folgen<strong>de</strong> Liste aufgelisteten Konstanten:<br />
ScrollPane.SCROLLBARS_AS_NEEDED<br />
ScrollPane.SCROLLBARS_ALWAYS<br />
ScrollPane.SCROLLBARS_NEVER<br />
Die Schieberegler wer<strong>de</strong>n genau dann angezeigt,<br />
wenn es erfor<strong>de</strong>rlich ist, d.h.: Es wird mehr Platz<br />
benötigt, als für sie zur Anzeige zur Verfügung<br />
steht.<br />
Die Schieberegler wer<strong>de</strong>n immer angezeigt<br />
Die Schieberegler wer<strong>de</strong>n nie angezeigt, <strong>de</strong>r<br />
Bildschirm kann nur vom Programm aus verschoben<br />
wer<strong>de</strong>n<br />
5.2.9 Zeichenbereiche<br />
E<strong>in</strong> Canvas ist e<strong>in</strong> frei <strong>de</strong>f<strong>in</strong>iertes Dialogelement, das <strong>in</strong> <strong>de</strong>r 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 wer<strong>de</strong>n.<br />
Konstruktor:<br />
public Canvas()<br />
Die Metho<strong>de</strong> 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 <strong>de</strong>m<br />
Bildschirm. Die vom System bereitgestellte Version zeichnet nur die Ausgabefläche<br />
<strong>in</strong> <strong>de</strong>r 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) <strong>de</strong>s übergebenen<br />
Graphics-Objekts entspricht dabei <strong>de</strong>r l<strong>in</strong>ken oberen Ecke <strong>de</strong>s 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.:<br />
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 />
// Instanzmetho<strong>de</strong>n<br />
public void bere<strong>in</strong>igen()<br />
{<br />
zeichneObjekte = false;<br />
repa<strong>in</strong>t();<br />
328
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
"Metho<strong>de</strong> pa<strong>in</strong>t wur<strong>de</strong> aufgerufen, zeichneObjekte = "<br />
+ zeichneObjekte);<br />
if (zeichneObjekte)<br />
{<br />
// Individuelle Auspraegung <strong>de</strong>r 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 />
setLayout(new Bor<strong>de</strong>rLayout());<br />
Panel panelN = new Panel(); panelN.add(new Label(„x: „));<br />
xFeld = new TextField(5); xFeld.setEditable(false);<br />
panelN.add(xFeld); panelN.add(new Label("y: "));<br />
yFeld = new TextField(5); 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); 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); add("South",panelS);<br />
pack();<br />
setVisible(true);<br />
}<br />
// Implementierung <strong>de</strong>s MouseMotionListener-Interface<br />
public void mouseMoved(MouseEvent e)<br />
{<br />
xFeld.setText(" " + e.getX()); yFeld.setText(" " + e.getY());<br />
}<br />
public void mouseDragged(MouseEvent e)<br />
{<br />
xFeld.setText(" " + e.getX()); yFeld.setText(" " + e.getY());<br />
}<br />
// Start <strong>de</strong>r GUI<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
ZeichneGUI gui = new ZeichneGUI();<br />
}<br />
}<br />
330
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.3 Conta<strong>in</strong>er<br />
Conta<strong>in</strong>er s<strong>in</strong>d allgeme<strong>in</strong>e Komponenten, die an<strong>de</strong>re Komponenten o<strong>de</strong>r auch<br />
an<strong>de</strong>re Conta<strong>in</strong>er enthalten.<br />
5.3.1 Panels<br />
E<strong>in</strong>e sehr häufig vorkommen<strong>de</strong> Conta<strong>in</strong>er-Form ist das sog. Panel, das e<strong>in</strong>en<br />
Conta<strong>in</strong>er darstellt, <strong>de</strong>r am Bildschirm dargestellt wer<strong>de</strong>n 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 <strong>de</strong>s 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 an<strong>de</strong>ren 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 wer<strong>de</strong>n.<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 <strong>de</strong>n verschie<strong>de</strong>nen 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 verschie<strong>de</strong>n gestaltete Mauszeiger verwen<strong>de</strong>n.<br />
Erzeugen von Frames. Mit <strong>de</strong>r Frame-Klasse kann e<strong>in</strong> funktionsfähiges Fenster mit<br />
Menüleiste erstellt wer<strong>de</strong>n. Zum Erzeugen von Frames stehen verschie<strong>de</strong>ne<br />
Konstruktoren zur Verfügung:<br />
public Frame()<br />
//Damit kann e<strong>in</strong> Frame erzeugt wer<strong>de</strong>n, <strong>de</strong>r 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 <strong>de</strong>r Erzeugung, das Frame ist zu Beg<strong>in</strong>n nicht sichtbar.<br />
Verän<strong>de</strong>rn <strong>de</strong>r Titelzeile. Sie läßt sich <strong>in</strong> <strong>de</strong>n Klassen Frame und Dialog mit <strong>de</strong>n<br />
Metho<strong>de</strong>n<br />
public void setTitle(Str<strong>in</strong>g titel)<br />
// än<strong>de</strong>rt die Beschriftung <strong>de</strong>r Titelleiste <strong>in</strong> titel<br />
public Str<strong>in</strong>g getTitle()<br />
// Abfrage <strong>de</strong>r Titelleiste<br />
bee<strong>in</strong>flussen.<br />
E<strong>in</strong>stellen <strong>de</strong>s Standard-Font. E<strong>in</strong> Fenster hat e<strong>in</strong>en Standard-Font, <strong>de</strong>r zur Ausgabe<br />
<strong>de</strong>r Schrift verwen<strong>de</strong>t wird, (wenn nicht im Grafik-Kontext e<strong>in</strong> an<strong>de</strong>rer Font<br />
ausgewählt wird). Der Standard-Font e<strong>in</strong>es Fensters wird mit „public void<br />
setFont (Font f)“ <strong>de</strong>r Klasse Component e<strong>in</strong>gestellt.<br />
E<strong>in</strong>stellen von Vor<strong>de</strong>r- Und H<strong>in</strong>tergrundfarbe. Die Vor<strong>de</strong>rgrundfarbe dient zur<br />
Ausgabe von Grafik- und Textobjekten, wenn im Grafik-Kontext ke<strong>in</strong>e an<strong>de</strong>re Farbe<br />
331
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
gesetzt wird. Wird die E<strong>in</strong>stellung nicht geän<strong>de</strong>rt, wer<strong>de</strong>n für Vor<strong>de</strong>rgrund- und<br />
H<strong>in</strong>tergrundfarbe die unter W<strong>in</strong>dows e<strong>in</strong>gestellten Standardfarben verwen<strong>de</strong>t. Mit<br />
public void setBackground(Color farbe)<br />
public void setForeground(Color farbe)<br />
können Vor<strong>de</strong>rgrund- und H<strong>in</strong>tergrundfarbe <strong>de</strong>s Fensters geän<strong>de</strong>rt wer<strong>de</strong>n.<br />
Größe und Position e<strong>in</strong>es Fensters können bestimmt wer<strong>de</strong>n über<br />
public void setSize(<strong>in</strong>t breite, <strong>in</strong>t hoehe)<br />
// verän<strong>de</strong>rt die Größe <strong>de</strong>s Fensters auf <strong>de</strong>n 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 <strong>de</strong>r 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, Wegblen<strong>de</strong>n und Löschen von Frames. Die Konstruktoren haben das<br />
Frame unsichtbar gelassen. Frames müssen vor Gebrauch sichtbar gemacht<br />
wer<strong>de</strong>n. Der 1. Schritt besteht dar<strong>in</strong>, e<strong>in</strong>en Frame e<strong>in</strong>e Größe mit <strong>de</strong>r Metho<strong>de</strong><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 <strong>de</strong>r Frame über<br />
die show()-Metho<strong>de</strong> 275 . Mit public void hi<strong>de</strong>() 276 kann <strong>de</strong>r Frame wie<strong>de</strong>r<br />
unsichtbar gemacht wer<strong>de</strong>n. Über public void dispose() wird <strong>de</strong>r Frame<br />
been<strong>de</strong>t. Mit public boolean isShow<strong>in</strong>g() kann geprüft wer<strong>de</strong>n, ob das<br />
Fenster bereits angezeigt ist.<br />
Standardlayout für Fenster: Bor<strong>de</strong>r-Layout.<br />
H<strong>in</strong>zufügen von Komponenten: Rahmen s<strong>in</strong>d Conta<strong>in</strong>er wie Panels, an<strong>de</strong>re<br />
Komponenten können mit <strong>de</strong>r add()-Metho<strong>de</strong> h<strong>in</strong>zugefügt wer<strong>de</strong>n.<br />
5.3.3 Menüs<br />
Je<strong>de</strong>s Fenster / Frame kann e<strong>in</strong>e eigene Menüleiste besitzen. Je<strong>de</strong> Menüleiste kann<br />
mehrere Menüs enthalten und je<strong>de</strong>s 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<br />
MenuBar<br />
Menu<br />
MenuItem<br />
CheckboxMenuItem<br />
Be<strong>de</strong>utung<br />
Beschreibt die Menüzeile (-leiste)e<strong>in</strong>es Fensters<br />
Beschreibet e<strong>in</strong> e<strong>in</strong>zelnes, <strong>de</strong>r <strong>in</strong> <strong>de</strong>r Menüzeile enthaltenen Menüs<br />
Bil<strong>de</strong>t die vom Anwen<strong>de</strong>r auswählbaren E<strong>in</strong>träge <strong>in</strong>nerhalb <strong>de</strong>r Menüs<br />
Die Menüleiste<br />
Sie beschreibt das Hauptmenü e<strong>in</strong>es Fensters. Sie bef<strong>in</strong><strong>de</strong>t sich unterhalb <strong>de</strong>r<br />
Titelleiste am oberen Rand <strong>de</strong>s Fensters und zeigt die Namen <strong>de</strong>r dar<strong>in</strong> enthaltenen<br />
Menüs an. E<strong>in</strong>e Menüleiste wird durch Instanzen <strong>de</strong>r Klasse MenuBar erzeugt:<br />
275 Für show() aus <strong>de</strong>m Paket java.awt.Component gibt es als neue Variante die Metho<strong>de</strong><br />
setVisible(boolean)<br />
276 hi<strong>de</strong>() ist <strong>in</strong> java.awt.Frame als „<strong>de</strong>precated“ <strong>de</strong>klariert. Statt <strong>de</strong>ssen steht setVisible(boolean) zur<br />
Verfügung<br />
332
<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 bestehen<strong>de</strong>n Menüs. public void remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public void remove(MenuComponent m)<br />
Zugriff auf e<strong>in</strong> beliebiges Menü. public Menu getMenu(<strong>in</strong>t <strong>in</strong><strong>de</strong>x).<br />
getMenu liefert das Menüobjekt, das sich an <strong>de</strong>r Position mit <strong>de</strong>m angegebenen<br />
In<strong>de</strong>x bef<strong>in</strong><strong>de</strong>t. Zum B<strong>in</strong><strong>de</strong>n e<strong>in</strong>er Menüleiste an e<strong>in</strong> Fenster mit <strong>de</strong>m angegebenen<br />
In<strong>de</strong>x (<strong>in</strong><strong>de</strong>x) bef<strong>in</strong><strong>de</strong>t.<br />
B<strong>in</strong><strong>de</strong>n e<strong>in</strong>er Menüleiste an e<strong>in</strong>en Frame. public void setMenuBar(MenuBar<br />
mb) .Durch Aufruf dieser Metho<strong>de</strong> wird die angegebene Menüleiste im Fenster<br />
angezeigt und beim Auswählen <strong>de</strong>s Menüpunkts wer<strong>de</strong>n Nachrichen ausgelöst und<br />
an das Fenster gesen<strong>de</strong>t. Die Fensterklasse kann diese Nachrichen durch das<br />
Registrieren e<strong>in</strong>es Objekts vom Typ ActionListener bearbeiten.<br />
Menüs.<br />
Sie bil<strong>de</strong>n die Bestandteile e<strong>in</strong>er Menüleiste und wer<strong>de</strong>n durch Instanzen <strong>de</strong>r Klasse<br />
Menu repräsentiert.<br />
Konstruktor. public Menu(Str<strong>in</strong>g label)<br />
// label gibt <strong>de</strong>n Namen <strong>de</strong>s Menüs an<br />
Standardhilfe-Menü: public void setHelpMenu(Menu m) erzeugt e<strong>in</strong> spezielles<br />
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 <strong>de</strong>m sie <strong>de</strong>m Anwen<strong>de</strong>r die dah<strong>in</strong>terstehen<strong>de</strong> Funktion anzeigen.<br />
Wenn <strong>de</strong>r zugehörige Menüpunkt aufgerufen wird, sen<strong>de</strong>t das Programm e<strong>in</strong>e<br />
Nachricht an das zugehörige Fenster, die dann zum Aufruf <strong>de</strong>r entsprechen<strong>de</strong>n<br />
Metho<strong>de</strong> führt.<br />
Erzeugen von Menüe<strong>in</strong>trägen: public MenuItem(Str<strong>in</strong>g label). „label“ ist<br />
<strong>de</strong>r Name <strong>de</strong>s Menüe<strong>in</strong>trags.<br />
Zugriff auf <strong>de</strong>n Namen bzw. Setzen <strong>de</strong>s 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 <strong>de</strong>m 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 <strong>de</strong>r Menüe<strong>in</strong>trag aktiv ist o<strong>de</strong>r nicht. Nur e<strong>in</strong> aktiver E<strong>in</strong>trag kann vom<br />
Anwen<strong>de</strong>r ausgewählt wer<strong>de</strong>n und so e<strong>in</strong>e Nachricht auslösen. Nach <strong>de</strong>m Aufruf <strong>de</strong>s<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“ <strong>de</strong>aktiviert und mit<br />
Parameterwert true aktiviert wer<strong>de</strong>n. Über public boolean isEnabled() kann<br />
<strong>de</strong>r aktuelle Zustand abgefragt wer<strong>de</strong>n.<br />
Metho<strong>de</strong>n 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><strong>de</strong>x)<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 <strong>de</strong>r Menüe<strong>in</strong>träge angezeigt:<br />
public void addSeparator()<br />
// fügt <strong>de</strong>n Separator h<strong>in</strong>ter <strong>de</strong>m zuletzt e<strong>in</strong>gefügten Menüe<strong>in</strong>trag e<strong>in</strong><br />
public void <strong>in</strong>sertSeparator(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// E<strong>in</strong>fügepostion kann frei angegeben wer<strong>de</strong>n.<br />
333
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Zugriff auf Menüe<strong>in</strong>trag. public MenuItem getItem(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
Anzahl <strong>de</strong>r 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 />
wer<strong>de</strong>n kann. Die visuelle Darstellung <strong>de</strong>r Zustandsvariablen erfolgt durch Anfügen<br />
o<strong>de</strong>r Entfernen e<strong>in</strong>es „Häkchens“ neben <strong>de</strong>m 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 bei<strong>de</strong>n Metho<strong>de</strong>n setState() und getState() zum Setzen<br />
und Abfragen <strong>de</strong>s 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 wer<strong>de</strong>n<br />
kann. Diese Aktion kann wie je<strong>de</strong> an<strong>de</strong>re Aktion mit <strong>de</strong>r Metho<strong>de</strong> actionPerformed<br />
behan<strong>de</strong>lt wer<strong>de</strong>n.<br />
Bsp.: Zusammenstellung <strong>de</strong>r 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> <strong>de</strong>r 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 />
334
<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,Bor<strong>de</strong>rLayout.CENTER);<br />
}<br />
class ML implements ActionListener<br />
{<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
MenuItem ziel<br />
= (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 />
335
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
System.out.pr<strong>in</strong>tln("Wache " + ziel.getState());<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 />
{ setBackground(Color.red); }<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 />
{ setBackground(Color.green); }<br />
}<br />
class GelbL implements ActionListener<br />
{<br />
public void actionPerformed(ActionEvent e)<br />
{ setBackground(Color.yellow); }<br />
}<br />
class FarbeL implements ActionListener<br />
{<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
System.out.pr<strong>in</strong>tln("Im Untermenue wur<strong>de</strong> 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 wur<strong>de</strong> 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 />
{ System.exit(0); }<br />
});<br />
f.setSize(300,200); f.setVisible(true);<br />
}<br />
}<br />
5.3.4 Dialoge<br />
Unter e<strong>in</strong>em Dialog versteht man e<strong>in</strong> Popup-Fenster. Dialoge wer<strong>de</strong>n entwe<strong>de</strong>r<br />
„modal“ o<strong>de</strong>r „non-modal“ erzeugt. „modal“ be<strong>de</strong>utet: Das Dialogfeld blockiert an<strong>de</strong>re<br />
Fenster, wenn es angezeigt wird.<br />
336
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Erzeugen. E<strong>in</strong> modaler Dialog muß immer von <strong>de</strong>r Klasse Dialog abgeleitet se<strong>in</strong>.<br />
Dialog bietet 4 Konstruktoren an<br />
public Dialog(Frame eltern)<br />
public Dialog(Frame 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 entschei<strong>de</strong>t, ob <strong>de</strong>r Dialog modal wird o<strong>de</strong>r nicht.<br />
Zugriff auf modale bzw. „nicht modale“ Eigenschaft. Dafür gibt es die Metho<strong>de</strong>n<br />
public boolean isModal()<br />
// Rückgabewert ist true, falls <strong>de</strong>r Dialog modal ist. An<strong>de</strong>renfalls ist er<br />
// false.<br />
public void setModal(boolean b)<br />
Unterb<strong>in</strong><strong>de</strong>n <strong>de</strong>r Verän<strong>de</strong>rbarkeit <strong>de</strong>r Größe e<strong>in</strong>es Fensters. Das kann über<br />
public void setResizable(boolean resizable)<br />
public boolean isResizable()<br />
geschehen bzw. überprüft wer<strong>de</strong>n.<br />
337
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r Oberfläche. Je nach Plattform und<br />
Bed<strong>in</strong>gungen wer<strong>de</strong>n Komponenten <strong>in</strong> die Oberfläche optimal angepaßt. Über<br />
Layout-Manager kann das AWT angewiesen wer<strong>de</strong>n, wo Komponenten im Verhältnis<br />
zu an<strong>de</strong>ren Komponenten stehen sollen. Der Layout-Manager bestimmt nach<br />
gewissen Regeln, an welche Stelle die Komponenten am besten passen und ermittelt<br />
die optimale Größe <strong>de</strong>r Komponenten.<br />
5.4.1 Layout-Regeln<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><br />
ist plattformunabhängig, daher kann <strong>de</strong>r Programmierer hier ke<strong>in</strong>e Aussagen<br />
machen.<br />
2. Die Reihenfolge, <strong>in</strong> <strong>de</strong>r die AWT-Komponenten <strong>in</strong> e<strong>in</strong>en Conta<strong>in</strong>er e<strong>in</strong>gefügt<br />
wer<strong>de</strong>n.<br />
3. Die Art <strong>de</strong>s Layout-Managers. Das AWT umfaßt 5 verschie<strong>de</strong>ne Typen von<br />
Layout-Managern, die die Oberfläche unterschiedlich aufglie<strong>de</strong>rn:<br />
- Flow-Layout<br />
- Grid-Layout<br />
- Bor<strong>de</strong>r-Layout<br />
- Card-Layout<br />
- GridBag-Layout<br />
Je<strong>de</strong>s Panel kann e<strong>in</strong>en eigenen Layout-Manager verwen<strong>de</strong>n.<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> <strong>de</strong>r <strong>in</strong>it()-Metho<strong>de</strong>) die Metho<strong>de</strong> public void<br />
setLayout(LayoutManager mgr) verwen<strong>de</strong>t wer<strong>de</strong>n, z.B.: setLayout(new<br />
FlowLayout());<br />
338
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.4.2 Die e<strong>in</strong>zelnen Layout-Manager<br />
Die FlowLayout-Klasse<br />
><br />
LayoutManager<br />
FlowLayout<br />
public static <strong>in</strong>t CENTER<br />
public static <strong>in</strong>t LEADING<br />
public static <strong>in</strong>t LEFT<br />
public static <strong>in</strong>t RIGHT<br />
public static <strong>in</strong>t TRAILING<br />
><br />
public FlowLayout()<br />
public FlowLayout(<strong>in</strong>t align)<br />
public FlowLayout(<strong>in</strong>t align, <strong>in</strong>t hgap, <strong>in</strong>t vgap)<br />
//erzeugt e<strong>in</strong> FlowLayout mit angegebenen Alignment und e<strong>in</strong>em<br />
//horizontalen bzw. vertikalen Rand<br />
><br />
public void addLayoutComponent(Str<strong>in</strong>g name, Component comp)<br />
public <strong>in</strong>t getAlignment()<br />
//liefert das Alignment <strong>de</strong>s FlowLayout-Managers<br />
public void setAlignment(<strong>in</strong>t align)<br />
//setzt das Alignment mit Hilfe <strong>de</strong>r Konstanten<br />
//FlowLayout.RIGHT, FlowLayout.LEFT, FlowLayout.CENTER<br />
...<br />
Abb. Die Klasse FlowLayout<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 bewegt<br />
sich wie<strong>de</strong>r von l<strong>in</strong>ks nach rechts. Die Standard-.Ausrichtung für e<strong>in</strong> FlowLayout ist<br />
zentriert.<br />
Der FlowLayout-Manager ist <strong>de</strong>r Standard-Layout-Manager für alle Applets.<br />
Bsp.: Plazierung von Schaltflächen.<br />
Die Komponenten wer<strong>de</strong>n <strong>in</strong> <strong>de</strong>r Reihenfolge, <strong>in</strong> <strong>de</strong>r sie <strong>in</strong> <strong>de</strong>n Conta<strong>in</strong>er e<strong>in</strong>gefügt<br />
wer<strong>de</strong>n, 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 <strong>de</strong>r folgen<strong>de</strong> Quellco<strong>de</strong><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 />
339
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
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 <strong>de</strong>n im Applet-Tag angegebenen Abmessungen<br />
<br />
<br />
FlowLayout-Test<br />
<br />
<br />
<br />
<br />
<br />
<br />
zur folgen<strong>de</strong>n Darstellung<br />
E<strong>in</strong>e Verän<strong>de</strong>rung <strong>in</strong> <strong>de</strong>r Größe <strong>de</strong>s Applet macht <strong>de</strong>n zeilenweisen Aufbau <strong>de</strong>utlich:<br />
<br />
<br />
FlowLayout-Test<br />
<br />
<br />
<br />
<br />
<br />
<br />
340
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Bor<strong>de</strong>rLayout-Klasse<br />
><br />
LayoutManager<br />
Bor<strong>de</strong>rLayout<br />
public static Str<strong>in</strong>g CENTER<br />
public static Str<strong>in</strong>g NORTH<br />
public static Str<strong>in</strong>g EAST<br />
public static Str<strong>in</strong>g SOUTH<br />
public static Str<strong>in</strong>g WEST<br />
><br />
public Bor<strong>de</strong>rLayout()<br />
public Bor<strong>de</strong>rLayout(<strong>in</strong>t hgap, <strong>in</strong>t vgap)<br />
><br />
public void addLayoutComponent(Component comp, Object constra<strong>in</strong>ts)<br />
public void layoutConta<strong>in</strong>er(Conta<strong>in</strong>er target)<br />
public Dimension preferredLayoutSize(Conta<strong>in</strong>er target)<br />
public void removeLayoutComponent(Component comp)<br />
...<br />
Abb. Die Klasse Bor<strong>de</strong>rLayout<br />
Die Bor<strong>de</strong>rLayout-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 wer<strong>de</strong>n,<br />
geschieht das über e<strong>in</strong> spezielles Exemplar <strong>de</strong>r add()-Metho<strong>de</strong> ( mit e<strong>in</strong>em dieser<br />
fünf Bereichsnamen).<br />
Bsp.: Bor<strong>de</strong>rLayout-Applet, das e<strong>in</strong>em Applet e<strong>in</strong>ige Schaltfläche h<strong>in</strong>zufügt.<br />
Der Quellco<strong>de</strong> ist<br />
import java.awt.*;<br />
import java.applet.*;<br />
public class Bor<strong>de</strong>rLayoutTestApplet 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 Bor<strong>de</strong>rLayout());<br />
add("North",new Button("Schaltflaeche " + i++));<br />
add("South",new Button("Schaltflaeche " + i++));<br />
add("East", new Button("Schaltflaeche " + i++));<br />
341
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
add("West", new Button("Schaltflaeche " + i++));<br />
add("Center",new Button("Schaltflaeche " + i++));<br />
}<br />
}<br />
Für das Applet wur<strong>de</strong> folgen<strong>de</strong> Größe vere<strong>in</strong>bart:<br />
<br />
<br />
FlowLayout-Test<br />
<br />
<br />
<br />
<br />
<br />
<br />
Das führt zu <strong>de</strong>m folgen<strong>de</strong>n Layout:<br />
Die GridLayout-Klasse<br />
Diese Klasse teilt <strong>de</strong>n 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 wer<strong>de</strong>n von l<strong>in</strong>ks nach rechts angeordnet, begonnen<br />
wird bei <strong>de</strong>n l<strong>in</strong>ken, oberen Zellen.<br />
Bsp.: Plazieren von Schaltflächen<br />
Der folgen<strong>de</strong> Quellco<strong>de</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 folgen<strong>de</strong> Größe im Applet-Tag<br />
<br />
<br />
FlowLayout-Test<br />
<br />
<br />
<br />
<br />
<br />
<br />
zu <strong>de</strong>r folgen<strong>de</strong>n Darstellung<br />
342
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die GridBagLayout-Klasse und die GridBagConstra<strong>in</strong>t-Klasse<br />
Die Klasse GridBagLayout ermöglicht die Anordnung <strong>de</strong>r Komponenten <strong>in</strong> e<strong>in</strong>em<br />
rasterähnlichen Layout. Zusätzlich zum GridLayout kann kontrolliert wer<strong>de</strong>n: 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 <strong>de</strong>r Zellen im Raster. Zur<br />
Erstellung e<strong>in</strong>es GridLayout dienen zwei Klassen:<br />
- GridBagLayout, die <strong>de</strong>n Layoutmanager bereitstellt<br />
- GridBagConstra<strong>in</strong>ts, die die Eigenschaften je<strong>de</strong>r 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, <strong>de</strong>n 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 wer<strong>de</strong>n, wo die Komponente<br />
h<strong>in</strong>gestellt wer<strong>de</strong>n soll. Die GridBagConstra<strong>in</strong>t-Klasse besitzt verschie<strong>de</strong>ne<br />
Variable zur Steuerung <strong>de</strong>r Anordnung <strong>de</strong>r Komponenten:<br />
- die Variablen gridx und gridy (Koord<strong>in</strong>aten <strong>de</strong>r Zelle <strong>in</strong> <strong>de</strong>r die nächste Komponente plaziert<br />
wer<strong>de</strong>n soll). Die obere l<strong>in</strong>ke Ecke von GridBagLayout liegt bei (0,0), <strong>de</strong>r Standardwert ist<br />
GridBagConstra<strong>in</strong>ts.RELATIVE. Für gridx ist das die erste rechte Zelle neben <strong>de</strong>r letzten<br />
h<strong>in</strong>zugefügten Komponente. Für gridy ist es genau die Zelle, die unterhalb <strong>de</strong>r letzten<br />
Komponente h<strong>in</strong>zugefügt wur<strong>de</strong>.<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>ts.REMAINDER für<br />
gridwidth bestimmt, daß e<strong>in</strong>e Komponente die letzte <strong>in</strong> <strong>de</strong>r Spalte se<strong>in</strong> sollte.<br />
- Die Variable fill gibt an, welche Dimension e<strong>in</strong>er Komponente sich verän<strong>de</strong>rn soll, wenn e<strong>in</strong>e<br />
Komponente kle<strong>in</strong>er als <strong>de</strong>r Anzeigebereich ist. Gültige Werte s<strong>in</strong>d: NONE, BOTH, HORIZONTAL<br />
und VERTICAL. „GridBagConstra<strong>in</strong>ts.BOTH“ sorgt für e<strong>in</strong>e Streckung <strong>de</strong>r Komponenten <strong>in</strong><br />
bei<strong>de</strong>n Richtungen so, daß sie <strong>de</strong>n Anzeigebereich voll ausfüllen.<br />
- anchor wird e<strong>in</strong>gesetzt, wenn die Komponente kle<strong>in</strong>er als ihr Anzeigebereich ist. Sie zeigt an, wo<br />
die Komponente <strong>in</strong>nerhalb <strong>de</strong>s Anzeigebereichs plaziert wer<strong>de</strong>n soll. Der Standardwert ist<br />
„GridBagConstra<strong>in</strong>ts.CENTER“. Er gibt an, welche Komponente im „Zentrum <strong>de</strong>s<br />
Anzeigebereichs“ stehen soll. Die an<strong>de</strong>ren Komponenten s<strong>in</strong>d Kompasspunkte:<br />
GridBagConstra<strong>in</strong>ts.NORTH, GridBagConstra<strong>in</strong>ts.NORTHEAST etc.<br />
- Die Variable weightx und weighty <strong>de</strong>f<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 <strong>de</strong>r Komponenten. E<strong>in</strong> Komponente mit e<strong>in</strong>em Wert<br />
343
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 />
<strong>de</strong>m Wert 1.0 für weightx.<br />
- Durch „<strong>in</strong>sets“ (Objekte <strong>de</strong>r Klasse Insets) 277 wird <strong>de</strong>r freizuhalten<strong>de</strong> Rand zwischen<br />
Komponente 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 wer<strong>de</strong>n. Die Pixel, die rechts und l<strong>in</strong>ks zuzufügen<br />
s<strong>in</strong>d, gibt ipadx an. Wieviel oben und unten h<strong>in</strong>zukommt, speichert ipady. (ipadx, ipady s<strong>in</strong>d<br />
standardmäßig 0).<br />
gridwidth<br />
ipady<br />
<strong>in</strong>sets<br />
ipadx<br />
fill<br />
gridheight<br />
Bsp. 278 : 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> <strong>de</strong>r Zeile:<br />
c.gridwidth = GridBagConstra<strong>in</strong>ts.REMAINDER;<br />
macheSchalter("Schaltflaeche4", gridbag, c);<br />
// neue Zeile, weightx wie<strong>de</strong>rherstellen:<br />
c.weightx = 0.0;<br />
macheSchalter("Schaltflaeche5", gridbag, c);<br />
// vorletztes Element <strong>de</strong>r 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 />
277 Beim Erstellen e<strong>in</strong>es neuen Layout-Managers erzeugte horizontale und vertikale Abstän<strong>de</strong> dienen zur<br />
Bestimmung <strong>de</strong>s Platzes zwischen Komponenten <strong>in</strong> e<strong>in</strong>em Panel. Die Klasse Insets bietet Ecke<strong>in</strong>setzwerte für<br />
oben, unten, l<strong>in</strong>ks und rechts an, die dann verwen<strong>de</strong>t wer<strong>de</strong>n, wenn das Panel gezeichnet wird.<br />
278 vgl. pr54205<br />
344
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
// neue Zeile, Wert wie<strong>de</strong>rherstellen:<br />
c.gridwidth = 1;<br />
c.gridheight = 2;<br />
c.weighty = 1.0;<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 />
CardLayout 279 plaziert die Elemente auf sich gegenseitig ver<strong>de</strong>cken<strong>de</strong> Karten.<br />
Jeweils e<strong>in</strong>e dieser Karten kann sichtbar gemacht wer<strong>de</strong>n.<br />
Das Null-Layout<br />
E<strong>in</strong> Aufruf <strong>de</strong>r Metho<strong>de</strong> „setLayout“ mit <strong>de</strong>m Argument null erzeugt e<strong>in</strong> Null-<br />
Layout. In diesem Fall verwen<strong>de</strong>t das Fenster ke<strong>in</strong>en Layoutmanager, son<strong>de</strong>rn<br />
überläßt die Positionierung <strong>de</strong>r Komponenten <strong>de</strong>r Anwendung. Je Komponente s<strong>in</strong>d<br />
drei Schritte auszuführen<br />
- Erzeugen <strong>de</strong>r Komponente<br />
- Festlegung von Größe und Position <strong>de</strong>r Komponente<br />
- Übergabe <strong>de</strong>r Komponente an das Fenster.<br />
Größe und Position <strong>de</strong>s 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 />
279 Das CardLayout ist als Notizbuchersatz durch die E<strong>in</strong>führung <strong>de</strong>r Klasse JTabbedPane <strong>in</strong> Sw<strong>in</strong>g fast<br />
überflüssig gewor<strong>de</strong>n<br />
345
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
festgelegt wer<strong>de</strong>n. Der Punkt (x,y) bestimmt die Anfangsposition und<br />
(breite,hoehe) die Größe.<br />
Bsp.:<br />
import java.awt.*;<br />
import java.awt.event.*;<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 />
346
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.5 Die Event-Mo<strong>de</strong>lle 1.0 und 1.1<br />
5.5.1 Der AWT-Handler 1.0<br />
Die Metho<strong>de</strong> handleEvent<br />
Die handleEvent()-Metho<strong>de</strong> 280 ist unter <strong>de</strong>m AWT-Event-Handler die allgeme<strong>in</strong>ste<br />
Art, wie das AWT auf irgendwelche Ereignisse e<strong>in</strong>geht, die auf <strong>de</strong>r<br />
Benutzeroberfläche stattf<strong>in</strong><strong>de</strong>n. Ereignisse wer<strong>de</strong>n <strong>in</strong>nerhalb <strong>de</strong>r handleEvent()-<br />
Metho<strong>de</strong> <strong>in</strong>terpretiert und dann gezielt passen<strong>de</strong> Metho<strong>de</strong>n 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“ <strong>de</strong>r Klasse<br />
Event enthält die Art <strong>de</strong>s 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 />
// Metho<strong>de</strong>n<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 />
}<br />
280 Die Metho<strong>de</strong> ist <strong>in</strong> <strong>de</strong>r Klasse Component <strong>de</strong>f<strong>in</strong>iert, von <strong>de</strong>r die Klasse java.applet.Applet<br />
abgeleitet ist. Dadurch steht die Metho<strong>de</strong> allen Applets zur Verfügung,<br />
347
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
catch (IOException e) { }<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.hi<strong>de</strong>();<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 wer<strong>de</strong>n über public boolean action(Event e, Object<br />
arg) behan<strong>de</strong>lt. Zuerst muß <strong>in</strong>nerhalb <strong>de</strong>r metho<strong>de</strong> überprüft wer<strong>de</strong>n, welche<br />
Komponente <strong>de</strong>r 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 <strong>de</strong>m Objekt, das das<br />
Ereignis aufgenommen hat, enthält. Mit <strong>de</strong>m <strong>in</strong>stanceof-Operator kann dann<br />
bestimmt wer<strong>de</strong>n, von welcher Komponente das Ereignis ausg<strong>in</strong>g. Das zweite<br />
Argument dient zum Bestimmen <strong>de</strong>s Labels 281 , <strong>de</strong>r Elemente, <strong>de</strong>s Inhalts <strong>de</strong>r<br />
Komponenten 282 . Anstatt <strong>de</strong>s zusätzlichen Arguments kann auch die Metho<strong>de</strong> 283<br />
getLabel verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Behandlung von Fokus-Ereignissen<br />
Für die Ereignisse "Fokuserhalt" und "Fokusverlust" können die Metho<strong>de</strong>n<br />
281 vgl. pr52105<br />
282 Nicht vergessen: Das Argument <strong>in</strong> <strong>de</strong>n richtigen Objekt-Typ zu casten<br />
283 vgl. pr54305<br />
348
<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 />
verwen<strong>de</strong>t wer<strong>de</strong>n.<br />
Ereignisse von Listenfel<strong>de</strong>rn<br />
Listenfel<strong>de</strong>r erzeugen drei verschie<strong>de</strong>ne Ereignisarten: Auswahl bzw. Abwahl e<strong>in</strong>es<br />
E<strong>in</strong>trags <strong>in</strong> <strong>de</strong>r 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 <strong>de</strong>r Metho<strong>de</strong> action bearbeitet wer<strong>de</strong>n. Auswahl und Abwahl e<strong>in</strong>es<br />
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 Ereignismo<strong>de</strong>ll erben die Ereignisklassen von <strong>de</strong>r Klasse<br />
java.util.EventObject. AWT-Events erben von <strong>de</strong>r Klasse<br />
java.awt.AWTEvent.<br />
EventListener<br />
Falls e<strong>in</strong>e Klasse im Ereignisbehandlungsmo<strong>de</strong>ll 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 wer<strong>de</strong>n als EventListener bezeichnet. Je<strong>de</strong>r<br />
Listener behan<strong>de</strong>lt e<strong>in</strong>e bestimmte Ereignisart. E<strong>in</strong>e Klasse kann so viele<br />
Listener implementieren, wie benötigt wer<strong>de</strong>n. Die folgen<strong>de</strong>n EventListener<br />
stehen zur Verfügung:<br />
ActionListener<br />
Aktionsereignisse, die durch <strong>de</strong>n Benutzer ausgelöst wer<strong>de</strong>n, z.B.<br />
Klick auf e<strong>in</strong>e Schaltfläche<br />
AdjustmentListener<br />
Ereignisse, die erzeugt wer<strong>de</strong>n, wenn werte e<strong>in</strong>er Komponente<br />
e<strong>in</strong>gestellt wer<strong>de</strong>n (z.B. Bewegung e<strong>in</strong>es Schiebers e<strong>in</strong>er<br />
Bildlaufleiste)<br />
FocusListener<br />
Ereignisse, die erzeugt wer<strong>de</strong>n, wenn e<strong>in</strong>e Komponente, z.B. e<strong>in</strong><br />
textfeld, <strong>de</strong>n e<strong>in</strong>gabefokus erhält o<strong>de</strong>r verliert.<br />
ItemListener<br />
Ereignisse, die erzeugt wer<strong>de</strong>n, wenn e<strong>in</strong> Element, z.B. e<strong>in</strong><br />
Kontrollkästchen, verän<strong>de</strong>rt wur<strong>de</strong><br />
KeyListener<br />
Tastaturereignisse, die bei Tastature<strong>in</strong>gaben erzeugt wer<strong>de</strong>n.<br />
MouseListener<br />
Mausereignisse, die erzeugt wer<strong>de</strong>n, wenn mit <strong>de</strong>r maus geklickt<br />
wird, die Maus <strong>in</strong> <strong>de</strong>n Bereich e<strong>in</strong>er Komponente e<strong>in</strong>tritt bzw. diese<br />
wie<strong>de</strong>r 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<br />
Ereignisse, die von Fenstern erzeugt wer<strong>de</strong>n<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 />
349
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Event-Handl<strong>in</strong>g mit Hilfe lokaler Klasse<br />
Für die Ereignisbehandlung wer<strong>de</strong>n lokale Klassen herangezogen. Im JDK 1.0<br />
wur<strong>de</strong>n Klassen nur auf Paketen <strong>de</strong>f<strong>in</strong>iert, e<strong>in</strong>e Schachtelung war nicht möglich. Im<br />
JDK 1.1 kann <strong>in</strong>nerhalb bestehen<strong>de</strong>r Klassen e<strong>in</strong>e neue Klasse <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n<br />
(Konzept <strong>de</strong>r „Inner Classes“), die nur <strong>in</strong>nerhalb <strong>de</strong>r bestehen<strong>de</strong>n Klasse sichtbar ist.<br />
Objekt<strong>in</strong>stanzen <strong>de</strong>r <strong>in</strong>neren Klasse können nur aus <strong>de</strong>r umfassen<strong>de</strong>n Klasse heraus<br />
erzeugt wer<strong>de</strong>n. Allerd<strong>in</strong>gs kann die <strong>in</strong>nere Klasse auf die Instanzvariablen <strong>de</strong>r<br />
äußeren Klasse zugreifen.<br />
Mit Hilfe lokaler Klassen wer<strong>de</strong>n die benötigten EventListener implementiert. Dazu<br />
wird <strong>in</strong> <strong>de</strong>m GUI-Objekt, das e<strong>in</strong>en Event-Handler benötigt, e<strong>in</strong>e lokale Klasse<br />
<strong>de</strong>f<strong>in</strong>iert (und aus e<strong>in</strong>er passen<strong>de</strong>n AdapterKlasse abgeleitet).<br />
E<strong>in</strong> e<strong>in</strong>führen<strong>de</strong>s Bsp.: Event-Handl<strong>in</strong>g nach <strong>de</strong>r Bearbeitung von Schaltflächen <strong>de</strong>s<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 />
350
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
*/<br />
}<br />
E<strong>in</strong>fügen / Entfernen passen<strong>de</strong>r Listener<br />
Das neue Event-Mo<strong>de</strong>ll von <strong>Java</strong> 1.1 bzw. 1.2 hat mit <strong>de</strong>m 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()“-Metho<strong>de</strong>n<br />
erhalten. „XXX“ beschreibt <strong>de</strong>n Typ <strong>de</strong>s Events. Die folgen<strong>de</strong> Tabelle zeigt<br />
Ereignisse, „Listeners“, Metho<strong>de</strong>n und Komponenten, die über addXXXListener()<br />
bzw. removeXXXListener() auf spezifische Ereignisse reagieren:<br />
Event, „listener <strong>in</strong>terface“ und „add“- bzw.<br />
„remove“-Metho<strong>de</strong>n<br />
ActionEvent<br />
ActionListener<br />
addActionListener()<br />
removeActionListener()<br />
AdjustmentEvent<br />
AdjustmentListener<br />
addAdjustmentListener()<br />
removeAdjustmentListener()<br />
ComponentEvent<br />
ComponentListener<br />
addComponentListener()<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 />
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 <strong>de</strong>r 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,<br />
TextArea, TextField<br />
Conta<strong>in</strong>er und se<strong>in</strong>e Abkömml<strong>in</strong>ge, e<strong>in</strong>schl.<br />
Panel, Applet, ScrollPane, W<strong>in</strong>dow, Dialog,<br />
FileDialog, 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, Frame,<br />
Label, 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,<br />
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,<br />
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,<br />
TextArea, 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 />
351
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
TextEvent<br />
TextListener<br />
addTextListener()<br />
removeTextListener()<br />
Alles was von TextComponent e<strong>in</strong>schl. TextArea<br />
und TextField abgeleitet ist<br />
Abb.: Event- und Listener-Typen<br />
Je<strong>de</strong>r Komponenten-Typ unterstützt nur bestimmte Ereignis-Typen:<br />
Komponenten-Typ<br />
Ereignis, das durch die Komponente unterstützt<br />
wird<br />
Adjustable<br />
AdjustmentEvent<br />
Applet Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />
MouseEvent, ComponentEvent<br />
Button<br />
ActionEvent,<br />
Canvas FocusEvent, KeyEvent, MouseEvent,<br />
ComponentEvent<br />
Checkbox<br />
ItemEvent, FocusEvent, KeyEvent, MouseEvent,<br />
ComponentEvent<br />
CheckboxMenuItem<br />
ActionEvent, ItemEvent<br />
Choice<br />
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,<br />
MouseEvent, ItemEvent, ComponentEvent<br />
Menu<br />
ActionEvent<br />
MenuItem<br />
ActionEvent<br />
Panel Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />
MouseEvent, ComponentEvent<br />
PopupMenu<br />
ActionEvent<br />
Scrollbar AdjustmentEvent, FocusEvent, KeyEvent,<br />
MouseEvent, ComponentEvent<br />
ScrollPane Conta<strong>in</strong>erEvent, FocusEvent, KeyEvent,<br />
MouseEvent, ComponentEvent<br />
TextArea<br />
TextEvent, FocusEvent, KeyEvent, MouseEvent,<br />
ComponentEvent<br />
TextComponent<br />
TextEvent, FocusEvent, KeyEvent, MouseEvent,<br />
TextField<br />
ComponentEvent<br />
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 />
Metho<strong>de</strong>n für die Ereignisbehandlung<br />
352
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Da nun bekannt ist, welche Ereignisse e<strong>in</strong>e bestimmte Komponente unterstützt, kann<br />
das zugehörige „Listener“-Interface angegeben wer<strong>de</strong>n:<br />
„Listener“-Interface<br />
ActionListener<br />
AdjustmentListener<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 />
MouseMotionListener<br />
MouseMotionAdapter<br />
W<strong>in</strong>dowListener<br />
W<strong>in</strong>dowadapter<br />
ItemListener<br />
TextListener<br />
Metho<strong>de</strong>n<br />
actionPerformed(ActionEvent)<br />
AdjustmentValueChanged(<br />
AdjustmentEvent)<br />
componentHid<strong>de</strong>n(ComponentEvent)<br />
componentShown(ComponentEvent)<br />
componentMoved(ComponentEvent)<br />
componentResized(ComponentEvent)<br />
componentAd<strong>de</strong>d(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 />
mouseMoved(MouseEvent)<br />
w<strong>in</strong>dowOpened(W<strong>in</strong>dowEvent)<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 />
itemStateChanged(ItemEvent)<br />
textValueChanged(TextEvent)<br />
Abb.: Listener-Interface<br />
Adapter besorgen Default-Metho<strong>de</strong>n für je<strong>de</strong> Metho<strong>de</strong> im Interface. Nur die Metho<strong>de</strong>,<br />
die geän<strong>de</strong>rt wird, muß überschrieben wer<strong>de</strong>n.<br />
Komponenten <strong>de</strong>s AWT <strong>in</strong> Fenstern bzw. Applets unter <strong>Java</strong> 1.1<br />
Die <strong>in</strong> <strong>de</strong>n folgen<strong>de</strong>n Programmen verwen<strong>de</strong>ten Komponenten können <strong>in</strong> e<strong>in</strong>em<br />
Fenster (Frame) über die Instanz e<strong>in</strong>es Applet dargestellt wer<strong>de</strong>n. Das Programm<br />
enthält <strong>de</strong>shalb zusätzlich zu <strong>de</strong>n für Applets nötigen Metho<strong>de</strong>n e<strong>in</strong>e ma<strong>in</strong>()-<br />
Metho<strong>de</strong>, die e<strong>in</strong>e Instanz e<strong>in</strong>es Applets <strong>in</strong>nerhalb e<strong>in</strong>es Frame aufbaut.<br />
Bsp.: Bearbeitung von zwei Schaltflächen und e<strong>in</strong>em Textfeld 284<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 />
284 pr55202<br />
353
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 <strong>de</strong>r 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 />
{ System.exit(0); }<br />
}<br />
// ma<strong>in</strong>()-Metho<strong>de</strong> 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,Bor<strong>de</strong>rLayout.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 />
354
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6 Benutzerschnittstellen mit Sw<strong>in</strong>g<br />
Die Oberflächentechnik „Sw<strong>in</strong>g“ (Paket: javax.sw<strong>in</strong>g) von <strong>Java</strong> 2 umfaßt e<strong>in</strong>e<br />
Vielzahl mächtiger Klassen (, z.B. Tabellen, Baumansichten). Sw<strong>in</strong>g benutzt <strong>de</strong>n<br />
Mo<strong>de</strong>l-View-Controller 285 -Ansatz, d.h. die konsequente Trennung <strong>de</strong>r Daten und <strong>de</strong>r<br />
Darstellung. Sw<strong>in</strong>g-Elemente fallen <strong>in</strong> zwei Gruppen:<br />
- Fenster, die direkt vom Betriebssystem dargestellt wer<strong>de</strong>n, z.B. JFrame, JDialog o<strong>de</strong>r JApplet.<br />
Diese s<strong>in</strong>d von <strong>de</strong>n jeweiligen AWT-Komponenten abgeleitet.<br />
- Kontrollelemente, die von <strong>Java</strong> selbst geren<strong>de</strong>rt wer<strong>de</strong>n. Diese s<strong>in</strong>d Subklassen von JComponent.<br />
javax.sw<strong>in</strong>g, javax.sw<strong>in</strong>g.event, javax.sw<strong>in</strong>g.table, javax.sw<strong>in</strong>g.tree, javax.sw<strong>in</strong>g.text<br />
Interfaces<br />
Klassen<br />
- ButtonMo<strong>de</strong>l Ereignis- Kontroll- Fenster Menüs<br />
- ComboBoxMo<strong>de</strong>l behandlung Elemente<br />
- ListMo<strong>de</strong>l<br />
- TreeMo<strong>de</strong>l<br />
- TableMo<strong>de</strong>l<br />
- TableColumnMo<strong>de</strong>l<br />
- Boun<strong>de</strong>dRangeMo<strong>de</strong>l<br />
- Ren<strong>de</strong>rer<br />
- ListCellRen<strong>de</strong>rer<br />
- TableCellRen<strong>de</strong>rer<br />
- TableCellEditor<br />
- TreeCellRen<strong>de</strong>rer<br />
- TreeCellEditor<br />
- ComboBoxEditor<br />
- TreeNo<strong>de</strong><br />
- MutableTreeNo<strong>de</strong><br />
- Bor<strong>de</strong>r<br />
- Scrollable<br />
- MenuElement<br />
- Document<br />
- ListDataEvent<br />
- ListSelectionEvent<br />
- TableMo<strong>de</strong>lEvent<br />
- TreeMo<strong>de</strong>lEvent<br />
- TreeExpansionEvent<br />
- TreeSelectionEvent<br />
- CaretEvent<br />
- MenuEvent<br />
- PopupMenuEvent<br />
- JComponent<br />
- JButton<br />
- JCheckBox<br />
- JRadioButton<br />
- JLabel<br />
- JTextField<br />
- JPasswordField<br />
- JTextArea<br />
- JComboBox<br />
- JList<br />
- JScrollBar<br />
- JSli<strong>de</strong>r<br />
- JProgressBar<br />
- JTree<br />
- JTable<br />
- JFrame<br />
- JDialog<br />
- JPanel<br />
- JApplet<br />
- JFileChooser<br />
- JColorChooser<br />
- JDesktopPane<br />
- JInternalFrame<br />
- JOptionPane<br />
- JScrollPane<br />
- JTabbedPane<br />
- JMenuBar<br />
- JMenuItem<br />
- JCheckbox-<br />
MenuItem<br />
- JRadioBox-<br />
MenuItem<br />
- JMenu<br />
- JPopupMenu<br />
- JToolBar<br />
- JSeparator<br />
- Caret Mo<strong>de</strong>l- Bor<strong>de</strong>r Bil<strong>de</strong>r Sonstiges<br />
- Style implementierung<br />
- StyledDocument<br />
- DesktopManager - AbstractListMo<strong>de</strong>l - Bor<strong>de</strong>rFactory - ...... - ImageIcon<br />
- Icon - DefaultListMo<strong>de</strong>l - TitledBor<strong>de</strong>r -ButtonGroup<br />
- Sw<strong>in</strong>gConstants - AbstractTableMo<strong>de</strong>l - L<strong>in</strong>eBor<strong>de</strong>r - KeyStroke<br />
- *Listener - ... - ... - ...<br />
285 Beim Mo<strong>de</strong>l-View-Controller-Entwurfsmuster (MVC) unterschei<strong>de</strong>t man drei Arten von<br />
Applikationselementen:<br />
Mo<strong>de</strong>l (Datenmo<strong>de</strong>ll)<br />
Im Datenmo<strong>de</strong>ll wer<strong>de</strong>n Zustand und Funktionalität gespeichert. Es kann Anfragen vom View über se<strong>in</strong>en<br />
Zustand beantworten und Zustandsän<strong>de</strong>rungen vom Controller o<strong>de</strong>r an<strong>de</strong>ren Objekten verarbeiten.<br />
View (Darstellung „look“)<br />
Die Ansicht weiß nichts o<strong>de</strong>r nur sehr wenig (über das Datenmo<strong>de</strong>ll und stellt lediglich die Daten dar).<br />
Controller (Steuerung „feel“)<br />
Die Steuerung stellt e<strong>in</strong> Mo<strong>de</strong>ll <strong>de</strong>r realen Welt dar und reagiert auf Benutzere<strong>in</strong>gaben von Maus, Tastatur und<br />
an<strong>de</strong>ren E<strong>in</strong>gabegeräten.<br />
355
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.1 Die Komponentenstruktur<br />
javax.sw<strong>in</strong>g.JComponent ist von java.awt.Conta<strong>in</strong>er abgeleitet. Als<br />
Conta<strong>in</strong>er können alle JComponents auch an<strong>de</strong>re Komponenten enthalten.<br />
Conta<strong>in</strong>er<br />
JComponent<br />
public void addAncestorListener(AncestorListener l)<br />
public void addNotify()<br />
...<br />
public boolean conta<strong>in</strong>s(<strong>in</strong>t x, <strong>in</strong>t y)<br />
public JToolTip createToolTip()<br />
...<br />
public float getAlignmentX()<br />
public float getAlignmentY()<br />
...<br />
public Bor<strong>de</strong>r getBor<strong>de</strong>r()<br />
public void setBor<strong>de</strong>r(Bor<strong>de</strong>r bor<strong>de</strong>r)<br />
public Rectangle getBounds(Rectangle rv)<br />
protected Graphics getComponentGraphics (Graphics g)<br />
...<br />
public Graphics getGraphics()<br />
public <strong>in</strong>t getHeight()<br />
public Insets getInsets()<br />
...<br />
public Po<strong>in</strong>t getLocation(Po<strong>in</strong>t rv)<br />
public Dimension getMaximumSize()<br />
public Dimension getM<strong>in</strong>imumSize()<br />
...<br />
…<br />
public Dimension getSize(Dimension rv)<br />
public Po<strong>in</strong>t getToolTipLocation(MouseEvent event)<br />
public Str<strong>in</strong>g getToolTipText()<br />
public Str<strong>in</strong>g getToolTipText(MouseEvent event)<br />
...<br />
public <strong>in</strong>t getWidth()<br />
public <strong>in</strong>t getX()<br />
public <strong>in</strong>t getY()<br />
...<br />
public void pa<strong>in</strong>t(Graphics g)<br />
...<br />
public void repa<strong>in</strong>t(Rectangle r)<br />
...<br />
public void setToolTipText(Str<strong>in</strong>g text)<br />
protected void setUI(ComponentUI newUI)<br />
public void setVisible(boolean aFlag)<br />
...<br />
public void update(Graphics g)<br />
public void updateUI()<br />
…<br />
Abb. Die Klasse JComponent<br />
356
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Viele <strong>de</strong>r Sw<strong>in</strong>g-Komponenten s<strong>in</strong>d direkt o<strong>de</strong>r <strong>in</strong>direkt aus <strong>de</strong>r Klasse JComponent<br />
abgeleitet<br />
Instanzen von JComponent können ausgestattet wer<strong>de</strong>n mit Umrandungen,<br />
Tooltips, transparentem H<strong>in</strong>tergrund, Doppelpufferung, etc.<br />
Umrandungen<br />
Instanzen von JComponent können über die Metho<strong>de</strong> setBor<strong>de</strong>r() Umrandungen<br />
erhalten.<br />
public void setBor<strong>de</strong>r(Bor<strong>de</strong>r bor<strong>de</strong>r)<br />
Bor<strong>de</strong>r ist e<strong>in</strong> Interface, zu <strong>de</strong>m es verschie<strong>de</strong>ne Implementierungen gibt. Die<br />
wichtigsten s<strong>in</strong>d:<br />
Klassenname<br />
EmptyBor<strong>de</strong>r<br />
L<strong>in</strong>eBor<strong>de</strong>r<br />
BevelBor<strong>de</strong>r<br />
EtchedBor<strong>de</strong>r<br />
CompoundBor<strong>de</strong>r<br />
TitledBor<strong>de</strong>r<br />
Beschreibung<br />
Unsichtbarer Rand mit e<strong>in</strong>stellbarer Dicke<br />
E<strong>in</strong>fache L<strong>in</strong>ie mit e<strong>in</strong>stellbarer Farbe und Dicke<br />
Erhabener und vertiefter 3D-Effekt<br />
E<strong>in</strong>gelassene L<strong>in</strong>e mit 3D-Effekt<br />
Aus 2 an<strong>de</strong>ren Umrandungen zusammengesetzt<br />
Umrandung mit e<strong>in</strong>em e<strong>in</strong>geketteten Text<br />
Abb.: Bor<strong>de</strong>r-Implementierungen<br />
Die Klassen besitzen sehr unterschiedliche Konstruktoren, mit <strong>de</strong>nen ihre jeweiligen<br />
Eigenschaften festgelegt wer<strong>de</strong>n. Bor<strong>de</strong>r-Instanzen können mit new über die Klasse<br />
Bor<strong>de</strong>rFactory mit <strong>de</strong>n Metho<strong>de</strong>n createEmptyBor<strong>de</strong>r(),<br />
createL<strong>in</strong>eBor<strong>de</strong>r(), usw. erzeugt wer<strong>de</strong>n.<br />
Bsp. 286 :<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
import javax.sw<strong>in</strong>g.bor<strong>de</strong>r.*;<br />
public class Raen<strong>de</strong>r extends JPanel<br />
{<br />
public Raen<strong>de</strong>r()<br />
{<br />
setLayout(new GridLayout(2,4));<br />
add(showBor<strong>de</strong>r(new TitledBor<strong>de</strong>r("Titel")));<br />
add(showBor<strong>de</strong>r(new EtchedBor<strong>de</strong>r()));<br />
add(showBor<strong>de</strong>r(new L<strong>in</strong>eBor<strong>de</strong>r(Color.blue)));<br />
add(showBor<strong>de</strong>r(new MatteBor<strong>de</strong>r(5,5,30,30,Color.green)));<br />
add(showBor<strong>de</strong>r(new BevelBor<strong>de</strong>r(BevelBor<strong>de</strong>r.RAISED)));<br />
add(showBor<strong>de</strong>r(new SoftBevelBor<strong>de</strong>r(BevelBor<strong>de</strong>r.LOWERED)));<br />
add(showBor<strong>de</strong>r(new CompoundBor<strong>de</strong>r(new EtchedBor<strong>de</strong>r(),<br />
new L<strong>in</strong>eBor<strong>de</strong>r(Color.red))));<br />
}<br />
static JPanel showBor<strong>de</strong>r(Bor<strong>de</strong>r b)<br />
{<br />
JPanel jp = new JPanel();<br />
jp.setLayout(new Bor<strong>de</strong>rLayout());<br />
Str<strong>in</strong>g nm = b.getClass().toStr<strong>in</strong>g();<br />
nm = nm.substr<strong>in</strong>g(nm.lastIn<strong>de</strong>xOf('.')+1);<br />
jp.add(new JLabel(nm,JLabel.CENTER),Bor<strong>de</strong>rLayout.CENTER);<br />
286 pr56001<br />
357
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
jp.setBor<strong>de</strong>r(b);<br />
return jp;<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
JFrame frame = new JFrame("Begrenzungen");<br />
// frame.addW<strong>in</strong>dowListener(new W<strong>in</strong>dowClos<strong>in</strong>gAdapter(true));<br />
frame.getContentPane().add(new Raen<strong>de</strong>r(),Bor<strong>de</strong>rLayout.CENTER);<br />
frame.setLocation(100,100);<br />
frame.setSize(500,300);<br />
frame.pack();<br />
/* Die Metho<strong>de</strong> pack() sorgt fuer die Reduzierung <strong>de</strong>r<br />
Groesse <strong>de</strong>s Frame, dass alle Komponenten gera<strong>de</strong> dar<strong>in</strong><br />
noch Platz f<strong>in</strong><strong>de</strong>n<br />
*/<br />
frame.setVisible(true);<br />
/* Macht <strong>de</strong>n Frame sichtbar */<br />
}<br />
}<br />
Abb.<br />
Tooltips<br />
JComponent kann Komponenten e<strong>in</strong> Tooltip-Text zuweisen. Dieser wird angezeigt,<br />
wenn die Maus über das Dialogelement bewegt und dort angehalten wird. Tooltip-<br />
Texte wer<strong>de</strong>n mit setToolTipText() zugewiesen bzw. mit getToolTipText()<br />
abgefragt:<br />
public void setToolTipText(Str<strong>in</strong>g text)<br />
public void getToolTipText()<br />
Das Fenster mit <strong>de</strong>m Hilfetext ist immer im Sw<strong>in</strong>g-Fenster und nie außerhalb. Passt<br />
die Hilfe nicht auf das Fenster wird sie gar nicht dargestellt, und die Komponente<br />
macht durch "Flackern" auf sie aufmerksam<br />
Bsp. 287 :<br />
import java.awt.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class TooltipDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
JFrame frame = new JFrame();<br />
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
Str<strong>in</strong>g text = "Ich brauche Hilfe.Tempo";<br />
JButton button = new JButton(text);<br />
Str<strong>in</strong>g hilfe = "Hier ist sie, die Hilfe:" +<br />
"Cool bleibenHandbuch lesen";<br />
287 pr56001<br />
358
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
button.setToolTipText(hilfe);<br />
frame.getContentPane().add(button);<br />
frame.setSize(250, 250);<br />
frame.show();<br />
}<br />
}<br />
Abb.: Tooltip-Demonstration<br />
Bildschirmdarstellung <strong>de</strong>r Komponenten<br />
Normalerweise braucht e<strong>in</strong>e GUI-Anwendung sich um die konkrete Darstellung nicht<br />
zu kümmern. Das än<strong>de</strong>rt sich, wenn e<strong>in</strong>e eigene Komponente entwickelt wer<strong>de</strong>n soll.<br />
Bei AWT-Anwendungen wur<strong>de</strong> dies aus Canvas abgeleitet, <strong>in</strong> überlagerten Varianten<br />
von pa<strong>in</strong>t() o<strong>de</strong>r update() wur<strong>de</strong> die nötige Bildschirmausgabe bereit gestellt.<br />
Die Metho<strong>de</strong> pa<strong>in</strong>t() hat <strong>in</strong> JComponent e<strong>in</strong>e recht aufwendige Implementierung<br />
und wird normalerweise nicht mehr überlagert. Im Pr<strong>in</strong>zip ruft sie nache<strong>in</strong>an<strong>de</strong>r ihre<br />
Metho<strong>de</strong>n pa<strong>in</strong>tComponent(), pa<strong>in</strong>tBor<strong>de</strong>r() (Zeichnen <strong>de</strong>r Umrandung) und<br />
pa<strong>in</strong>tChildren() (Zeichnen <strong>de</strong>r Dialogelemente) auf. Für die Darstellung <strong>de</strong>r<br />
eigenen Komponenten ist<br />
protected void pa<strong>in</strong>tComponent(Graphics g)<br />
zuständig. In JComponent wird je<strong>de</strong>r Aufruf von pa<strong>in</strong>tComponent() an das<br />
ComponentUI <strong>de</strong>legiert. Je<strong>de</strong> Sw<strong>in</strong>g-Komponente besitzt e<strong>in</strong> ComponentUI, das je<br />
Look and Feel unterschiedlich se<strong>in</strong> kann. E<strong>in</strong>e selbst<strong>de</strong>f<strong>in</strong>ierte Komponente muß also<br />
entwe<strong>de</strong>r für je<strong>de</strong>s Look and Feel e<strong>in</strong> passen<strong>de</strong>s ComponentUI zur Verfügung<br />
stellen o<strong>de</strong>r die Bildschirmdarstellung durch Überlagern von pa<strong>in</strong>tComponent()<br />
selbst erledigen.<br />
Doppelpufferung<br />
Sw<strong>in</strong>g-Komponenten, die aus JComponent abgeleitet s<strong>in</strong>d, können automatisch<br />
doppelgepuffert wer<strong>de</strong>n. Dazu ist lediglich <strong>de</strong>r Aufruf von<br />
public void setDoubleBuffered(boolean e<strong>in</strong>Flag)<br />
mit Übergabe von "true" erfor<strong>de</strong>rlich. Mit<br />
359
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public boolean isDoubleBuffered()<br />
kann <strong>de</strong>r aktuelle Zustand abgefragt wer<strong>de</strong>n.<br />
Größenangaben<br />
In <strong>de</strong>r Klasse Component s<strong>in</strong>d die Metho<strong>de</strong>n getM<strong>in</strong>imumSize(),<br />
getPreferredSize(), getMaximumSize() <strong>de</strong>f<strong>in</strong>iert. Sie wer<strong>de</strong>n <strong>in</strong> abgeleiteten<br />
Klassen überlagert, um <strong>de</strong>m Layoutmanager die m<strong>in</strong>imale, optimale, maximale<br />
Größe mitzuteilen. In JComponent gibt es zusätzlich<br />
public void setM<strong>in</strong>imumSize(Dimension m<strong>in</strong>imumSize)<br />
public void setPreferredSize(Dimension preferredSize)<br />
public void setMaximumSize(Dimension maximumSize)<br />
zur Verän<strong>de</strong>rung <strong>de</strong>r Größenangaben bestehen<strong>de</strong>r Komponenten.<br />
Invalidierung / Validierung<br />
Zur Mitteilung an <strong>de</strong>n Conta<strong>in</strong>er, dass das Layout se<strong>in</strong>er Komponenten komplett<br />
aufgebaut wer<strong>de</strong>n soll, ist validate() aufzurufen.<br />
public void validate()<br />
Zuvor muß <strong>de</strong>r Conta<strong>in</strong>er, auf <strong>de</strong>m <strong>de</strong>r Aufruf erfolgte, zuvor mit<br />
public void <strong>in</strong>validate()<br />
als ungültig <strong>de</strong>klariert se<strong>in</strong>.<br />
In JComponent gibt es zusätzlich revalidate(), das die bei<strong>de</strong>n Schritte<br />
nache<strong>in</strong>an<strong>de</strong>r durchführt.<br />
360
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.2 Fenster<br />
Conta<strong>in</strong>er<br />
W<strong>in</strong>dow<br />
JComponent<br />
Frame<br />
Dialog<br />
JFrame<br />
JDialog<br />
Conta<strong>in</strong>er contentPane<br />
Int <strong>de</strong>faultCloseOperation<br />
> ><br />
public JFrame()<br />
public JDialog()<br />
public JFrame(Str<strong>in</strong>g titel)<br />
Abb.: Die Klassen JFrame und JDialog<br />
Die Sw<strong>in</strong>g-Klassen für Hauptfenster (JFrame) und Dialogboxen (JDialog) s<strong>in</strong>d<br />
direkt von <strong>de</strong>n AWT-Klassen Frame und Dialog abgeleitet und erben all ihre<br />
Metho<strong>de</strong>n. Der Hauptunterschied ist, daß ke<strong>in</strong>e Kontrollelemente mehr direkt auf das<br />
Fenster platziert wer<strong>de</strong>n, son<strong>de</strong>rn auf e<strong>in</strong>en Client-Conta<strong>in</strong>er (mit <strong>de</strong>m Namen<br />
„ContentPane“). Nun können bei<strong>de</strong> Klassen Menüleisten aufnehmen (Typ<br />
JMenuBar) und besitzen Vorgaben beim Schließen e<strong>in</strong>es Fensters.<br />
5.6.2.1 JFrame<br />
class javax.sw<strong>in</strong>g.Jframe extends Frame implements W<strong>in</strong>dowConstants,<br />
Accessible, RootPaneConta<strong>in</strong>er<br />
JFrame dient für <strong>de</strong>n Ersatz <strong>de</strong>r schwergewichtigen Komponente Frame und ist<br />
Ausgangsbasis für die meisten Sw<strong>in</strong>g-Oberflächen. Die Klasse JFrame erbt die<br />
wichtigsten Metho<strong>de</strong>n zum Adm<strong>in</strong>istrieren von Rahmen von ihren Vorgängern. Die<br />
wichtigste Metho<strong>de</strong> ist die von Component geerbte Metho<strong>de</strong> setVisible(true)<br />
(o<strong>de</strong>r show()), da Fenster standardmäßig nicht sichtbar s<strong>in</strong>d. „dispose()“ macht<br />
Fenster unsichbar und gibt damit alle verbun<strong>de</strong>nen Ressourcen frei.<br />
E<strong>in</strong> JFrame ist e<strong>in</strong> vollwertiges Fenster. Es besitzt e<strong>in</strong>en Rahmen mit Titelleiste und<br />
u.U.a. e<strong>in</strong>e MenuBar (Attribut JMenuBar). „resizable()“ gibt an, ob <strong>de</strong>r Benutzer<br />
die Größe e<strong>in</strong>es Fensters verän<strong>de</strong>rn kann und iconImage() dient zur Festlegung<br />
e<strong>in</strong>es Symbols, falls das Fenster <strong>de</strong>n Zustand (state) Frame.ICONIFIED<br />
annimmt.<br />
361
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Unterschied zum AWT-Frame. Mit frame.add(komponente) wird <strong>in</strong> e<strong>in</strong>em AWT-<br />
Programm e<strong>in</strong> Objekt zu e<strong>in</strong>em Fenster h<strong>in</strong>zugefügt. Bei e<strong>in</strong>em JFrame muß das<br />
Component-Objekt erst zu <strong>de</strong>r Zeichenfläche, die ContentPane genammt wird,<br />
zugefügt wer<strong>de</strong>n, z.B.:<br />
Conta<strong>in</strong>er con = frame.getContentPane();<br />
con.add(komponente);<br />
Das läßt sich abkürzen zu: frame.getContentPane().add(komponente)<br />
Auch beim Schließen e<strong>in</strong>es Fensters verhält sich e<strong>in</strong> JFrame etwas an<strong>de</strong>rs als e<strong>in</strong><br />
AWT-Frame. Beim JFrame verschw<strong>in</strong><strong>de</strong>t das Fenster <strong>in</strong> <strong>de</strong>n H<strong>in</strong>tergrund. Dieses<br />
Verhalten kann mit <strong>de</strong>r Funktion „void setDefaultCloseOperation(<strong>in</strong>t<br />
operation)“ geän<strong>de</strong>rt wer<strong>de</strong>n. So verhält sich bspw. mit<br />
setDefaultCloseOperation(W<strong>in</strong>dowConstants.DO_NOTHING_ON_CLOSE)<br />
e<strong>in</strong> JFrame wie e<strong>in</strong> Frame. Jetzt lässt sich mit Hilfe e<strong>in</strong>es W<strong>in</strong>dowListener-Objekts<br />
auf w<strong>in</strong>dowClos<strong>in</strong>g() reagieren. Neben DO_NOTHING_ON_CLOSE existieren drei<br />
weitere Konstanten:<br />
W<strong>in</strong>dowConstants.HIDE_ON_CLOSE<br />
Das Fenster wird automatisch ver<strong>de</strong>ckt, nach<strong>de</strong>m die W<strong>in</strong>dowListener aufgerufen wer<strong>de</strong>n (Standard).<br />
W<strong>in</strong>dowConstants.DISPOSE_ON_CLOSE<br />
Bewirkt die Freigabe <strong>de</strong>r Ressourcen, nach<strong>de</strong>m die Listener abgearbeitet s<strong>in</strong>d und das Fenster<br />
geschlossen wird.<br />
W<strong>in</strong>dowConstants.EXIT_ON_CLOSE<br />
Ruft System.exit() auf und schließt die Anwendung.<br />
„getDefaultCloseOperation()“ liefert die e<strong>in</strong>gestellte Eigenschaft beim<br />
Schließen <strong>de</strong>s Fensters.<br />
Das Applikationsgerüst. Für das E<strong>in</strong>fügen <strong>in</strong> e<strong>in</strong>en Sw<strong>in</strong>g-Frame ist folgen<strong>de</strong>s<br />
Applikationsgerüst zweckmäßig: Conta<strong>in</strong>er und Komponenten müssen <strong>in</strong> e<strong>in</strong>em<br />
Zwischen-Conta<strong>in</strong>er mit <strong>de</strong>m Namen „ContentPane“ (Inhaltsbereich) e<strong>in</strong>gefügt<br />
wer<strong>de</strong>n. Der JFrame ist <strong>in</strong> verschie<strong>de</strong>n Bereiche (panes) unterteilt. Der<br />
Hauptbereich ist <strong>de</strong>r Inhaltsbereich, <strong>de</strong>r die gesamte Fläche <strong>de</strong>s Frame repräsentiert,<br />
<strong>in</strong> <strong>de</strong>n Komponenten e<strong>in</strong>gefügt wer<strong>de</strong>n können. Das Erzeugen e<strong>in</strong>er Komponenten <strong>in</strong><br />
<strong>de</strong>n Inhaltsbereich umfasst:<br />
- Erzeugen e<strong>in</strong>es JPanel-Objekts<br />
- E<strong>in</strong>fügen aller Komponenten <strong>in</strong> das JPanel-Objekt über <strong>de</strong>ssen add (Component)-Metho<strong>de</strong><br />
- Implementieren <strong>de</strong>s JPanel-Objekts über die Metho<strong>de</strong> setContentPane(Conta<strong>in</strong>er).<br />
Bsp. 288 :<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class Rahmenwerk extends JFrame<br />
{<br />
public Rahmenwerk()<br />
{<br />
super("Anwendung - Titel");<br />
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
setLocation(100,100);<br />
setSize(300,200);<br />
pack();<br />
288 pr56110<br />
362
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
/* pack() sorgt fuer die Reduzierung <strong>de</strong>r<br />
Groesse <strong>de</strong>s Frame, dass alle Komponenten gera<strong>de</strong> dar<strong>in</strong><br />
noch Platz f<strong>in</strong><strong>de</strong>n<br />
*/<br />
setVisible(true);<br />
/* Macht <strong>de</strong>n Frame sichtbar */<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
JFrame frame = new Rahmenwerk();<br />
}<br />
}<br />
Layout. LayouManager verwalten die Anordnung <strong>de</strong>r Komponenten <strong>in</strong> e<strong>in</strong>em<br />
Conta<strong>in</strong>er. Das Layout wird durch die Metho<strong>de</strong> setLayout(LayoutManager lm)<br />
angegeben.<br />
Bsp. 289 : Anwendung <strong>de</strong>s LayoutManagers Bor<strong>de</strong>rLayout<br />
Das Programm fügt <strong>in</strong> das JFrame e<strong>in</strong> Texfeld mit e<strong>in</strong>em Scrollbalken, e<strong>in</strong>em JColorChooser und 2<br />
"Karteikarten mit jeweils e<strong>in</strong>er Tabelle" e<strong>in</strong>.<br />
Das Textfeld wird durch das Anlegen e<strong>in</strong>es JTextArea-Objekts erzeugt. Durch Übergabe dieses<br />
Objekts an <strong>de</strong>n Konstruktor e<strong>in</strong>es JScrollPane-Objekts wird das Textfeld mit e<strong>in</strong>em Scrollbalken auf<br />
<strong>de</strong>r rechten Seite ausgestattet.<br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
public class Pr56352 extends JFrame<br />
{<br />
Color farbe;<br />
JColorChooser jcc;<br />
JButton jw;<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Pr56352 pr56352 = new Pr56352();<br />
}<br />
public Pr56352()<br />
{<br />
super("Bor<strong>de</strong>rLayout");<br />
JTextArea ja = new JTextArea("Nor<strong>de</strong>n");<br />
JScrollPane jsp =<br />
new JScrollPane(ja, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,<br />
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);<br />
jsp.setPreferredSize(new Dimension((<strong>in</strong>t) this.getWidth(),100));<br />
jcc = new JColorChooser();<br />
jw = new JButton("Westen");<br />
jw.addActionListener(new ActionListener()<br />
{<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
farbe = jcc.getColor();<br />
jw.setBackground(farbe);<br />
}<br />
});<br />
JTabbedPane jtp = new JTabbedPane(2);<br />
JTable jt1 = new JTable(13,2);<br />
JTable jt2 = new JTable(10,1);<br />
jt2.setBackground(Color.green);<br />
jtp.addTab("2",jt1);<br />
jtp.addTab("1",jt2);<br />
JButton js = new JButton("Sue<strong>de</strong>n");<br />
289 vgl. pr56352 <strong>in</strong> pr56350<br />
363
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
js.setBackground(Color.yellow);<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 />
System.exit(0);<br />
}<br />
} );<br />
getContentPane().setLayout(new Bor<strong>de</strong>rLayout());<br />
getContentPane().add(Bor<strong>de</strong>rLayout.NORTH,jsp);<br />
getContentPane().add(Bor<strong>de</strong>rLayout.WEST,jw);<br />
getContentPane().add(Bor<strong>de</strong>rLayout.EAST,jtp);<br />
getContentPane().add(Bor<strong>de</strong>rLayout.CENTER,jcc);<br />
getContentPane().add(Bor<strong>de</strong>rLayout.SOUTH,js);<br />
setSize(700,400);<br />
setVisible(true);<br />
Abb. Grafische Benutzroberfläche, die mit Bor<strong>de</strong>rLayout erzeugt wur<strong>de</strong><br />
364
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Interne Struktur von JFrame. Die <strong>in</strong>terne Struktur weist mehrere übere<strong>in</strong>an<strong>de</strong>rliegen<strong>de</strong><br />
Bereiche auf, <strong>de</strong>nen verschie<strong>de</strong>ne Aufgaben zugeteilt wur<strong>de</strong>n. Im<br />
wesentlichen s<strong>in</strong>d dies:<br />
- Wurzelbereich<br />
- Schichtbereich<br />
(dient hauptsächlich zur Darstellung von Menüs)<br />
- Inhaltsbereich<br />
(Conta<strong>in</strong>er für die meisten visuellen Elemente, kann mit getContentPane() angefor<strong>de</strong>rt wer<strong>de</strong>n)<br />
- Glasbereich<br />
(Komponenten, die <strong>in</strong> <strong>de</strong>n Glasbereich e<strong>in</strong>gefügt wer<strong>de</strong>n, ersche<strong>in</strong>en im Vor<strong>de</strong>rgrund und<br />
über<strong>de</strong>cken die darunter liegen<strong>de</strong>n Schichten. Diese Eigenschaft ist vor allem für die Darstellung<br />
von PopUp-Menüs von Be<strong>de</strong>utung.)<br />
JFrame<br />
JRoot<br />
JLayeredPane<br />
Inhaltsbereich<br />
Glasbereich<br />
Abb.: Interne Struktur von JFrame<br />
Die Hauptkomponente wird als RootPane bezeichnet und ist vom Typ JRootPane.<br />
E<strong>in</strong>e RootPane enthält folgen<strong>de</strong> Komponenten:<br />
- e<strong>in</strong>e aus Conta<strong>in</strong>er abgeleitete GlassPane<br />
- e<strong>in</strong>e aus JLayeredPane abgeleitete LayeredPane.<br />
E<strong>in</strong>e LayeredPane enthält ihrerseits zwei Unterkomponenten:<br />
- e<strong>in</strong>e aus Conta<strong>in</strong>er abgeleitete ContentPane<br />
- e<strong>in</strong>e aus JMenuBar abgeleitete Menüleiste.<br />
Die RootPane und mit ihr die dar<strong>in</strong> enthaltene GlassPane, LayeredPane und<br />
ContentPane wer<strong>de</strong>n beim Anlegen <strong>de</strong>s Fensters automatisch erzeugt (nur die<br />
Menüleiste bleibt standardmäßig leer). Außer<strong>de</strong>m implementieren alle Hauptfenster<br />
das Interface RootPaneConta<strong>in</strong>er, das <strong>de</strong>n Zugriff auf die RootPane vere<strong>in</strong>facht.<br />
E<strong>in</strong>ige se<strong>in</strong>er Metho<strong>de</strong>n s<strong>in</strong>d:<br />
public JRootPane getRootPane()<br />
public Conta<strong>in</strong>er getContentPane()<br />
public JLayeredPane getLayeredPane()<br />
public Component getClassPane()<br />
Neben <strong>de</strong>n “getter”-Metho<strong>de</strong>n gibt es auch „setter“-Metho<strong>de</strong>n, die <strong>de</strong>n strukturellen<br />
Aufbau <strong>de</strong>r RootPane vollständig verän<strong>de</strong>rn können.<br />
365
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.2.2 JW<strong>in</strong>dow<br />
JW<strong>in</strong>dow ist aus W<strong>in</strong>dow abgeleitet und dient dazu, e<strong>in</strong> rahmenloses Fenster zu<br />
erzeugen, das an beliebiger Stelle und <strong>in</strong> beliebiger Größe auf <strong>de</strong>m Bildschirm<br />
platziert wer<strong>de</strong>n kann.<br />
5.6.2.3 JDialog, JFileChooser, JColorChooser<br />
JDialog<br />
Mit <strong>de</strong>r aus Dialog abgeleiteten Klasse JDialog stehen auch im Sw<strong>in</strong>g Dialogfenster<br />
zur Verfügung. Dialogfenster unterschei<strong>de</strong>n sich von Hauptfenstern, dass sie ke<strong>in</strong><br />
Menü und nur e<strong>in</strong>geschränkte Systemfunktionen besitzen. Sie besitzen <strong>de</strong>nselben<br />
strukturellen Aufbau wie JFrame und JW<strong>in</strong>dow und implementieren ebenfalls das<br />
Interface RootPaneConta<strong>in</strong>er. Auch hier erfolgt das H<strong>in</strong>zufügen und Anordnen<br />
von Komponenten nicht auf <strong>de</strong>m Fenster selbst, son<strong>de</strong>rn auf se<strong>in</strong>er ContentPane.<br />
Die (wichigsten) Konstruktoren s<strong>in</strong>d:<br />
public JDialog(Frame owner)<br />
public JDialog(Frame owner, bollean modal)<br />
public JDialog(Frame owner, Str<strong>in</strong>g titel)<br />
public JDialog(Frame owner, Str<strong>in</strong>g titel, boolean modal)<br />
Als "owner" sollte <strong>de</strong>r Aufrufer das Fenster übergeben, zu <strong>de</strong>m <strong>de</strong>r Dialog logisch<br />
gehört. Alle Konstruktoren gibt es auch owner vom Typ Dialog. Wahlweise kann e<strong>in</strong><br />
JDialog auch ohne owner konstruiert wer<strong>de</strong>n (mit <strong>de</strong>m parameterlosen<br />
Konstruktor), doch kann es dann u.U. Fokusprobleme beim Wechsel zwischen <strong>de</strong>n<br />
Anwendungen geben.<br />
Modaler bzw. nicht-modaler Dialog. Bei e<strong>in</strong>em modalen Dialog wird <strong>de</strong>r Aufruf von<br />
show() (bzw. setVisible(true)) erst dann been<strong>de</strong>t, wenn <strong>de</strong>r Dialog<br />
geschlossen wur<strong>de</strong>. Bei e<strong>in</strong>em nicht-modalen Dialog fährt das Programm dagegen<br />
unmittelbar nach <strong>de</strong>r nächsten Anweisung h<strong>in</strong>ter show() fort.<br />
JFileChooser<br />
Diese Klasse ermöglicht e<strong>in</strong>en Standarddialog, mit <strong>de</strong>ssen Hilfe komfortable und<br />
Betriebssystem unabhängige Datei- und Verzeichnisauswahl möglich ist.<br />
JColorChooser<br />
Diese Klasse erlaubt e<strong>in</strong>e e<strong>in</strong>fache, visuelle und kontextunabhängige Auswahl von<br />
Farb<strong>in</strong>formationen.<br />
366
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Bsp. 290 : JColorChooserTest<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class JColorChooserTest extends JFrame<br />
implements ActionListener<br />
{<br />
public JColorChooserTest()<br />
{<br />
super("Us<strong>in</strong>g JColorChooser");<br />
// W<strong>in</strong>dowUtilities.setNativeLookAndFeel();<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 />
{ System.exit(0); }<br />
});<br />
Conta<strong>in</strong>er content = getContentPane();<br />
content.setBackground(Color.white);<br />
content.setLayout(new FlowLayout());<br />
JButton colorButton<br />
= new JButton("Choose Background Color");<br />
colorButton.addActionListener(this);<br />
content.add(colorButton);<br />
setSize(300, 100);<br />
setVisible(true);<br />
}<br />
public void actionPerformed(ActionEvent e)<br />
{<br />
// Args are parent component, title, <strong>in</strong>itial color<br />
Color bgColor<br />
= JColorChooser.showDialog(this,<br />
"Choose Background Color",<br />
getBackground());<br />
if (bgColor != null)<br />
getContentPane().setBackground(bgColor);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
new JColorChooserTest();<br />
}<br />
}<br />
Nach Drücken <strong>de</strong>s Button "ChooseBackgroundColor" ersche<strong>in</strong>t<br />
290 pr56370<br />
367
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
zur Auswahl <strong>de</strong>r gewünschten Farbe, die hier zum Füllen <strong>de</strong>s H<strong>in</strong>tergrunds benutzt wird.<br />
Mit <strong>de</strong>m Dialog lassen sich Farben <strong>in</strong> drei unterschiedlichen Dialogen auswählen.<br />
Der Benutzer hat die Auswahl unter <strong>de</strong>n vor<strong>de</strong>f<strong>in</strong>ierten Farben, HSB-Werten und<br />
RGB-Werten. Der Farbauswahl-Dialog ersche<strong>in</strong>t auf <strong>de</strong>m Bildschirm nach <strong>de</strong>m Aufruf<br />
JColorChooser.showDialog() mit drei Argumenten:<br />
e<strong>in</strong>em Component-Objekt, auf <strong>de</strong>m gezeichnet wer<strong>de</strong>n kann<br />
<strong>de</strong>m Titel<br />
e<strong>in</strong>er Anfangsfarbe<br />
Rückgabewert ist nach Been<strong>de</strong>n <strong>de</strong>s Dialogs die ausgewählte Farbe (bei Abbruch:<br />
null).<br />
5.6.2.4 JOptionPane<br />
Die Klasse javax.sw<strong>in</strong>g.JOptionPane ist <strong>in</strong> <strong>de</strong>r Lage, e<strong>in</strong>fache Dialoge, die<br />
lediglich e<strong>in</strong> Icon, e<strong>in</strong>en Text o<strong>de</strong>r e<strong>in</strong> E<strong>in</strong>gabefeld und e<strong>in</strong>e Anzahl <strong>de</strong>r Schaltflächen<br />
"Yes", "No" und "Cancel" enthalten, mit e<strong>in</strong>em e<strong>in</strong>zigen Aufruf e<strong>in</strong>er statischen<br />
Metho<strong>de</strong> zu erzeugen.<br />
368
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.2.5 JInternalFrame<br />
Bei vielen Programmen gibt es e<strong>in</strong> e<strong>in</strong>ziges Hauptfenster und zahlreiche geöffnete<br />
K<strong>in</strong>dfenster <strong>in</strong>nerhalb <strong>de</strong>s Hauptfensters. Diese unter W<strong>in</strong>dows als MDI (Multiple<br />
Document Interface) bezeichnete Technik ist mittlerweise weit verbreitet.<br />
In Sw<strong>in</strong>g können MDI-Anwendungen entwickelt wer<strong>de</strong>n. Dazu wer<strong>de</strong>n zwei Arten von<br />
Komponenten benötigt:<br />
- das als Desktop bezeichnete Hauptfenster <strong>de</strong>r Anwendung<br />
- das Subfenster <strong>de</strong>r Anwendung<br />
5.6.2.6 JPanel und JLayeredPane<br />
JPanel<br />
E<strong>in</strong> JPanel ist e<strong>in</strong> Fensterbereich, <strong>in</strong> <strong>de</strong>m an<strong>de</strong>re Kontrollelemente platziert wer<strong>de</strong>n<br />
können (Conta<strong>in</strong>er). Hauptaufgabe ist die Gestaltung und Glie<strong>de</strong>rung von<br />
Benutzeroberflächen. JPanel ist die Basisklasse für GUI-Conta<strong>in</strong>er, die nicht<br />
Hauptfenster s<strong>in</strong>d. Standardmäßig ist e<strong>in</strong>em JPanel e<strong>in</strong> FlowLayout als<br />
LayoutManager zugeordnet. Neben <strong>de</strong>n geerbten Metho<strong>de</strong>n von JComponent,<br />
Conta<strong>in</strong>er, Component und Object kommen ke<strong>in</strong>e nenneswerten Funktionen<br />
h<strong>in</strong>zu.<br />
Konstruktoren.<br />
public JPanel()<br />
// erzeugt e<strong>in</strong> neues JPanel mit Double-Buffer<strong>in</strong>g<br />
public JPanel(boolean isDoubleBuffered)<br />
// erzeugt e<strong>in</strong> neues JPanel mit FlowLayout und <strong>de</strong>r angegebenen Puffer-Strategie<br />
public JPanel(LayoutManager layout)<br />
// erzeugt e<strong>in</strong>en JPanel mit Double-Buffer<strong>in</strong>g und <strong>de</strong>m angegebenen Layout-Manager<br />
public JPanel(LayoutManager layout, boolean isDoubleBuffered)<br />
// erzeugt e<strong>in</strong> neues JPanel mit <strong>de</strong>m angegebenen LayoutManager und <strong>de</strong>r angegebenen Puffer-<br />
// Strategie<br />
JLayeredPane<br />
JLayeredPane fügt <strong>de</strong>n Dialogen e<strong>in</strong>e dritte Dimension h<strong>in</strong>zu und ermöglicht mit<br />
Hilfe e<strong>in</strong>es Layerkonzepts die kontrollierte Anordnung von Komponenten<br />
übere<strong>in</strong>an<strong>de</strong>r. JLayeredPane ist die Elternklasse von JDesktopPane und wichtiger<br />
Bestandteil <strong>de</strong>r Struktur von Hauptfenstern.<br />
369
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.3 Menüs<br />
5.6.3.1 Grundlagen<br />
Menüs dienen zur Auswahl von Funktionen und Optionen <strong>in</strong> Anwendungen. Sie<br />
können entwe<strong>de</strong>r an <strong>de</strong>r Oberseite von Fenstern o<strong>de</strong>r als PopUp-Menüs an e<strong>in</strong>er<br />
beliebigen Stelle auftauchen.<br />
JMenuBar<br />
In Sw<strong>in</strong>g können alle Hauptfenster mit Ausnahme von JW<strong>in</strong>dow e<strong>in</strong>e Menüleiste<br />
haben.<br />
JMenu<br />
Die e<strong>in</strong>zelnen Menüs e<strong>in</strong>er Menüleiste s<strong>in</strong>d Instanzen <strong>de</strong>r Klasse JMenu, die aus<br />
JMenuItem abgeleitet ist.<br />
JMenuItem<br />
Die Klasse JMenuItem repräsentiert Menüe<strong>in</strong>träge, also Elemente, die sich <strong>in</strong> e<strong>in</strong>em<br />
Menu bef<strong>in</strong><strong>de</strong>n. Dabei han<strong>de</strong>lt es sich um Texte, die wahlweise mit e<strong>in</strong>em Icon o<strong>de</strong>r<br />
mit e<strong>in</strong>em Häkchen versehen wer<strong>de</strong>n können.<br />
5.6.3.2 Kontextmenüs<br />
370
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
AbstractButton<br />
JMenuItem<br />
><br />
public JMenuItem()<br />
public JMenuItem(Icon icon)<br />
public JMenuItem(Str<strong>in</strong>g text)<br />
public JMenuItem(Str<strong>in</strong>g text, Icon icon)<br />
public JMenuItem(Str<strong>in</strong>g text, <strong>in</strong>t mnemonic)<br />
><br />
public void addMenuDragMouseListener(MenuDragMouseListener l)<br />
public void addMenuKeyListener(MenuKeyListener l)<br />
public KeyStroke getAccelerator()<br />
…<br />
public MenuKeyListener [] getMenuKeyListeners()<br />
public MenuElement [] getSubElements()<br />
…<br />
public void <strong>in</strong>it(Str<strong>in</strong>g text, Icon icon)<br />
…<br />
public void removeKeyListener(MenuKeyListener l)<br />
public void setAccelerator(KeyStroke keyStroke)<br />
…<br />
public void setEnabled(boolean b)<br />
public void setUI(MenuItem ui)<br />
public void updateUI()<br />
JMenu<br />
JCheckBoxMenuItem<br />
> JRadioButtonMenuItem<br />
public JMenu()<br />
public JMenu(Action a)<br />
public JMenu(Str<strong>in</strong>g s)<br />
public JMenu(Str<strong>in</strong>g s, boolean b)<br />
><br />
public JMenuItem add(Action a)<br />
public JMenuItem add(JMenuItem menuItem)<br />
public JMenuItem add(Str<strong>in</strong>g s)<br />
public addmenuListener(MenuListener l)<br />
public void addSeparator()<br />
…<br />
public void doClick(<strong>in</strong>t pressTime)<br />
…<br />
public JMenuItem getItem(<strong>in</strong>t pos)<br />
public <strong>in</strong>t getItemCount()<br />
…<br />
public JMenuItem <strong>in</strong>sert(Action a, <strong>in</strong>t pos)<br />
Abb.: Die Sw<strong>in</strong>g-Menüklassen<br />
371
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
JMenuBar<br />
JPopupMenu<br />
> ><br />
public JMenuBar()<br />
public JPopupMenu()<br />
> public JPopupMenu(Str<strong>in</strong>g label)<br />
public void add(JMenu c) ><br />
public void addNotify() public JMenuItem add(Action a)<br />
… public JMenuItem add(JMenuItem m)<br />
public JMenu getMenu(<strong>in</strong>t <strong>in</strong><strong>de</strong>x) public JMenuItem add(Str<strong>in</strong>g s)<br />
…<br />
public MenuElement [] getSubElements()<br />
public MenuBarUI getUI()<br />
…<br />
public boolean isSelected()<br />
…<br />
public void setHelpMenu(JMenu menu)<br />
…<br />
public void setUI(MenuBarUI ui)<br />
public void updateUI()<br />
372
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.4 Die Conta<strong>in</strong>er-Klassen JToolBar, JSplitPane, JScrollPane,<br />
JTabbedPane<br />
JToolBar<br />
Mit JToolBar können Werkzeugleisten erstellt wer<strong>de</strong>n, die Buttons enthalten.<br />
JSplitPane<br />
Das Kontrollelment teilt e<strong>in</strong>e Fläche <strong>in</strong> zwei Teile.<br />
JScrollPane<br />
Der Conta<strong>in</strong>er JScrollPane ermöglicht die Anzeige e<strong>in</strong>es<br />
Komponentenausschnitts. In Verb<strong>in</strong>dung mit <strong>de</strong>n Klassen JTextArea und JList<br />
besteht die Ausgabe von JScrollPane dar<strong>in</strong>, Dialogelemente, die zu groß für <strong>de</strong>n zur<br />
Verfügung stehen<strong>de</strong>n Platz s<strong>in</strong>d, mit Hilfe e<strong>in</strong>es verschiebbaren Fensters<br />
ausschnittsweise sichtbar zu machen.<br />
Konstruktoren.<br />
public JScrollPane(Component view)<br />
public JScrollPane(Component view, <strong>in</strong>t vsbPolicy, <strong>in</strong>t hsbPolicy)<br />
Die Argumente vsbPolicy und hsbPolicy geben an, wann e<strong>in</strong> horiz<strong>in</strong>taler bzw. vertikaler<br />
Schieberegler e<strong>in</strong>geblen<strong>de</strong>t wird. Es können folgen<strong>de</strong> Werte angegeben wer<strong>de</strong>n:<br />
Konstante<br />
VERTICAL_SCROLLBAR_NEVER<br />
VERTICAL_SCROLLBAR_ALLWAYS<br />
VERTICAL_SCROLLBAR_AS_NEEDED<br />
HORIZONTAL_SCROLLBAR_NEVER<br />
HORIZONTAL_SCROLLBAR_ALLWAYS<br />
HORIZONTAL_SCROLLBAR_AS_NEEDED<br />
Be<strong>de</strong>utung<br />
Der vertikale Schieberegler wird nie angezeigt.<br />
Der vertikale Schieberegler wird immer angezeigt.<br />
Der vertikale Schieberegler wird nur angezeigt,<br />
wenn er benötigt wird<br />
Der horizontale Schieberegler wird nie angezeigt<br />
Der horizontale Schieberegler wird immer<br />
angezeigt<br />
Der horizontale Schieberegler wird nur angezeigt,<br />
wenn er benötigt wird<br />
Falls die Argumente vsbPolicy und hsbPolicy nicht angegeben wer<strong>de</strong>n, blen<strong>de</strong>t JScrollPane<br />
die Schieberegler nur dann e<strong>in</strong>, wenn sie wirklich benötigt wer<strong>de</strong>n.<br />
Metho<strong>de</strong>n.<br />
public void setColumnHea<strong>de</strong>rView(Component view)<br />
Angabe e<strong>in</strong>er Komponente für <strong>de</strong>n Spaltenkopf. Sie wird über <strong>de</strong>m eigentlichen Dialogelement<br />
angezeigt, bei horozontalen Bewegungen mit diesem verschoben. Bei vertikalen<br />
Schieberbewegungen bleiben sie dagegen am Platz.<br />
public void setRowhea<strong>de</strong>rView(Component view)<br />
Angabe e<strong>in</strong>es Zeilenkopfs l<strong>in</strong>ks neben <strong>de</strong>r eigentlichen Komponente, wird bei vertikalen Bewegungen<br />
verschoben, behält bei horizontalen Bewegungen se<strong>in</strong>en Platz bei.<br />
373
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void setCorner(Str<strong>in</strong>g key, Component corner)<br />
E<strong>in</strong> Dialogelement kann <strong>in</strong> e<strong>in</strong>e beliebige <strong>de</strong>r vier ungenutzten Ecken 291 e<strong>in</strong>er JScrollPane plaziert<br />
wer<strong>de</strong>n. Der Parameter key gibt dabei an, welche Ecke belegt wer<strong>de</strong>n soll. Argument kann e<strong>in</strong>er <strong>de</strong>r<br />
Konstanten LOWER_LEFT_CORNER, LOWER_RIGHT_CORNER, UPPER_LEFT_CORNER,<br />
UPPER_RIGHT_CORNER se<strong>in</strong>.<br />
Eckfläche<br />
Zeilenhea<strong>de</strong>r<br />
Eckfläche<br />
Abb.: Aufbau e<strong>in</strong>er JScrollpane<br />
Spaltenhea<strong>de</strong>r<br />
ViewPort<br />
Horizontaler<br />
Schieberegler<br />
Eckfläche<br />
Vertikaler<br />
Schieberegler<br />
Eckfläche<br />
Der sichtbare Ausschnitt heißt ViewPort und wird durch folgen<strong>de</strong> Metho<strong>de</strong>n e<strong>in</strong>gestell:<br />
public void setViewPort(JViewPort viewport)<br />
public void setViewPortView(Component view)<br />
e<strong>in</strong>gestellt.<br />
JTabbedPane<br />
E<strong>in</strong> JTabbedPane erlaubt die Darstellung mehrerer Conta<strong>in</strong>er, die über Kartenreiter<br />
zugänglich s<strong>in</strong>d.<br />
291 u.U. stehen Eckflächen nicht zur Verfügung. Die bei<strong>de</strong>n Ecken auf <strong>de</strong>r l<strong>in</strong>ken Seite s<strong>in</strong>d bspw. nur<br />
vorhan<strong>de</strong>n, wenn e<strong>in</strong> Zeilenkopf e<strong>in</strong>geblen<strong>de</strong>t wur<strong>de</strong>. Die rechte obere ist nur vorhan<strong>de</strong>n, wenn e<strong>in</strong> vertikaler<br />
Schieberegler e<strong>in</strong>geblen<strong>de</strong>t wur<strong>de</strong>, und die rechte untere erfor<strong>de</strong>rt sogar die Anwesenheit bei<strong>de</strong>r Schieberegler.<br />
Auch kann die Anwendung praktisch ke<strong>in</strong>en E<strong>in</strong>fluß auf die Größe <strong>de</strong>r Ecken nehmen. Diese wird<br />
ausschließlich die Aus<strong>de</strong>hnung <strong>de</strong>r Schieberegler und <strong>de</strong>s Zeilenkopfes bestimmt.<br />
374
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.5 Sw<strong>in</strong>g-Komponenten<br />
5.6.5.1 Label und Textfel<strong>de</strong>r<br />
JLabel<br />
E<strong>in</strong> JLabel ist e<strong>in</strong> Dialogelement zur Anzeige und Beschriftung <strong>in</strong>nerhalb e<strong>in</strong>es GUI-<br />
Comta<strong>in</strong>ers, besitzt Text und Icon, die <strong>in</strong> beliebiger Anordnung dargestellt wer<strong>de</strong>n<br />
können. Die bei<strong>de</strong>n Elemente s<strong>in</strong>d optional, e<strong>in</strong> JLabel kann auch nur e<strong>in</strong> Icon<br />
enthalten. Auf Benutzere<strong>in</strong>geben reagiert e<strong>in</strong> JLabel nicht. In <strong>de</strong>r Sw<strong>in</strong>g-Bibliothek<br />
gibt es mit <strong>de</strong>m Interface Icon bzw. <strong>de</strong>r Klasse ImageIcon Unterstützung zur<br />
Bildverarbeitung, wobei <strong>de</strong>r La<strong>de</strong>vorgang mit Hilfe von Mediatracker <strong>in</strong>tern erledigt<br />
wird.<br />
Konstruktoren.<br />
public JLabel(Str<strong>in</strong>g text)<br />
public JLabel(Icon image)<br />
public JLabel(Str<strong>in</strong>g text, Icon icon,<strong>in</strong>t horizontalAlignment)<br />
// Der Parameter horizontalAlignment gibt an, wie das Label horizontal plaziert wer<strong>de</strong>n soll, falls<br />
// l<strong>in</strong>ks und rechts mehr Platz als erfor<strong>de</strong>rlich zur Verfügung steht. Hier kann e<strong>in</strong>e <strong>de</strong>r Konstanten<br />
// LEFT, CENTER o<strong>de</strong>r RIGHT aus <strong>de</strong>m Interface Sw<strong>in</strong>gConstants angegeben wer<strong>de</strong>n.<br />
Metho<strong>de</strong>n.<br />
public void setHorizonatTextPosition(<strong>in</strong>t textPosition)<br />
public void getHorizontalTextPosition()<br />
public void setHorizontalAlignment(<strong>in</strong>t alignment)<br />
// horizontale Ausrichtung, mögliche Parameter: LEFT, CENTER, RIGHT<br />
public <strong>in</strong>t getHorizontalAlignment()<br />
public void setVerticalAlignment(<strong>in</strong>t alignment)<br />
// vertikale Ausrichtung, mögliche Parameter: TOP, CENTER, BOTTOM<br />
public <strong>in</strong>t getVerticalAlignment()<br />
Anzeige von Bil<strong>de</strong>rn (im Gegensatz zur AWT-Implementierung). Angegeben wer<strong>de</strong>n<br />
zur Anzeige von Bil<strong>de</strong>rn Icon-Objekte. Die Klasse ImageIcon implemntiert die Icon-<br />
Schnittstelle.<br />
<strong>in</strong>terface java.awt.sw<strong>in</strong>g.Icon<br />
public <strong>in</strong>t getIconWidth()<br />
// liefert die Breite e<strong>in</strong>es Icons<br />
public <strong>in</strong>t getIconHeight()<br />
// liefert die Höhe e<strong>in</strong>es Icons<br />
public void pa<strong>in</strong>tIcon(Component c, Graphics g, unt x, <strong>in</strong>t y)<br />
// zeichnet das Icon an die angegebene Position.<br />
Die Klasse ImageIcon implementiert die Icon-Schnittstelle und nutzt die Klasse<br />
Image (und <strong>de</strong>ren verwandte Klassen. E<strong>in</strong> ImageIcon ist serialisierbar<br />
(implementiert das Interface Serializable). E<strong>in</strong>e Referenz auf das Image-Objekt kann<br />
durch <strong>de</strong>n Aufruf von getImage() <strong>de</strong>r Klasse Toolkit hergestellt wer<strong>de</strong>n. Mit <strong>de</strong>r<br />
Metho<strong>de</strong> protected void loadImage(Image image) wartet man dann mit<br />
Hilfe e<strong>in</strong>es Mediatrackers auf das Bild. Dabei setzt <strong>de</strong>r Mediatracker Höhe und<br />
375
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Breite, die sich über Icon-Metho<strong>de</strong>n abfragen lassen. Zur Serialisierbarkeit s<strong>in</strong>d die<br />
Metho<strong>de</strong>n readObject() und writeObject() implementiert. Im zugehörigen<br />
Dateistrom bef<strong>in</strong><strong>de</strong>n sich Breite und Höhe und anschließend e<strong>in</strong> Integer-Feld mit<br />
Pixelwerten. Bei readObject() liest s.readObject() – wobei s <strong>de</strong>r aktuelle<br />
ObjectInputStream ist -, das Feld wie<strong>de</strong>r e<strong>in</strong>. Über die Toolkit-Funktion<br />
createImage() wird die Klasse MemoryImage genutzt, um das Feld wie<strong>de</strong>r bzu<br />
e<strong>in</strong>em Image-Objekt zu konvertieren. Umgekehrt geht es genauso e<strong>in</strong>fach:<br />
writeObject() schreibt Breite und Höhe und anschließend das Integer-Feld, das<br />
es über e<strong>in</strong> PixelGrabber bekommen hat.<br />
Die ImageIcon-Klasse kann somit das La<strong>de</strong>n von Icon-Objekten mit e<strong>in</strong>er<br />
Programmzeilen beschreiben:<br />
Image image = new ImageIcon(("bild.jpg").getImage())<br />
Da e<strong>in</strong> Image immer wie<strong>de</strong>r <strong>in</strong> e<strong>in</strong> ImageIcon umgewan<strong>de</strong>lt wer<strong>de</strong>n kann, eignet<br />
sich die Klasse hervorragend zum La<strong>de</strong>n und Speichern.<br />
Bsp. 292 : E<strong>in</strong>ige Labels mit unterschiedlichen Eigenschaften<br />
import java.awt.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
class LabelDemo extends JFrame<br />
{<br />
public LabelDemo()<br />
{<br />
super("JLabel Demo");<br />
setSize(600, 100);<br />
JPanel content = (JPanel) getContentPane();<br />
content.setLayout(new GridLayout(1, 4, 4, 4));<br />
JLabel label = new JLabel();<br />
label.setText("JLabel");<br />
label.setBackground(Color.white);<br />
content.add(label);<br />
label = new JLabel("JLabel",Sw<strong>in</strong>gConstants.CENTER);<br />
label.setOpaque(true);<br />
label.setBackground(Color.white);<br />
content.add(label);<br />
label = new JLabel("JLabel");<br />
label.setFont(new Font("Helvetica", Font.BOLD, 18));<br />
label.setOpaque(true);<br />
label.setBackground(Color.white);<br />
content.add(label);<br />
ImageIcon image = new ImageIcon("flight.gif");<br />
label = new JLabel("JLabel", image,Sw<strong>in</strong>gConstants.RIGHT);<br />
label.setVerticalTextPosition(Sw<strong>in</strong>gConstants.TOP);<br />
label.setOpaque(true);<br />
label.setBackground(Color.white);<br />
content.add(label);<br />
setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
new LabelDemo();<br />
}<br />
}<br />
292 pr56360<br />
376
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Demonstration zu <strong>de</strong>n Klassen JLabel und IconImage<br />
JTextField<br />
E<strong>in</strong> JTextField ist e<strong>in</strong> e<strong>in</strong>zeiliges E<strong>in</strong>gabefeld.<br />
Konstruktoren.<br />
public JTextField(<strong>in</strong>t columns)<br />
// e<strong>in</strong> leeres Textfeld mit <strong>de</strong>r angegebenen Anzahl Spalten<br />
public JTextField(Str<strong>in</strong>g text)<br />
// erzeugt e<strong>in</strong> Textfeld mit angegebenem Text<br />
public JTextField(Str<strong>in</strong>g text,<strong>in</strong>t columns)<br />
// erzeugt e<strong>in</strong> Textfeld nach Vorgabe von Spaltenanzahl und Text<br />
// Die Spaltenanzahl wird zur Berechnung <strong>de</strong>r Breite <strong>de</strong>r Textfel<strong>de</strong>r verwen<strong>de</strong>t<br />
Metho<strong>de</strong>n.<br />
public Str<strong>in</strong>g getText()<br />
public void setText()<br />
public Str<strong>in</strong>g getSelectedText()<br />
public <strong>in</strong>t getSelectionStart()<br />
public void setSelectionStart()<br />
public void setSelectionEnd(<strong>in</strong>t selectionEnd)<br />
public <strong>in</strong>t getCaretPosition()<br />
public void setCaretPosition(<strong>in</strong>t pos)<br />
public void moveCaretPosition(<strong>in</strong>t pos)<br />
// verän<strong>de</strong>rt die Position <strong>de</strong>r E<strong>in</strong>fügemarke und markiert dabei <strong>de</strong>n Bereich zwischen alter und<br />
// neuer Position. Für alle Positionsangaben gilt, dass <strong>de</strong>r Platz vor <strong>de</strong>m ersten Zeichen die<br />
// Position 0, und <strong>de</strong>r nach <strong>de</strong>m letzten Textzeichen die Position Länge <strong>de</strong>s Texts hat<br />
Listener.<br />
public void addActionListener(ActionListener l)<br />
// wird immer aufgerufen, wenn im E<strong>in</strong>gabefeld ENTER gedrückt wird.<br />
public void addCaretListener(CaretListener l)<br />
// wir aufgerufen, wenn sich die Position <strong>de</strong>r E<strong>in</strong>fügemarke geän<strong>de</strong>rt hat<br />
Bsp. 293 :<br />
import javax.sw<strong>in</strong>g.*;<br />
import java.awt.*;<br />
public class JTextFieldTest extends JFrame<br />
{<br />
public JTextFieldTest()<br />
{<br />
super("JTextField Test");<br />
getContentPane().setLayout(new FlowLayout());<br />
JTextField textField1 = new JTextField("m",1);<br />
JTextField textField2 = new JTextField("mm",2);<br />
JTextField textField3 = new JTextField("mmm",3);<br />
JTextField textField4 = new JTextField("mmmm",4);<br />
293 pr56370<br />
377
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JTextField textField5 = new JTextField("mmmmm",5);<br />
JTextField textField6 = new JTextField("mmmmmm",6);<br />
JTextField textField7 = new JTextField("mmmmmmm",7);<br />
JTextField textField8 = new JTextField("mmmmmmmm",8);<br />
JTextField textField9 = new JTextField("mmmmmmmmm",9);<br />
JTextField textField10 = new JTextField("mmmmmmmmmm",10);<br />
JTextField textField11 = new JTextField("mmmmmmmmmmm",11);<br />
JTextField textField12 = new JTextField("mmmmmmmmmmmm",12);<br />
JTextField textField13 = new JTextField("mmmmmmmmmmmmm",13);<br />
JTextField textField14 = new JTextField("mmmmmmmmmmmmmm",14);<br />
getContentPane().add(textField1);<br />
getContentPane().add(textField2);<br />
getContentPane().add(textField3);<br />
getContentPane().add(textField4);<br />
getContentPane().add(textField5);<br />
getContentPane().add(textField6);<br />
getContentPane().add(textField7);<br />
getContentPane().add(textField8);<br />
getContentPane().add(textField9);<br />
getContentPane().add(textField10);<br />
getContentPane().add(textField11);<br />
getContentPane().add(textField12);<br />
getContentPane().add(textField13);<br />
getContentPane().add(textField14);<br />
setSize(300,170);<br />
setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g argv[])<br />
{<br />
new JTextFieldTest();<br />
}<br />
}<br />
Abb.: Demonstration zur Klasse JTextField<br />
JTextArea<br />
JTextArea ist e<strong>in</strong>e Komponente zur Anzeige und E<strong>in</strong>gabe von mehrzeiligen Texten.<br />
Wie die AWT-Klasse TextArea dient sie dazu, unformatierte Texte zu bearbeiten.<br />
Diese können Zeilenumbrüche und Tabulatoren, nicht aber unterschiedliche<br />
Schriften, Farben o<strong>de</strong>r grafische Elemente enthalten 294 .<br />
Konstruktoren.<br />
public JTextArea(Str<strong>in</strong>g text)<br />
public JTextArea(<strong>in</strong>t rows, <strong>in</strong>t columns)<br />
public JTextArea(Str<strong>in</strong>g text,<strong>in</strong>t rows,<strong>in</strong>t columns)<br />
294 Für diesen Zweck gibt es die Klassen JEditorPane und JTextPane<br />
378
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Metho<strong>de</strong>n.<br />
public <strong>in</strong>t getL<strong>in</strong>eCount()<br />
// liefert Anzahl <strong>de</strong>r Zeilen<br />
public <strong>in</strong>t getL<strong>in</strong>eStartOffset(<strong>in</strong>t l<strong>in</strong>e)<br />
public <strong>in</strong>t getL<strong>in</strong>eEndOffset(<strong>in</strong>t l<strong>in</strong>e)<br />
// Zu e<strong>in</strong>er beliebigen Zeile kann Anfangs- und Endoffset bestimmt wer<strong>de</strong>n.<br />
public <strong>in</strong>t getL<strong>in</strong>eOfOffset(<strong>in</strong>t offset)<br />
// ermittelt die Nummer e<strong>in</strong>er Zeile, wenn <strong>de</strong>r Offset e<strong>in</strong>es dar<strong>in</strong> enthaltenen Zeichens bekannt ist.<br />
public void setTabSize(<strong>in</strong>t size)<br />
public <strong>in</strong>t getTabSize()<br />
// Zugriff auf die Tabulatorwerte (standardmäßig mit Wert 8 295 )<br />
public void setL<strong>in</strong>eWrap(boolean wrap)<br />
// Festlegung, ob zu breite Spalten automatisch unterbrochen wer<strong>de</strong>n sollen<br />
public void setWrapStyleWord(boolean word)<br />
// Umbruch an Wortgrenzen o<strong>de</strong>r mitten im Wort<br />
Automatisches Scrollen. JTextArea kann Text nicht automatisch scrollen. Wird das<br />
gewünscht, muß das Textfeld <strong>in</strong> e<strong>in</strong>er Komponente von JScrollPane e<strong>in</strong>gebettet<br />
wer<strong>de</strong>n.<br />
Bsp. 296 :<br />
import java.awt.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
import javax.sw<strong>in</strong>g.bor<strong>de</strong>r.*;<br />
public class BspScroll<strong>in</strong>g extends JFrame<br />
{<br />
public BspScroll<strong>in</strong>g()<br />
{<br />
super();<br />
JScrollPane scroller = new JScrollPane();<br />
getContentPane().add(scroller);<br />
Str<strong>in</strong>gBuffer bigBuffer = new Str<strong>in</strong>gBuffer();<br />
for (<strong>in</strong>t i = 0; i < 50; i++)<br />
{<br />
bigBuffer.append(Integer.toStr<strong>in</strong>g(i));<br />
bigBuffer.append(' ');<br />
}<br />
JLabel longLabel = new JLabel(bigBuffer.toStr<strong>in</strong>g());<br />
scroller.getViewport().add(longLabel);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
BspScroll<strong>in</strong>g e<strong>in</strong>Frame = new BspScroll<strong>in</strong>g();<br />
e<strong>in</strong>Frame.setVisible(true);<br />
}<br />
}<br />
JEditorPane und JTextPane<br />
Die Klasse JEditorPane und <strong>de</strong>ren Subklasse JTextPane erlauben verschie<strong>de</strong>ne<br />
Typen von Text darzustellen. Die bei<strong>de</strong>n Klassen unterstützen HTML und Rich Text<br />
Format (RTF). Eigene Implementierungen lassen sich h<strong>in</strong>zufügen (sog. Editor-Kits).<br />
Der Editor stellt Text dar, <strong>de</strong>r ihm mit<br />
295 Zur Umrechnung <strong>in</strong> Bildschirmpixel wird er mit <strong>de</strong>r Breite <strong>de</strong>s breitesten Buchstabens im aktuellen Font<br />
multipliziert.<br />
296 pr56110<br />
379
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void setContentType(Str<strong>in</strong>g type)<br />
übergeben wird. Ohne eigene Erweiterung s<strong>in</strong>d text/html (Standard),<br />
text/pla<strong>in</strong> und text/rtf erlaubt 297 . Wird mit Standardkonstruktor gearbeitet,<br />
dann kann mit<br />
public void setPage(Str<strong>in</strong>g url)<br />
bzw.<br />
public void setPage(URL page)<br />
e<strong>in</strong> URL-Objekt o<strong>de</strong>r e<strong>in</strong> Str<strong>in</strong>g e<strong>in</strong>e Seite belegen. Auch<br />
public void setText(Str<strong>in</strong>g t)<br />
erlaubt Setzen <strong>de</strong>s spezifizierten Inhalts von Text ohne Textkomponente.<br />
Konstruktoren.<br />
public JEditorPane()<br />
public JEditorPane(Str<strong>in</strong>g url)<br />
public JEditorPane(Str<strong>in</strong>g type,Str<strong>in</strong>g text)<br />
public JEditorPane(URL <strong>in</strong>itialPage)<br />
Bsp. 298 :Anzeige e<strong>in</strong>er HTML-Seite<br />
import java.io.*;<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class PR56510 extends Frame<br />
{<br />
Str<strong>in</strong>g url = "file:///d:/dok/pgj/ws02/progr/pr56510/Skript48.html";<br />
public PR56510()<br />
{<br />
try {<br />
JEditorPane htmlPane = new JEditorPane(url);<br />
htmlPane.setEditable(false);<br />
add(new JScrollPane(htmlPane));<br />
}<br />
catch(IOException e) { System.out.pr<strong>in</strong>tln("Error" + url);};<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 />
{ System.exit(0);}<br />
});<br />
setSize(300,200);<br />
setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
}<br />
}<br />
PR56510 pr56510 = new PR56510();<br />
297 Soll nur Text ohne Formatierungen und ohne Attribute dargestellt wer<strong>de</strong>n, lässt sich gleich TextField<br />
verwen<strong>de</strong>n.<br />
298 pr56510<br />
380
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JTextComponent<br />
JTextArea<br />
JEditorPane<br />
> ><br />
public JTextArea()<br />
public JEditorPane()<br />
public JTextArea (Document doc,<br />
public JEditorPane(Str<strong>in</strong>g type, Str<strong>in</strong>g<br />
Str<strong>in</strong>g text,<br />
text)<br />
<strong>in</strong>t rows, <strong>in</strong>t columns)<br />
public JEditorPane(URL <strong>in</strong>itialPage)<br />
public JTextArea(<strong>in</strong>t rows,<strong>in</strong>t columns)<br />
…<br />
public JTextArea(Str<strong>in</strong>g text) ><br />
public JTextArea(Str<strong>in</strong>g text,<br />
public Str<strong>in</strong>g getContentType()<br />
<strong>in</strong>t rows, <strong>in</strong>t columns)<br />
public EditorKit getEditorKit()<br />
> …<br />
public void append(Str<strong>in</strong>g str)<br />
public URL getPage()<br />
…<br />
public Dimension getPreferedSize()<br />
public <strong>in</strong>t getColumns()<br />
…<br />
…<br />
public Str<strong>in</strong>g getText()<br />
public <strong>in</strong>t getColumnCount()<br />
…<br />
…<br />
public void setPage(Str<strong>in</strong>g url)<br />
public <strong>in</strong>t getRows()<br />
public void setPage(URL page)<br />
… public void setText(Str<strong>in</strong>g t)<br />
public void <strong>in</strong>sert(Str<strong>in</strong>g str, <strong>in</strong>t pos)<br />
…<br />
public void replaceRange(Str<strong>in</strong>g str,<strong>in</strong>t start,<strong>in</strong>t end)<br />
public void setColumns(<strong>in</strong>t columns)<br />
public void setFont(Font f)<br />
JTextPane<br />
…<br />
public void setRows(<strong>in</strong>t rows)<br />
><br />
public JTextPane()<br />
public JTextPane(StyledDocument doc)<br />
><br />
public Style addStyle(Str<strong>in</strong>g nm, Style<br />
parent)<br />
…<br />
public Str<strong>in</strong>g getUIClassID()<br />
public void setStyleDocument(<br />
StyledDocument doc)<br />
Abb.: Die Klassen JTextArea und JTextPane<br />
381
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.5.2 Schaltflächen<br />
Die Klasse JButton und das Interface ButtonMo<strong>de</strong>l<br />
Buttons (Schaltflächen) s<strong>in</strong>d rechteckige Knöpfe, die e<strong>in</strong>e Aktion auslösen, wenn <strong>de</strong>r<br />
Benutzer sie anklickt.<br />
Die visuelle Komponente wird durch die Klasse JButton repräsentiert, die das<br />
Mo<strong>de</strong>ll und die Ansicht speichert. Gleichzeitig dient die Klasse als Vermittler beim<br />
Zugriff auf das Mo<strong>de</strong>ll o<strong>de</strong>r bei Anfor<strong>de</strong>rungen an die Ansicht. Das jeweilige Mo<strong>de</strong>ll<br />
ist durch e<strong>in</strong>e gleichnamige Schnittstelle implementiert. So <strong>de</strong>f<strong>in</strong>iert z.B. die<br />
Schnittstelle ButtonMo<strong>de</strong>l <strong>de</strong>n Zustand <strong>de</strong>r Schaltflächen-Klassen mit <strong>de</strong>n<br />
Zugriffsmetho<strong>de</strong>n:<br />
public Str<strong>in</strong>g getActionCommand()<br />
// liefert <strong>de</strong>n Namen <strong>de</strong>s Aktionsfel<strong>de</strong>s<br />
public boolean isArmed()<br />
public boolean isEnabled()<br />
public boolean isPressed()<br />
public boolean isRollover()<br />
public boolean isSelected()<br />
Der Zugriff auf das Mo<strong>de</strong>ll <strong>de</strong>r Komponente muß mit Hilfe <strong>de</strong>r Metho<strong>de</strong><br />
public ButtonMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
<strong>de</strong>r Klasse JButton angefor<strong>de</strong>rt wer<strong>de</strong>n bzw. kann mit<br />
public void setMo<strong>de</strong>l(ButtonMo<strong>de</strong>l newMo<strong>de</strong>l)<br />
<strong>de</strong>r Klasse JButton angefor<strong>de</strong>rt wer<strong>de</strong>n. In Standardfällen ist <strong>de</strong>r direkte Zugriff auf<br />
das Mo<strong>de</strong>ll nicht erfor<strong>de</strong>rlich, da die Klasse JButton über Zugriffsmetho<strong>de</strong>n auf die<br />
meisten Inhalte <strong>de</strong>s Mo<strong>de</strong>lls verfügt und diese kapselt. Alle Mo<strong>de</strong>lle mit<br />
"Schaltflächen"-Funktionalität (Schaltflächen, Optionsfel<strong>de</strong>r, Kontrollkästchen)<br />
können dasselbe Mo<strong>de</strong>ll verwen<strong>de</strong>n.<br />
382
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
AbstractButton<br />
protected ActionListener actionListener<br />
protected ChangeEvent changeEvent<br />
protected ChangeListener changeListener<br />
protected ItemListener itemListener<br />
public void addActionListener(ActionListener l)<br />
public void addChangeListener (ChangeListener l)<br />
public void addItemListener(ItemListener l)<br />
…<br />
public void doClick()<br />
…<br />
public <strong>in</strong>t getHorizontalTextPosition()<br />
public <strong>in</strong>t getHorizontalAlignment()<br />
public <strong>in</strong>t getVerticalAlignment()<br />
…<br />
public Icon getIcon()<br />
…<br />
public Insets getMarg<strong>in</strong>()<br />
public <strong>in</strong>t getMnemonic()<br />
public ButtonMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
…<br />
public Icon getSelectedIcon()<br />
public Str<strong>in</strong>g getText()<br />
public ButtonUI getUI();<br />
…<br />
public void setUI(ButtonUI ui)<br />
…<br />
public void updateUI()<br />
JButton<br />
><br />
public JButton()<br />
public JButton(Str<strong>in</strong>g text)<br />
public JButton(Icon icon)<br />
public JButton(Str<strong>in</strong>g text,Icon icon)<br />
><br />
…<br />
public boolean isDefaultButton()<br />
…<br />
public void removeNotify()<br />
…<br />
Abb.: Die Klasse JButton<br />
383
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klassen JCheckBox und JRadioButton<br />
In Sw<strong>in</strong>g wer<strong>de</strong>n run<strong>de</strong> und eckige Optionsfel<strong>de</strong>r nicht mehr <strong>in</strong> e<strong>in</strong>er Klasse<br />
zusammengefasst, son<strong>de</strong>rn durch die Klassen JCheckBox und JRadioButton<br />
dargestellt.<br />
JCheckBox<br />
Die Klasse JCheckBox stellet e<strong>in</strong>en Button dar, <strong>de</strong>r vom Anwen<strong>de</strong>r wahlweise ano<strong>de</strong>r<br />
ausgeschaltet wer<strong>de</strong>n kann. JCheckBox ist von <strong>de</strong>r Klasse JToggleButton<br />
abgeleitet, die als Abstraktion von Buttons, die ihren Zustand än<strong>de</strong>rn können, auch<br />
Basisklasse von JRadioButton ist.<br />
JCheckBox kann e<strong>in</strong>e textuelle Beschriftung o<strong>de</strong>r e<strong>in</strong> Icon o<strong>de</strong>r bei<strong>de</strong>s enthalten.<br />
Konstruktoren.<br />
public JCheckBox(Str<strong>in</strong>g text)<br />
public JCheckBox(Str<strong>in</strong>g text,boolean selected)<br />
// Mit <strong>de</strong>m Parameter "selected" kann bereits bei <strong>de</strong>r Instanzierung angegeben wer<strong>de</strong>n,<br />
// ob die Checkbox aktiviert o<strong>de</strong>r <strong>de</strong>aktiviert se<strong>in</strong> soll.<br />
Metho<strong>de</strong>n.<br />
public void getSelected(boolean b)<br />
public boolean isSelected()<br />
Wie e<strong>in</strong> JButton sen<strong>de</strong>t e<strong>in</strong>e JCheckBox bei je<strong>de</strong>r Bestätigung e<strong>in</strong> ActionEvent<br />
an registrierte Listener. Zu<strong>de</strong>m wird bei Zustandsän<strong>de</strong>rungen e<strong>in</strong> ItemEvent<br />
versen<strong>de</strong>t, auf das e<strong>in</strong> ItemListener reagieren kann.<br />
JRadioButton<br />
Die Klasse JRadioButton stellt e<strong>in</strong>e Button dar, <strong>de</strong>r wahlweise an- und<br />
ausgeschaltet wer<strong>de</strong>n kann. An<strong>de</strong>rs als bei <strong>de</strong>r JCheckBox ist <strong>in</strong> e<strong>in</strong>er Gruppe von<br />
Radiobuttons allerd<strong>in</strong>gs immer nur e<strong>in</strong> Button zur Zeit aktiviert, alle an<strong>de</strong>ren s<strong>in</strong>d<br />
<strong>de</strong>aktiviert.<br />
Konstruktoren.<br />
public JRadioButton(Str<strong>in</strong>g text)<br />
public JRadioButton(Str<strong>in</strong>g text, boolean selected)<br />
Metho<strong>de</strong>n.<br />
public void add(AbstractButton b)<br />
public ButtonMo<strong>de</strong>l getSelection()<br />
public Enumeration getElements()<br />
// liefert alle Buttons <strong>de</strong>r Gruppe<br />
384
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
AbstractButton<br />
ButtonGroup<br />
protected Vector Buttons<br />
><br />
public ButtonGroup()<br />
JToggleButton ><br />
public void add(AbstractButton b)<br />
public <strong>in</strong>t getButtonCount()<br />
public Enumeration getElement()<br />
public ButtonMo<strong>de</strong>l getSelection()<br />
public boolean isSelected(ButtonMo<strong>de</strong>l m)<br />
public void remove(AbstractButton b)<br />
public void setSelected(ButtonMo<strong>de</strong>l m,<br />
boolean b)<br />
JCheckBox<br />
JRadioButton<br />
> ><br />
public JCheckBox()<br />
public JRadioButton(Str<strong>in</strong>g text)<br />
public JCheckBox(Str<strong>in</strong>g text))<br />
public JRadionButton(Str<strong>in</strong>g text,<br />
public JCheckBox(Str<strong>in</strong>g text,<br />
boolean selected)<br />
boolean selected)<br />
> ><br />
…<br />
…<br />
Abb. JCheckBox und JRadioButton<br />
385
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.5.3 Listen und Comboboxen<br />
JList<br />
JList ist e<strong>in</strong> typisches Beispiel für das Mo<strong>de</strong>l-View-Controller-Pr<strong>in</strong>zip. Dabei stehen<br />
für die View (JList) mehrere Mo<strong>de</strong>lle zur Verfügung. Am wichtigsten ist das<br />
Datenmo<strong>de</strong>ll vom Typ ListMo<strong>de</strong>l, das Auswahlmo<strong>de</strong>ll (ListSelectionMo<strong>de</strong>l)<br />
und die Klassen für die Darstellung <strong>de</strong>r E<strong>in</strong>träge (ListCellRen<strong>de</strong>rer).<br />
Konstruktoren: JList verfügt über Konstruktoren, die e<strong>in</strong>e Liste aus e<strong>in</strong>em Vector<br />
o<strong>de</strong>r Array 299 erzeugen. Da die Daten nicht direkt <strong>in</strong> <strong>de</strong>r Liste gespeichert wer<strong>de</strong>n,<br />
son<strong>de</strong>rn <strong>in</strong> e<strong>in</strong>em separaten Vektor, ist je<strong>de</strong>rzeit e<strong>in</strong>Zugriff auf diese Daten möglich.<br />
Die Daten können also, nach<strong>de</strong>m sie <strong>in</strong> <strong>de</strong>r Liste angezeigt wur<strong>de</strong>n, nachträglich<br />
verän<strong>de</strong>rt wer<strong>de</strong>n. Das Problem ist dabei, dass die Komponenten von <strong>de</strong>r Än<strong>de</strong>rung<br />
nichts erfahren, da e<strong>in</strong> sehr triviales Mo<strong>de</strong>ll, ohne jegliche Vorkehrungen o<strong>de</strong>r<br />
Benachrichtigungen im Fall e<strong>in</strong>er Än<strong>de</strong>rung, durch <strong>de</strong>n Konstruktor verwen<strong>de</strong>t wur<strong>de</strong>.<br />
Darstellung und Auswahl <strong>de</strong>r <strong>in</strong> <strong>de</strong>r Liste enthaltenen Elemente: Die Anzahl <strong>de</strong>r<br />
Elemente, die gleichzeitig angezeigt wer<strong>de</strong>n sollen, kann mit <strong>de</strong>r Metho<strong>de</strong><br />
public void setVisibleRowCount(<strong>in</strong>t setVisibleRowCount)<br />
e<strong>in</strong>gestellt wer<strong>de</strong>n. Die Listenanzeige ist aber völlig von an<strong>de</strong>ren Mechanismen wie<br />
z.B. Bildlauf getrennt, d.h. e<strong>in</strong> Listenfeld führt ke<strong>in</strong>en automatischen Bildlauf durch.<br />
Zur Realisierung e<strong>in</strong>es Bildlaufbereichs muß e<strong>in</strong> JScrollPane-Objekt mit <strong>de</strong>r Liste<br />
als Parameter erzeugt wer<strong>de</strong>n und diese dann anschließend e<strong>in</strong>em Panel<br />
h<strong>in</strong>zugefügt wer<strong>de</strong>n.<br />
Entfernen, Modifizieren von E<strong>in</strong>trägen <strong>in</strong> bzw. aus <strong>de</strong>r Liste: Das Listenobjekt selbst<br />
verfügt über ke<strong>in</strong>e Metho<strong>de</strong>n, die es erlauben, e<strong>in</strong>en neuen E<strong>in</strong>trag <strong>in</strong> die List<br />
e<strong>in</strong>zufügen. Daten wer<strong>de</strong>n nicht <strong>in</strong> die Liste selbst gespeichert, son<strong>de</strong>rn wer<strong>de</strong>n über<br />
e<strong>in</strong>e Mo<strong>de</strong>ll-Schnittstelle ListMo<strong>de</strong>l verwaltet. Das ListMo<strong>de</strong>l besitzt folgen<strong>de</strong><br />
Metho<strong>de</strong>, mit <strong>de</strong>ren Hilfe auf die Daten zugegriffen wer<strong>de</strong>n kann:<br />
public void getElementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public <strong>in</strong>t getSize()<br />
Es besteht die Möglichkeit, die Daten<strong>in</strong>halte, statt sie <strong>in</strong> <strong>de</strong>r Liste selbst zu speichern<br />
o<strong>de</strong>r aus e<strong>in</strong>em Vektor zu lesen, mit Hilfe e<strong>in</strong>er Neu<strong>de</strong>f<strong>in</strong>ition von getElementAt()<br />
und getSize() z.B. onl<strong>in</strong>e zu berechnen o<strong>de</strong>r aus e<strong>in</strong>er Datenbank anzufor<strong>de</strong>rn.<br />
Die zur Anzeige benötigten Inhalte wer<strong>de</strong>n dann dynamisch durch die Liste vom<br />
vorhan<strong>de</strong>nen ListMo<strong>de</strong>l über <strong>de</strong>n zugehörigen In<strong>de</strong>x angefor<strong>de</strong>rt.<br />
Mit Hilfe <strong>de</strong>r Metho<strong>de</strong><br />
public void addDataListener(ListDataListener l)<br />
kann e<strong>in</strong> Listener zum Mo<strong>de</strong>ll h<strong>in</strong>zugefügt wer<strong>de</strong>n, <strong>de</strong>r dafür Sorge tragen kann, dass<br />
e<strong>in</strong>e Benachrichtigung <strong>de</strong>r Listener-Komponente stattf<strong>in</strong><strong>de</strong>t, falls e<strong>in</strong> Element<br />
modifiziert wur<strong>de</strong>. Da die Liste nichts über die Elemente, die angezeigt wer<strong>de</strong>n<br />
sollen, weiß, muß für je<strong>de</strong>s Element Breite und Höhe neu berechnet wer<strong>de</strong>n. Mit Hilfe<br />
von<br />
public void setFixedCellHeight(<strong>in</strong>t height)<br />
299 Übergabe beim Erstellen <strong>de</strong>s Elements<br />
386
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void setFixedCellWidth(<strong>in</strong>t width)<br />
<strong>de</strong>r Klasse JList können konstante Abmaße <strong>de</strong>r darzustellen<strong>de</strong>n Elemente <strong>de</strong>f<strong>in</strong>iert<br />
wer<strong>de</strong>n, wodurch die Berechnung bei gleichartigen Elementen, was die<br />
überwiegen<strong>de</strong> Mehrheit <strong>de</strong>r Fälle se<strong>in</strong> dürfte, entfallen kann.<br />
Dynamische Speicherung <strong>de</strong>r Objekte im Mo<strong>de</strong>ll durch E<strong>in</strong>satz von DefaultListMo<strong>de</strong>l:<br />
Das DefaulListMo<strong>de</strong>l verfügt über die Metho<strong>de</strong>n<br />
public void addElement(Object element)<br />
public boolean removeElement(Object obj)<br />
, die zum E<strong>in</strong>fügen und Entfernen von Listenelementen e<strong>in</strong>gesetzt wer<strong>de</strong>n können.<br />
Darstellung beliebiger, benutzer<strong>de</strong>f<strong>in</strong>ierter Zeichnungen und Objekte: Hierzu muß e<strong>in</strong><br />
Listenzellen-Ren<strong>de</strong>rer <strong>de</strong>f<strong>in</strong>iert wer<strong>de</strong>n. Dieser kann dafür Sorge tragen, dass<br />
entsprechen<strong>de</strong> Elemente benutzer<strong>de</strong>f<strong>in</strong>iert <strong>in</strong>nerhalb <strong>de</strong>r Liste gezeichnet wer<strong>de</strong>n.<br />
E<strong>in</strong> Listenzellen-Ren<strong>de</strong>rer kann e<strong>in</strong>e beliebige Klasse se<strong>in</strong>, die e<strong>in</strong>e Schnittstelle mit<br />
public Component getListCellRen<strong>de</strong>rerComponent(JList list,Object value,<br />
<strong>in</strong>t <strong>in</strong><strong>de</strong>x, boolean isSelected,boolean hasFocus)<br />
implementiert. Die Schnittstelle gibt e<strong>in</strong> Objekt vom Typ Component zurückgeben,<br />
das wie<strong>de</strong>rum die Metho<strong>de</strong>n pa<strong>in</strong>tComponent() und getPreferredSize()<br />
implementiert. pa<strong>in</strong>tComponent() sorgt für das Zeichnen <strong>de</strong>r Komponente,<br />
getPreferredSize() ist für das Berechnen <strong>de</strong>r Abmaße erfor<strong>de</strong>rlich, falls ke<strong>in</strong>e<br />
feste Größen <strong>de</strong>f<strong>in</strong>iert wur<strong>de</strong>n.<br />
387
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
JList<br />
...<br />
><br />
public JList()<br />
public JList(ListMo<strong>de</strong>l dataMo<strong>de</strong>l)<br />
public JList(Object[] listData)<br />
public JList(Vector listData)<br />
><br />
public void addListSelectionListener(ListSelectionListener l)<br />
public void addSelectionInterval(<strong>in</strong>t anchor,<strong>in</strong>t lead)<br />
public void clearSelection()<br />
protected ListSelectionMo<strong>de</strong>l createSelectionMo<strong>de</strong>l()<br />
…<br />
public AccessibleContext getAccessibleContext()<br />
public <strong>in</strong>t getAnchorSelectionIn<strong>de</strong>x()<br />
public Rectangle getCellBounds(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0,<strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
public ListCellRen<strong>de</strong>rer getCellRen<strong>de</strong>rer()<br />
…<br />
public void getSelectionMo<strong>de</strong>(<strong>in</strong>t selectionMo<strong>de</strong>)<br />
public <strong>in</strong>t getSelectedIn<strong>de</strong>x()<br />
public <strong>in</strong>t [] getSelectedIndices()<br />
public Object getSelectedValue()<br />
public Object [] getSelectedValues()<br />
public boolean isSelectedIn<strong>de</strong>x(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
…<br />
public void ListSelectionListener[] getSelectionListeners()<br />
public <strong>in</strong>t getMaxSelectionIn<strong>de</strong>x()<br />
public <strong>in</strong>t getM<strong>in</strong>SelectionIn<strong>de</strong>x()<br />
public ListMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
…<br />
public ListUI getUI()<br />
…<br />
public Str<strong>in</strong>g paramStr<strong>in</strong>g()<br />
…<br />
public void setListData(Object[] listData)<br />
public void setListData(Vector listData)<br />
public void setMo<strong>de</strong>l(ListMo<strong>de</strong>l mo<strong>de</strong>l)<br />
…<br />
public void setSelectionMo<strong>de</strong>l(ListSelectionMo<strong>de</strong>l selectionMo<strong>de</strong>l)<br />
public void setUI(ListUI ui)<br />
public void setValueIsAdjust<strong>in</strong>g(boolean b)<br />
public void setVisibleRowCount(<strong>in</strong>t visibleRowCount)<br />
public void updateUI()<br />
Abb.: Die Klasse JList<br />
388
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
ListMo<strong>de</strong>l<br />
public void addListDataListener(ListDataListener l)<br />
public void setUI(ListUI ui)<br />
public void setValueIsAdjust<strong>in</strong>g(boolean b)<br />
public void setVisibleRowCount(<strong>in</strong>t visibleRowCount)<br />
public void updateUI()<br />
AbstractListMo<strong>de</strong>l<br />
{ abstract }<br />
public void addListDataListener(ListDataListener l)<br />
…<br />
public void removeDataListener(ListDataListener l)<br />
DefaultListMo<strong>de</strong>ll<br />
><br />
public DefaultListMo<strong>de</strong>l()<br />
><br />
public void add(<strong>in</strong>t <strong>in</strong><strong>de</strong>x,Object element)<br />
public void addElement(Object obj)<br />
public void clear()<br />
public void conta<strong>in</strong>s(Object elem)<br />
public void copyInto(Object[] anArray)<br />
public Object elementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public Enumeration elements()<br />
…<br />
public Object get(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public Object getElementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
…<br />
public void <strong>in</strong>sertElementAt(Object obj,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public boolean isEmpty()<br />
public Object lastElement()<br />
…<br />
public Object remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public void removeAllElements()<br />
…<br />
public Object set(<strong>in</strong>t <strong>in</strong><strong>de</strong>x,Object element)<br />
public void setElementAt(Object obj,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public voiud setSize(<strong>in</strong>t newSize)<br />
public <strong>in</strong>t size()<br />
public Object[] toArray()<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
public void trimToSize()<br />
389
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
ListSelectionMo<strong>de</strong>l<br />
public void addListSelectionListener(ListSelectionListener x)<br />
public void addSelectionInterval(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0,<strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
public void clearSelection()<br />
public <strong>in</strong>t getAnchorSelectionIn<strong>de</strong>x()<br />
public <strong>in</strong>t getMaxSelectionIn<strong>de</strong>x()<br />
public <strong>in</strong>t getM<strong>in</strong>SelectionIn<strong>de</strong>x()<br />
public <strong>in</strong>t getSelectionMo<strong>de</strong>()<br />
…<br />
public boolean isSelectionEmpty()<br />
…<br />
public void setSelectionMo<strong>de</strong>()<br />
public void setValueIsAdjust<strong>in</strong>g(boolean valueIsAdjust<strong>in</strong>g)<br />
…<br />
protected EventListenerList listenerList<br />
DefaultListSelectionMo<strong>de</strong>l<br />
><br />
public DefaultListSelectionMo<strong>de</strong>l()<br />
><br />
public void addListSelectionListener(ListSelectionListener l)<br />
public void addSelectionInterval(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0,<strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
public void clearSelection()<br />
public Object clone()<br />
…<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
><br />
ListCellRen<strong>de</strong>rer<br />
public Componet getListCellRen<strong>de</strong>rerComponent(JList list,Object value,<br />
<strong>in</strong>t <strong>in</strong><strong>de</strong>x, boolean isSelected,boolean hasFocus)<br />
DefaultListCellRen<strong>de</strong>rer<br />
><br />
public DefaultListCellRen<strong>de</strong>rer()<br />
><br />
public void firePropertyChange(Str<strong>in</strong>g propertyName,boolean oldValue,boolean newValue)<br />
…<br />
public void validate()<br />
390
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComboBox<br />
Die JComboBox teilt dasselbe Darstellungsmo<strong>de</strong>ll (ListCellRen<strong>de</strong>rer) mit <strong>de</strong>r<br />
JList. Das Datenmo<strong>de</strong>ll ComboBoxMo<strong>de</strong>l ist von ListMo<strong>de</strong>l abgeleitet und<br />
erweitert es um Metho<strong>de</strong>n zum H<strong>in</strong>zufügen und Löschen von E<strong>in</strong>trägen. In e<strong>in</strong>er<br />
JComboBox kann immer nur e<strong>in</strong> E<strong>in</strong>trag ausgewählt se<strong>in</strong>.<br />
5.6.5.4 Quasi analoge Komponenten<br />
In Sw<strong>in</strong>g gibt es drei Kontrollelemente zur E<strong>in</strong>gabe und Visualisierung von<br />
Zahlenwerten aus e<strong>in</strong>em festgelegten Wertbereich: JScrollBar (e<strong>in</strong> e<strong>in</strong>facher<br />
Scrollbalken), JSli<strong>de</strong>r (e<strong>in</strong> komplexer Schieberegler mit Skala), JProgressBar<br />
(e<strong>in</strong>e Fortschrittsanzeige). Alle drei unterstützen das Boun<strong>de</strong>dRangeMo<strong>de</strong>l-<br />
Interface, das <strong>de</strong>n Zugriff auf die Attribute value, m<strong>in</strong>imum, maximum, extent bzw.<br />
valueAdjust<strong>in</strong>g (e<strong>in</strong> Flag, das anzeigt, ob <strong>de</strong>r Wert gera<strong>de</strong> e<strong>in</strong>gestellt wird) und<br />
die Implementierung von ChangeEvents sicherstellt.<br />
><br />
Boun<strong>de</strong>dRangeMo<strong>de</strong>l<br />
public void addChangeListener(ChangeListener x)<br />
public <strong>in</strong>t getExtent()<br />
public <strong>in</strong>t getMaximum()<br />
public <strong>in</strong>t getM<strong>in</strong>imum()<br />
public <strong>in</strong>t getValue()<br />
public boolean getValueIsAdjust<strong>in</strong>g()<br />
public void removeChangeListener(ChangeListener x)<br />
public void setExtent(<strong>in</strong>t newExtent)<br />
public void setMaximum(<strong>in</strong>t newMaximum)<br />
public void setRangeProperties(<strong>in</strong>t value, <strong>in</strong>t extent, <strong>in</strong>t m<strong>in</strong>,<br />
<strong>in</strong>t max, boolean adjust<strong>in</strong>g)<br />
public void setValue(<strong>in</strong>t newValue)<br />
public void setValueIsAdjust<strong>in</strong>g(boolean b)<br />
DefaultBoun<strong>de</strong>dRangeMo<strong>de</strong>l<br />
Abb.: Interface Boun<strong>de</strong>dRangeMo<strong>de</strong>l<br />
JScrollBar<br />
Attrribute. Die Klasse JScrollBar besitzt zusätzlich die Attribute unitIncrement für<br />
die Schrittweite, wenn auf die Pfeiltatsen gedrückt wird (Standard ist 1) und<br />
blockIncrement für e<strong>in</strong>en Mausklickj auf <strong>de</strong>n weißen H<strong>in</strong>tergrung <strong>de</strong>s<br />
Scrollbalkens (Standard ist 10).<br />
Konstruktor. Der wichtigste Konstruktor ist<br />
public JScrollBar(<strong>in</strong>t orientation, // Ausrichtung <strong>de</strong>s Schiebereglers<br />
<strong>in</strong>t value, // Anfangswert <strong>de</strong>s Schiebers<br />
<strong>in</strong>t extent, // Aus<strong>de</strong>hnung <strong>de</strong>s Schiebereglers<br />
<strong>in</strong>t m<strong>in</strong>, <strong>in</strong>t max)<br />
391
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Mit orientation wird die Ausrichtung (HORIZONTAL o<strong>de</strong>r VERTICAL) <strong>de</strong>s Schiebereglers<br />
festgelegt, m<strong>in</strong> gibt <strong>de</strong>n kle<strong>in</strong>sten, max <strong>de</strong>n größten möglichen Wert an.<br />
Mit extent wird die Aus<strong>de</strong>hnung <strong>de</strong>s Schiebers festgelegt. Sie muß m<strong>in</strong><strong>de</strong>stens e<strong>in</strong>s, kann auch<br />
größer se<strong>in</strong>.<br />
value ist <strong>de</strong>r Anfangswert <strong>de</strong>s Schiebers. Er muß zwischen m<strong>in</strong> und max – extent liegen.<br />
Metho<strong>de</strong>n.<br />
public <strong>in</strong>t getMaximum()<br />
public void setMaximum(<strong>in</strong>t maximum)<br />
public <strong>in</strong>t getVisibleAmount()<br />
// liefert die Aus<strong>de</strong>hnung <strong>de</strong>s Schiebers<br />
public void setVisibleAmount(<strong>in</strong>t extent)<br />
public <strong>in</strong>t getValue()<br />
public void setValue(<strong>in</strong>t value)<br />
public <strong>in</strong>t getUnitIncrement()<br />
// gibt an, um welchen Betrag <strong>de</strong>r Wert <strong>de</strong>s Schiebereglers sich verän<strong>de</strong>rt, wenn <strong>de</strong>r Anwen<strong>de</strong>r<br />
// e<strong>in</strong>en Pfeilbutton betätigt<br />
public void setUnitIncrement(<strong>in</strong>t unitIncrement)<br />
public <strong>in</strong>t getBlockIncremnent()<br />
// ermittelt <strong>de</strong>n Betrag <strong>de</strong>r Än<strong>de</strong>rung, wenn zwischen Schieber und Pfeiltatsen geklickt wird.<br />
public void setBlockIncrement(<strong>in</strong>t blockIncrement)<br />
Ereignisbehandlung. Aus Kompatibilitätsgrün<strong>de</strong>n zur AWT-Scrollbar implementiert<br />
die Klasse das Interface Adjustable und unterstützt <strong>de</strong>n AdjustmentListener.<br />
Wird e<strong>in</strong> Wert e<strong>in</strong>er JScrollBar verän<strong>de</strong>rt, sen<strong>de</strong>t sie e<strong>in</strong> AdjustmentEvent an<br />
registrierte Listener. Diese müssen das Interface AdjustmentListener<br />
implementieren und wer<strong>de</strong>n durch addjustmentListener() registiert. Mit<br />
getValueAdjust<strong>in</strong>g() kann festgestellt wer<strong>de</strong>n, auf welche Weise <strong>de</strong>r Wert<br />
verän<strong>de</strong>rt wird. Rückgabe von true erfolgt dann, wenn <strong>de</strong>r Anwen<strong>de</strong>r <strong>de</strong>n Schieber<br />
betätigt. false wird zurückgegeben, wenn die Än<strong>de</strong>rung durch e<strong>in</strong>en Mausklick auf<br />
e<strong>in</strong>en Button o<strong>de</strong>r auf die Fläche zwischen Button und Schieber ausgelöst wird.<br />
JSli<strong>de</strong>r<br />
Wichtiger (konzeptioneller) Unterschied zum JScrollbar:<br />
1. E<strong>in</strong> JSli<strong>de</strong>r kann e<strong>in</strong>e Anzeigeskala mit grober und fiener Beschriftung haben.<br />
2. E<strong>in</strong> JSli<strong>de</strong>r kennt ke<strong>in</strong>e unterschiedlichen Schiebergrößen. Ihre Aus<strong>de</strong>hung ist immer 1.<br />
Die Klasse JSli<strong>de</strong>r ist e<strong>in</strong> Schieberegler mit optionaler Skala. Die Skalenstriche<br />
nennen sich Ticks und existieren <strong>in</strong> zwei Längen: majorTicks, m<strong>in</strong>orTicks.<br />
Wichtigster Konstruktor.<br />
public JSli<strong>de</strong>r(<strong>in</strong>t orientation, <strong>in</strong>t m<strong>in</strong>, <strong>in</strong>t max, <strong>in</strong>t value)<br />
Metho<strong>de</strong>n.<br />
public <strong>in</strong>t getMaximum()<br />
public void setMaximum(<strong>in</strong>t maximum)<br />
public <strong>in</strong>t getM<strong>in</strong>imum()<br />
public void setM<strong>in</strong>imum(<strong>in</strong>t m<strong>in</strong>imum)<br />
392
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public <strong>in</strong>t getValue()<br />
public void setValue(<strong>in</strong>t value)<br />
public <strong>in</strong>t getMajorTickSpac<strong>in</strong>g()<br />
// Vorgabe <strong>de</strong>s Abstands <strong>de</strong>r großen Markierung<br />
public void setMajorTockSpac<strong>in</strong>g(<strong>in</strong>t n)<br />
public <strong>in</strong>t getM<strong>in</strong>orTickSpac<strong>in</strong>g()<br />
public void setM<strong>in</strong>orTickSpac<strong>in</strong>g(<strong>in</strong>t n)<br />
// Vorgabe <strong>de</strong>s Abstands <strong>de</strong>r kle<strong>in</strong>en Markierung<br />
public void setPa<strong>in</strong>tTicks(boolen b)<br />
// Anzeige <strong>de</strong>r Anzeigeskala durch Übergabe von true<br />
public void setPa<strong>in</strong>tLabels(boolean b)<br />
// Anzeige <strong>de</strong>r Beschriftung durch Übergabe von true<br />
Ereignisbehandlung. E<strong>in</strong> JSli<strong>de</strong>r sen<strong>de</strong>t e<strong>in</strong> ChangeEvent, wenn se<strong>in</strong> Wert<br />
verän<strong>de</strong>rt wird. Zur Reaktion auf dieses Ereignis muß das Interface<br />
ChangeListener implementiert se<strong>in</strong>, und das zu implementieren<strong>de</strong> Objekt durch<br />
<strong>de</strong>n Aufruf addChangeListener() registriert se<strong>in</strong>. Mit getValueIsAdjust<strong>in</strong>g()<br />
kann festgestellt wer<strong>de</strong>n, ob die Än<strong>de</strong>rung Bestandteil e<strong>in</strong>er Kette von Än<strong>de</strong>rungen<br />
sit o<strong>de</strong>r ob sie e<strong>in</strong>zeln aufgetreten ist.<br />
Bsp. 300 :<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class JSli<strong>de</strong>rs extends JFrame<br />
{<br />
public JSli<strong>de</strong>rs()<br />
{<br />
super("Us<strong>in</strong>g JSli<strong>de</strong>r");<br />
// W<strong>in</strong>dowUtilities.setNativeLookAndFeel();<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 />
{ System.exit(0); }<br />
});<br />
Conta<strong>in</strong>er content = getContentPane();<br />
content.setBackground(Color.white);<br />
JSli<strong>de</strong>r sli<strong>de</strong>r1 = new JSli<strong>de</strong>r();<br />
sli<strong>de</strong>r1.setBor<strong>de</strong>r(Bor<strong>de</strong>rFactory.createTitledBor<strong>de</strong>r<br />
("JSli<strong>de</strong>r without Tick Marks"));<br />
content.add(sli<strong>de</strong>r1, Bor<strong>de</strong>rLayout.NORTH);<br />
JSli<strong>de</strong>r sli<strong>de</strong>r2 = new JSli<strong>de</strong>r();<br />
sli<strong>de</strong>r2.setBor<strong>de</strong>r(Bor<strong>de</strong>rFactory.createTitledBor<strong>de</strong>r<br />
("JSli<strong>de</strong>r with Tick Marks"));<br />
sli<strong>de</strong>r2.setMajorTickSpac<strong>in</strong>g(20);<br />
sli<strong>de</strong>r2.setM<strong>in</strong>orTickSpac<strong>in</strong>g(5);<br />
sli<strong>de</strong>r2.setPa<strong>in</strong>tTicks(true);<br />
content.add(sli<strong>de</strong>r2, Bor<strong>de</strong>rLayout.CENTER);<br />
JSli<strong>de</strong>r sli<strong>de</strong>r3 = new JSli<strong>de</strong>r();<br />
sli<strong>de</strong>r3.setBor<strong>de</strong>r(Bor<strong>de</strong>rFactory.createTitledBor<strong>de</strong>r<br />
("JSli<strong>de</strong>r with Tick Marks & Labels"));<br />
sli<strong>de</strong>r3.setMajorTickSpac<strong>in</strong>g(20);<br />
sli<strong>de</strong>r3.setM<strong>in</strong>orTickSpac<strong>in</strong>g(5);<br />
sli<strong>de</strong>r3.setPa<strong>in</strong>tTicks(true);<br />
sli<strong>de</strong>r3.setPa<strong>in</strong>tLabels(true);<br />
content.add(sli<strong>de</strong>r3, Bor<strong>de</strong>rLayout.SOUTH);<br />
pack();<br />
300 vgl. pr56370<br />
393
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
new JSli<strong>de</strong>rs();<br />
}<br />
}<br />
JProgressBar<br />
Die Klasse JProgressBar zeigt e<strong>in</strong>en im Programm berechneten Fortschritt e<strong>in</strong>es<br />
Vorgangs an. Im Fortschritts-Balken kann e<strong>in</strong> Text angezeigt wer<strong>de</strong>n<br />
Konstruktoren.<br />
public JProgressBar(<strong>in</strong>t orient)<br />
public JProgressBar(<strong>in</strong>t m<strong>in</strong>, <strong>in</strong>t max)<br />
public JProgressBar(<strong>in</strong>t orient,<strong>in</strong>t m<strong>in</strong>,<strong>in</strong>t max)<br />
Metho<strong>de</strong>n.<br />
public void setStr<strong>in</strong>gPa<strong>in</strong>ted(boolean b)<br />
// Standardmäßig wird die Fortschrittsanzeige ohne Beschriftung dargestellt. Durch Aufruf von<br />
// setStr<strong>in</strong>gPa<strong>in</strong>ted() mit Übergabe true kann e<strong>in</strong> prozentualer Fortschrittswert angezeigt<br />
// wer<strong>de</strong>n.<br />
public void setValue(<strong>in</strong>t n)<br />
// Verän<strong>de</strong>rung <strong>de</strong>r grafischen darstellung <strong>de</strong>s Fortschritts<br />
public <strong>in</strong>t getValue()<br />
// Abfrage <strong>de</strong>s Werts <strong>de</strong>s grafischen Fortschritts<br />
Bsp. 301 :<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
import javax.sw<strong>in</strong>g.event.*;<br />
public class JProgressBarDemo extends JFrame<br />
{<br />
protected <strong>in</strong>t m_m<strong>in</strong> = 0;<br />
protected <strong>in</strong>t m_max = 100;<br />
protected <strong>in</strong>t m_counter = 0;<br />
protected JProgressBar jpb;<br />
public JProgressBarDemo()<br />
{<br />
301 pr56370<br />
394
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
super("JProgressBar Demo");<br />
setSize(300,50);<br />
UIManager.put("ProgressBar.selectionBackground", Color.black);<br />
UIManager.put("ProgressBar.selectionForeground", Color.white);<br />
UIManager.put("ProgressBar.foreground", new Color(8,32,128));<br />
jpb = new JProgressBar();<br />
jpb.setM<strong>in</strong>imum(m_m<strong>in</strong>);<br />
jpb.setMaximum(m_max);<br />
jpb.setStr<strong>in</strong>gPa<strong>in</strong>ted(true);<br />
JButton start = new JButton("Start");<br />
start.addActionListener(new ActionListener() {<br />
public void actionPerformed(ActionEvent e) {<br />
Thread runner = new Thread() {<br />
public void run() {<br />
m_counter = m_m<strong>in</strong>;<br />
while (m_counter
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponente<br />
JScrollBar<br />
protected <strong>in</strong>t blockIncrement<br />
protected BoundRangeMo<strong>de</strong>l mo<strong>de</strong>l<br />
protected <strong>in</strong>t orientation<br />
protected <strong>in</strong>t unitIncrement<br />
JProgressBar<br />
protected ChangeEvent changeEvent<br />
protected ChangeListener changeListener<br />
protected BoundRangeMo<strong>de</strong>l mo<strong>de</strong>l<br />
protected <strong>in</strong>t orientation<br />
protected boolean pa<strong>in</strong>tBor<strong>de</strong>r<br />
protected boolean pa<strong>in</strong>tStr<strong>in</strong>g<br />
protected Str<strong>in</strong>g progressStr<strong>in</strong>g<br />
> ><br />
public JScrollBar()<br />
public JProgressBar()<br />
public JScrollBar(<strong>in</strong>t orientation)<br />
…<br />
public JScrollBar(<strong>in</strong>t orientation, ><br />
<strong>in</strong>t value, <strong>in</strong>t extent,<br />
public void addChangeListener(<br />
<strong>in</strong>t m<strong>in</strong>, <strong>in</strong>t max) ChangeListener l)<br />
> protected ChangeListener<br />
public void AddAdjustmentListener(<br />
createChangeListener<br />
AdjustmentListener l)<br />
…<br />
….<br />
public <strong>in</strong>t getBlockIncrement()<br />
public <strong>in</strong>t getMaximum()<br />
public Dimension getMaximumSize()<br />
…<br />
JSli<strong>de</strong>r<br />
public ChangeEvent changeEvent<br />
public ChangeListener changeListener<br />
><br />
public JSli<strong>de</strong>r()<br />
><br />
…<br />
Abb.: Die Klassen JProgressBar, JScrollBar und JSli<strong>de</strong>r<br />
396
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.5.5 Tabellen<br />
Das Mo<strong>de</strong>ll für JTable muß das Interface TableMo<strong>de</strong>l implementieren. Die Klasse<br />
AbstractTableMo<strong>de</strong>l kann als Ableitungsbasis für die konkrete Datenklasse<br />
verwen<strong>de</strong>t wer<strong>de</strong>n. Die Klasse DefaultTableMo<strong>de</strong>l enthält e<strong>in</strong>e Implementierung<br />
aus <strong>in</strong>e<strong>in</strong>an<strong>de</strong>r verschachtelten Vector-Objekten.<br />
Konstruktoren.<br />
public JTable(Object[][] rowData,Object ColumnNanes)<br />
Im zweidimensionalen Array enthält die erste Dimension die Zeilen, die zweite die Spalten. Zur<br />
Darstellung <strong>in</strong> <strong>de</strong>r Tabelle wer<strong>de</strong>n die Arrayelemente mit toStr<strong>in</strong>g() <strong>in</strong> Str<strong>in</strong>gs umgewan<strong>de</strong>lt. Das 2.<br />
Array enthält e<strong>in</strong> Array mit Str<strong>in</strong>gs, die als Spaltenköpfe angezeigt wer<strong>de</strong>n.<br />
public JTable(Vector rowData,Vector columnNames)<br />
Daten und Spalten wer<strong>de</strong>n <strong>in</strong> e<strong>in</strong>em Vector übergeben. Der Datenvektor rowData muß für je<strong>de</strong> Zeile<br />
e<strong>in</strong>en Subvektor mit <strong>de</strong>n Datenelementen <strong>de</strong>r Zeile enthalten.<br />
public JTable(TableMo<strong>de</strong>l dm, TableColumnMo<strong>de</strong>l cm, ListSelectionMo<strong>de</strong>l sm)<br />
Das TableMo<strong>de</strong>l stellt Daten zur Verfügung.<br />
Das TableColumnMo<strong>de</strong>l <strong>de</strong>f<strong>in</strong>iert die Spalten.<br />
Das ListSelectionMo<strong>de</strong>l ist für die Auswahl von Tabellenelelementen zuständig.<br />
Bsp.: Erzeugen e<strong>in</strong>er e<strong>in</strong>fachen Tabelle<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
public class SimpleTable extends JFrame<br />
{<br />
public static f<strong>in</strong>al Str<strong>in</strong>g[][] DATEN =<br />
{<br />
{"Uebungsblatt 1", "B<strong>in</strong>aere Baumknoten <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 1a", "Baumansichten <strong>de</strong>r <strong>Java</strong> Foundation Classes"},<br />
{"Uebungsblatt 2", "Verarbeitung b<strong>in</strong>aerer Suchbaumknoten"},<br />
{"Uebungsblatt 3", "Die generische Klasse B<strong>in</strong>aererSuchbaum <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 4", "Die generische Klasse AvlBaum <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 5", "Perfekt ausgeglichene Baeume"},<br />
{"Uebungsblatt 6", "Rot-Schwarz-Baeume"},<br />
{"Uebungsblatt 7", "AA-Baeume"},<br />
{"Uebungsblatt 8", "Splay-Baeume"},<br />
{"Uebungsblatt 9", "Bayer-Baeume"},<br />
{"Uebungsplatt 10", "Auf Platte / Diskette gespeicherte Bayer-Bäume"},<br />
{"Uebungsblatt 11", "Hash-Tabellen"},<br />
{"Uebungsblatt 12", "Heap-Algorithmen"},<br />
{"Uebungsblatt 13", "Vorrangwarteschlangen"},<br />
{"Uebungsblatt 14", "B<strong>in</strong>omial Queue, Fibonacci Heap"},<br />
{"Uebungsblatt 15", "Backtrack<strong>in</strong>g-Algorithmen"},<br />
{"Uebungsblatt 16",<br />
"Ansichten <strong>de</strong>r <strong>Java</strong> Foundation Classes JList und JTable"},<br />
{"Uebungsblatt 17", "Skip Lists"}<br />
};<br />
public static f<strong>in</strong>al Str<strong>in</strong>g[] COLHEADS =<br />
{<br />
"Ausgabe", "Titelthema"<br />
};<br />
// Konstruktor<br />
public SimpleTable()<br />
{<br />
super("Uebersicht zu <strong>de</strong>n Uebungen <strong>in</strong> AD");<br />
JTable table = new JTable(DATEN, COLHEADS);<br />
Conta<strong>in</strong>er cp = getContentPane();<br />
cp.add(new JLabel("Uebungen zu AD im WS 02"), "North");<br />
cp.add(new JScrollPane(table), "Center");<br />
}<br />
397
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
SimpleTable frame = new SimpleTable();<br />
frame.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 />
frame.setLocation(100, 100);<br />
frame.setSize(300, 200);<br />
frame.setVisible(true);<br />
}<br />
}<br />
Das Programm erzeugt die folgen<strong>de</strong> Tabelle:<br />
Abb.: Tabelle, die von SimpleTable erzeugt wird<br />
Konfiguration <strong>de</strong>r Tabelle.<br />
Mit public void setRowHeight(<strong>in</strong>t rowHeight) wird die Gesamthöhe e<strong>in</strong>er Zeile festgelegt.<br />
Alle Zeilen s<strong>in</strong>d dabei gleich hoch.<br />
Mit public void setRowMarg<strong>in</strong>(<strong>in</strong>t rowMartg<strong>in</strong>) wird <strong>de</strong>r am oberen Rand und unteren<br />
Rand je<strong>de</strong>r Zeile frei bleiben<strong>de</strong> Platz bestimmt. Der für <strong>de</strong>n Inhalt <strong>de</strong>r Zelle verfügbare Platz ergibt<br />
sich aus <strong>de</strong>r Zellenhöhe m<strong>in</strong>us oberem und unterem Rand. Durch Aufruf von public void<br />
setIntercellSpac<strong>in</strong>g(Dimension newSpac<strong>in</strong>g) kann (zusammen mit <strong>de</strong>m vertikalen) auch<br />
<strong>de</strong>r horizontale Rand <strong>de</strong>r Zellenelemente festgelegt wer<strong>de</strong>n.<br />
Standardmäßig wer<strong>de</strong>n die Zellen e<strong>in</strong>er JTable mit senkrechten und waagrechten Begrenzungsl<strong>in</strong>ien<br />
vone<strong>in</strong>an<strong>de</strong>r getrennt. Mit public void setShowGrid(boolean b) können bei<strong>de</strong> L<strong>in</strong>ienarten<br />
zugleich an- o<strong>de</strong>r ausgeschaltet wer<strong>de</strong>n. Sollen die horizontalen o<strong>de</strong>r vertikalen L<strong>in</strong>ien separat<br />
aktiviert o<strong>de</strong>r <strong>de</strong>aktiviert wer<strong>de</strong>n, können<br />
public void setShowHorizontalL<strong>in</strong>es(boolean b)<br />
public void setShowVerticalL<strong>in</strong>es(boolean b)<br />
verwen<strong>de</strong>t wer<strong>de</strong>n. Das Verän<strong>de</strong>rn <strong>de</strong>r Zellen ist <strong>in</strong> begrenzter Weise mit folgen<strong>de</strong>n Metho<strong>de</strong>n<br />
möglich:<br />
public void setGridColor(Color newColor)<br />
// verän<strong>de</strong>rt die Farbe, mit <strong>de</strong>r Gitterl<strong>in</strong>ien angezeigt wer<strong>de</strong>n<br />
public void setSelectionForeground(Color selectionForeground)<br />
public void setSelectionBackground(Color selectionBackground)<br />
Das Verhalten <strong>de</strong>r Tabelle, nach<strong>de</strong>m die Breite e<strong>in</strong>er e<strong>in</strong>zelnen Spalte verän<strong>de</strong>rt wur<strong>de</strong>, bestimmt<br />
public void setAutoResize(<strong>in</strong>t mo<strong>de</strong>)<br />
398
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Der dadurch frei wer<strong>de</strong>n<strong>de</strong> o<strong>de</strong>r zusätzlich benötigte Platz kann auf unterschiedliche Weise <strong>de</strong>n<br />
übrigen Spalten zugeordnet wer<strong>de</strong>n. Der Parameter mo<strong>de</strong> kann folgen<strong>de</strong> Werte annehmen:<br />
Modus<br />
AUTO_RESIZE_OFF<br />
Be<strong>de</strong>utung<br />
ke<strong>in</strong>e automatische Größenanpassung <strong>de</strong>r Spalten.<br />
Wur<strong>de</strong> die Tabelle <strong>in</strong> JScrollPane verpackt, bekommt<br />
sie nötigenfalls e<strong>in</strong>en horizontale Schieberegler.<br />
AUTO_RESIZE_LAST_COLUMN Die letzte Spalte wird zum Größenausgleich<br />
verwen<strong>de</strong>t. Dadurch reduziert sich <strong>de</strong>r Platz für die<br />
letzte Spalte, wenn e<strong>in</strong>e an<strong>de</strong>re Spalte vergrößert<br />
wird, und er erhöht sich, wenn sie verkle<strong>in</strong>ert wird.<br />
AUTO_RESIZE_NEXT_COLUMN<br />
AUTO_RESIZE_SUBSEQUENT_COLUMNS<br />
AUTO_RESIZE_ALL_COLUMNS<br />
Selektieren von Elementen<br />
Die recht neben <strong>de</strong>r modifizierten Spalte liegen<strong>de</strong><br />
Spalte wird zum Größenausgleich verwen<strong>de</strong>t.<br />
Die Größenän<strong>de</strong>rung wird gleichmäßig auf alle<br />
nachfolgen<strong>de</strong>n Spalten verteilt.<br />
Die Größenän<strong>de</strong>rung wird auf alle Spalten <strong>de</strong>r Tabelle<br />
verteilt.<br />
Selektionsmodi: Die folgen<strong>de</strong>n Metho<strong>de</strong>n <strong>de</strong>r Klasse JTable regeln die Selektion:<br />
public void setRowSelectionAllowed(boolean flag)<br />
Zeilenweise Selektion nach Aufruf dieser Metho<strong>de</strong> mit true als Argument.<br />
public void setColumnSelectionAllowed(boolean flag)<br />
Spaltenweise Selektion nach Aufruf dieser Metho<strong>de</strong> mit true als Argument.<br />
Durch Übergabe von false können Selektionsmarken ausgeschaltet wer<strong>de</strong>n und nur noch e<strong>in</strong>zelne<br />
Zellen selektiert wer<strong>de</strong>n. Standardmäßig kann zeilen-, aber nicht spaltenweise selektiert wer<strong>de</strong>n.<br />
public void setSelectionMo<strong>de</strong>(<strong>in</strong>t selectionMo<strong>de</strong>)<br />
legt fest, ob e<strong>in</strong> e<strong>in</strong>zelnes Element, e<strong>in</strong> zusammenhängen<strong>de</strong>r Bereich o<strong>de</strong>r mehrere Bereiche<br />
selektiert wer<strong>de</strong>n können. Hier ist e<strong>in</strong>e <strong>de</strong>r Konstanten SINGLE_SELECTION,<br />
SINGLE_INTERVAL_SELECTION, o<strong>de</strong>r MULTIPLE_INTERNAL_SELECTION <strong>de</strong>r Klasse<br />
ListSelectionMo<strong>de</strong>l zu übergeben.<br />
public void setSelectionEnabled(boolean flag)<br />
Der Aufruf dieser Metho<strong>de</strong> mit true als Argument bewirkt: Zeile und Spalten können gleichzeitig<br />
markiert und so zusammenhängen<strong>de</strong> rechteckige Bereiche von Zellen (e<strong>in</strong>schl. e<strong>in</strong>er e<strong>in</strong>zelnen)<br />
selektiert wer<strong>de</strong>n.<br />
Abfragen <strong>de</strong>r Selektion. Die folgen<strong>de</strong>n Metho<strong>de</strong>n <strong>de</strong>r Klasse JTable bestimmen, welche Elemente<br />
selektiert wur<strong>de</strong>n:<br />
public <strong>in</strong>t getSelectionRow()<br />
public <strong>in</strong>t getSelectionColumn()<br />
Die bei<strong>de</strong>n Metho<strong>de</strong>n liefern die selektierte Zeile bzw. Spalte, wenn <strong>de</strong>r Selektionsmodus<br />
SINGLE_SELECTION ist. Die 1. Zeile und Spalte haben jeweils <strong>de</strong>n In<strong>de</strong>x 0. Erlaubt <strong>de</strong>r aktuelle<br />
Selektionsmodus das Selektieren ganzer Zeilen und Spalten, dann impliziert das Ergebnis: Alle<br />
Elemente dieser Zeile bzw. Spalte s<strong>in</strong>d selektiert. Falls ke<strong>in</strong>e Elemente selektiert s<strong>in</strong>d, wird –1<br />
zurückgegeben.<br />
public <strong>in</strong>t [] getSelectedRows()<br />
public <strong>in</strong>t [] getSelectedCloumns()<br />
Falls e<strong>in</strong>er <strong>de</strong>r Mehrfachselektionsmodi aktiviert ist, können über diese bei<strong>de</strong>n Metho<strong>de</strong>n Arrays mit<br />
allen selektierten Zeilen und Spalten beschafft wer<strong>de</strong>n. Falls ke<strong>in</strong>e Elemente selektiert s<strong>in</strong>d, wird e<strong>in</strong><br />
leeres Array zurückgegeben.<br />
Verän<strong>de</strong>rn <strong>de</strong>r Selektion. JTable stellt Metho<strong>de</strong>n bereit mit <strong>de</strong>nen die Selektion programmgesteuert<br />
verän<strong>de</strong>rt wer<strong>de</strong>n kann:<br />
public void selectAll()<br />
public void clearSelection()<br />
public void setRowSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
399
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Markieren e<strong>in</strong>es zusammenhängen<strong>de</strong>n Bereichs von Zeilen<br />
public void addRowSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
H<strong>in</strong>zufügen e<strong>in</strong>es zusammenhängen<strong>de</strong>n Bereichs zur aktuellen Selektion<br />
public void removeRowSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
Entferenen e<strong>in</strong>es zusammenhängen<strong>de</strong>n Bereichs aus <strong>de</strong>r aktuellen Selektion<br />
public void setColumnSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
public void addColumnSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
public void removeColumnSelectionIntervall(<strong>in</strong>t <strong>in</strong><strong>de</strong>x0, <strong>in</strong>t <strong>in</strong><strong>de</strong>x1)<br />
Zugriff auf <strong>de</strong>n Inhalt <strong>de</strong>r Tabelle<br />
Daten <strong>in</strong> <strong>de</strong>r Tabelle. Unabhängig von <strong>de</strong>r aktuellen Selektion kann auf <strong>de</strong>n Inhalt <strong>de</strong>r Tabelle<br />
zugegriffen wer<strong>de</strong>n.<br />
pulic <strong>in</strong>t getRowCount()<br />
public <strong>in</strong>t getColumnCount()<br />
liefern die aktuelle Zeilen- bzw. Spaltenanzahl <strong>de</strong>r Tabelle.<br />
Editieren von Tabellenelementen. Nach e<strong>in</strong>em Doppelklick auf e<strong>in</strong>e Zelle kann <strong>de</strong>r Anwen<strong>de</strong>r die <strong>in</strong><br />
diesem Element enthaltenen Daten verän<strong>de</strong>rn. JTable besitzt eigene Metho<strong>de</strong>n, mit <strong>de</strong>nen abgefragt<br />
wer<strong>de</strong>n kann, ob und <strong>in</strong> welcher Zelle die Tabelle gera<strong>de</strong> editiert wird.<br />
Das Tabellenmo<strong>de</strong>ll. E<strong>in</strong> eigenes Tabellenmo<strong>de</strong>ll muß das Interface TableMo<strong>de</strong>l<br />
implementieren und bei <strong>de</strong>r Instanzierung an <strong>de</strong>n Konstruktor <strong>de</strong>r JTable<br />
übergeben. Wahlweise kann nach Instanzierung auf das Mo<strong>de</strong>ll mit folgen<strong>de</strong>n<br />
Metho<strong>de</strong>n <strong>de</strong>r Klasse JTable zugegriffen wer<strong>de</strong>n:<br />
public void setMo<strong>de</strong>l(TableMo<strong>de</strong>l newMo<strong>de</strong>l)<br />
public TableMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
Das Interface TableMo<strong>de</strong>l <strong>de</strong>f<strong>in</strong>iert folgen<strong>de</strong> Metho<strong>de</strong>n:<br />
public void addTableMo<strong>de</strong>lListener(TableMo<strong>de</strong>lListener l)<br />
public Class getColumnClass(<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public <strong>in</strong>t getColumnCount()<br />
public <strong>in</strong>t getRowCount()<br />
public Object getValueAt(<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public boolean isCellEditable(<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public void removeTableMo<strong>de</strong>lLister(TableMo<strong>de</strong>lListener l)<br />
public void setValueAt(Object aValue,<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
Das Spaltenmo<strong>de</strong>ll. Das Spaltenmo<strong>de</strong>ll e<strong>in</strong>er JTable muß das Interface<br />
TableColumnMo<strong>de</strong>l aus <strong>de</strong>m Paket javax.sw<strong>in</strong>g.table implementieren. Es wird bei<br />
<strong>de</strong>r Instanzierung e<strong>in</strong>er JTable an <strong>de</strong>n Konstruktor übergeben. Ohne weitere<br />
Ableitung kann die Standard-Implementierung DefaultTableColumnMo<strong>de</strong>l<br />
verwen<strong>de</strong>t wer<strong>de</strong>n. Sie stellt Metho<strong>de</strong>n zum H<strong>in</strong>zufügen bzw. Entfernen von<br />
Spaltenobjekten (Typ TableColumn) bereit.<br />
public void addColumn(TableColumn aColumn)<br />
public void removeColumn(TableColumn aColumn)<br />
Bsp.:<br />
import java.awt.*;<br />
import java.awt.event.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
import javax.sw<strong>in</strong>g.table.*;<br />
public class SimpleTable2 extends JFrame<br />
{<br />
400
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public static f<strong>in</strong>al Str<strong>in</strong>g[][] DATEN =<br />
{<br />
{"Uebungsblatt 1", "B<strong>in</strong>aere Baumknoten <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 1a", "Baumansichten <strong>de</strong>r <strong>Java</strong> Foundation Classes"},<br />
{"Uebungsblatt 2", "Verarbeitung b<strong>in</strong>aerer Suchbaumknoten"},<br />
{"Uebungsblatt 3", "Die generische Klasse B<strong>in</strong>aererSuchbaum <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 4", "Die generische Klasse AvlBaum <strong>in</strong> <strong>Java</strong>"},<br />
{"Uebungsblatt 5", "Perfekt ausgeglichene Baeume"},<br />
{"Uebungsblatt 6", "Rot-Schwarz-Baeume"},<br />
{"Uebungsblatt 7", "AA-Baeume"},<br />
{"Uebungsblatt 8", "Splay-Baeume"},<br />
{"Uebungsblatt 9", "Bayer-Baeume"},<br />
{"Uebungsplatt 10", "Auf Platte / Diskette gespeicherte Bayer-Bäume"},<br />
{"Uebungsblatt 11", "Hash-Tabellen"},<br />
{"Uebungsblatt 12", "Heap-Algorithmen"},<br />
{"Uebungsblatt 13", "Vorrangwarteschlangen"},<br />
{"Uebungsblatt 14", "B<strong>in</strong>omial Queue, Fibonacci Heap"},<br />
{"Uebungsblatt 15", "Backtrack<strong>in</strong>g-Algorithmen"},<br />
{"Uebungsblatt 16",<br />
"Ansichten <strong>de</strong>r <strong>Java</strong> Foundation Classes JList und JTable"},<br />
{"Uebungsblatt 17", "Skip Lists"}<br />
};<br />
public static f<strong>in</strong>al Str<strong>in</strong>g[] COLHEADS =<br />
{<br />
"Ausgabe", "Titelthema"<br />
};<br />
// Konstruktor<br />
public SimpleTable2()<br />
{<br />
super("Uebersicht zu <strong>de</strong>n Uebungen <strong>in</strong> AD");<br />
//Spaltenmo<strong>de</strong>ll erzeugen<br />
DefaultTableColumnMo<strong>de</strong>l cm = new DefaultTableColumnMo<strong>de</strong>l();<br />
for (<strong>in</strong>t i = 0; i < COLHEADS.length; i++)<br />
{<br />
TableColumn col = new TableColumn(i, i == 2 ? 150 : 60);<br />
col.setHea<strong>de</strong>rValue(COLHEADS[i]);<br />
cm.addColumn(col);<br />
}<br />
//Tabellenmo<strong>de</strong>ll erzeugen<br />
TableMo<strong>de</strong>l tm = new AbstractTableMo<strong>de</strong>l()<br />
{<br />
public <strong>in</strong>t getRowCount()<br />
{<br />
return DATEN.length;<br />
}<br />
public <strong>in</strong>t getColumnCount()<br />
{<br />
return DATEN[0].length;<br />
}<br />
public Object getValueAt(<strong>in</strong>t row, <strong>in</strong>t column)<br />
{<br />
return DATEN[row][column];<br />
}<br />
};<br />
JTable table = new JTable(tm, cm);<br />
Conta<strong>in</strong>er cp = getContentPane();<br />
cp.add(new JLabel("Uebungen zu AD im WS 02"), "North");<br />
cp.add(new JScrollPane(table), "Center");<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
SimpleTable2 frame = new SimpleTable2();<br />
frame.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 />
401
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
System.exit(0);<br />
}<br />
});<br />
frame.setLocation(100, 100);<br />
frame.setSize(300, 200);<br />
frame.setVisible(true);<br />
}<br />
}<br />
Ren<strong>de</strong>r<strong>in</strong>g 302 <strong>de</strong>r Zellen<br />
public TableCellRen<strong>de</strong>rer getDefaultRen<strong>de</strong>rer(Class columnClass)<br />
public void setDefaultCellRen<strong>de</strong>rer(Class columnClass,<br />
TableCellRen<strong>de</strong>rer ren<strong>de</strong>rer)<br />
Sofern nicht <strong>in</strong> <strong>de</strong>n Tabellenspalten e<strong>in</strong> eigener Ren<strong>de</strong>rer bestimmt ist, ist <strong>de</strong>r<br />
Standard-Ren<strong>de</strong>rer für die Darstellung aller Tabellenelemente zuständig. Es muß das<br />
Interface TableCellRen<strong>de</strong>rer implementieren, das nur e<strong>in</strong>e e<strong>in</strong>zige Metho<strong>de</strong> enthält.<br />
public Component getTableCellRen<strong>de</strong>rerComponent(<br />
JTable table,Object value,<br />
boolean isSelected,<br />
boolean hasFocus,<br />
<strong>in</strong>t row,<br />
<strong>in</strong>t column)<br />
Diese Metho<strong>de</strong> arbeitet als Factory-Metho<strong>de</strong> und wird nur dann aufgerufen, wenn zur<br />
Darstellung e<strong>in</strong>er Zelle e<strong>in</strong> Ren<strong>de</strong>rer benötigt wird.<br />
Standardmäßig wird als Ren<strong>de</strong>rer e<strong>in</strong>e Instanz <strong>de</strong>r Klasse DefaultTableCellRen<strong>de</strong>rer<br />
verwen<strong>de</strong>t. Sie ist e<strong>in</strong>e Ableitung von JLabel mit <strong>de</strong>ren Hilfe Farbe, H<strong>in</strong>tergrund und<br />
das Look-and-Feel <strong>de</strong>r Tabelle an die Erfor<strong>de</strong>rnisse <strong>de</strong>r jeweiligen Zelle angepasst<br />
wer<strong>de</strong>n.<br />
Reaktion auf Ereignisse. JTable generiert e<strong>in</strong>e Vielzahl vom Ereignissen, um<br />
registrierte Listener über Än<strong>de</strong>rungen <strong>de</strong>s Tabellenzustands zu <strong>in</strong>formieren. Will e<strong>in</strong><br />
Objekt beispielsweise darüber <strong>in</strong>formiert wer<strong>de</strong>n, daß sich die Selektion geän<strong>de</strong>rt<br />
hat, muß es zwei ListSelectionListener registrieren. E<strong>in</strong>er davon wird auf <strong>de</strong>m<br />
Selektionsmo<strong>de</strong>ll registriert, das mit getSelectionMo<strong>de</strong>l() ermittelt wer<strong>de</strong>n kann.<br />
Da dieser nur Informationen über Än<strong>de</strong>rungen an <strong>de</strong>r Zeilenselektion versen<strong>de</strong>t, muß<br />
e<strong>in</strong> zweiter Listener auf <strong>de</strong>m Mo<strong>de</strong>ll für die Spaltenselektion registriert wer<strong>de</strong>n. Es<br />
kann durch Aufruf von getColumnMo<strong>de</strong>l() beschafft wer<strong>de</strong>n, und auf se<strong>in</strong><br />
Selektionsmo<strong>de</strong>ll kann ebenfalls mit getSelectionMo<strong>de</strong>l() zugegriffen wer<strong>de</strong>n.<br />
Bei je<strong>de</strong>r Än<strong>de</strong>rung <strong>de</strong>r Selektion wird nun valueChanged() aufgerufen und kann<br />
mit Hilfe <strong>de</strong>r oben erläuterten Metho<strong>de</strong>n herausf<strong>in</strong><strong>de</strong>n, welche Zeilen und Spalten<br />
selektiert s<strong>in</strong>d.<br />
Die Tabelle <strong>in</strong>formiert auch über Än<strong>de</strong>rungen ihrer Daten. Dazu muß auf <strong>de</strong>m<br />
Tabellenmo<strong>de</strong>ll (das mit getMo<strong>de</strong>l() beschafft wird) durch Aufruf von<br />
addTableMo<strong>de</strong>lListener() e<strong>in</strong> TableMo<strong>de</strong>lListener registriert wer<strong>de</strong>n. Bei<br />
je<strong>de</strong>r Än<strong>de</strong>rung <strong>de</strong>s Mo<strong>de</strong>lls wird dann <strong>de</strong>ssen Metho<strong>de</strong> tableChanged()<br />
aufgerufen.<br />
Schließlich können alle <strong>in</strong> <strong>de</strong>n Superklassen von JTable <strong>de</strong>f<strong>in</strong>ierten Listener<br />
registriert wer<strong>de</strong>n.<br />
302 Vorgang, <strong>de</strong>r dafür sorgt, dass die Zellen auf <strong>de</strong>m Bildschirm dargestellt wer<strong>de</strong>n. Die dafür verantwortlichen<br />
Komponenten wer<strong>de</strong>n als Ren<strong>de</strong>rer bezeichnet.<br />
402
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
JTable<br />
...<br />
protected TableCellEditor cellEditor<br />
protected boolean cellSelectionEnabled<br />
protected TableCloumnMo<strong>de</strong>l columnMo<strong>de</strong>l<br />
protected TableMo<strong>de</strong>l dataMo<strong>de</strong>l<br />
…<br />
protected Color selectionBackground<br />
potected Color selectionForeground<br />
protected ListSelectionMo<strong>de</strong>l selectionMo<strong>de</strong>l<br />
protected boolean showHorizontalL<strong>in</strong>es<br />
protected boolean showVerticalL<strong>in</strong>es<br />
><br />
public JTable()<br />
public JTable(<strong>in</strong>t numRows, <strong>in</strong>t numColumns)<br />
public JTable(Object[][] neuDaten,Object [] columnNames)<br />
public JTable(TableMo<strong>de</strong>l dm)<br />
public JTable(TableMo<strong>de</strong>l dm, TableColumnMo<strong>de</strong>l cm)<br />
public JTable(TableMo<strong>de</strong>l dm, TableColumnMo<strong>de</strong>l cm, ListSelectionMo<strong>de</strong>l sm)<br />
public JTable(Vector rowData, Vector columnNames)<br />
><br />
public void addColumn(TableColumn aColumn)<br />
…<br />
public void addNotify()<br />
…<br />
public void clearSelection()<br />
public void columnAd<strong>de</strong>d(TableColumnMo<strong>de</strong>lEvent e)<br />
public <strong>in</strong>t columnAtPo<strong>in</strong>t(Po<strong>in</strong>t po<strong>in</strong>t)<br />
…<br />
public void doLayout()<br />
public boolean editCellAt(<strong>in</strong>t row, <strong>in</strong>t column)<br />
…<br />
public TableCellEditor getCellEditor()<br />
public TableCellEditor getCellEditor(<strong>in</strong>t row,<strong>in</strong>t column)<br />
public Rectangle getCellRect(<strong>in</strong>t row,<strong>in</strong>t column,boolean <strong>in</strong>clu<strong>de</strong>Spac<strong>in</strong>g)<br />
public TableCellRen<strong>de</strong>rer getCellRen<strong>de</strong>rer(<strong>in</strong>t row,<strong>in</strong>t column)<br />
public TableColumn getColumnClass(<strong>in</strong>t column)<br />
public <strong>in</strong>t getColumnCount()<br />
public TableColumnMo<strong>de</strong>l getColumnMo<strong>de</strong>l()<br />
public Str<strong>in</strong>g columnName(<strong>in</strong>t column)<br />
public boolean getSelectionEnabled()<br />
public Class getColumnClass(<strong>in</strong>t column)<br />
public <strong>in</strong>t getColumnCount()<br />
public TableColumnMo<strong>de</strong>l getColumnMo<strong>de</strong>l()<br />
public Str<strong>in</strong>g getColumnName(<strong>in</strong>t column)<br />
public boolean getColumnSelectionAllowed()<br />
…<br />
403
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public TableMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
public <strong>in</strong>t getRowCount()<br />
public <strong>in</strong>t getRowHeight()<br />
public <strong>in</strong>t getRowHeight(<strong>in</strong>t row)<br />
…<br />
public ListSelectionMo<strong>de</strong>l getSelectionMo<strong>de</strong>l()<br />
public boolean getShowHorizontalL<strong>in</strong>es()<br />
public boolean getShowVerticalL<strong>in</strong>es()<br />
…<br />
public JTableHea<strong>de</strong>r getTableHea<strong>de</strong>r()<br />
…<br />
public TableUI getUI()<br />
…<br />
public Object getValueAt(<strong>in</strong>t row,<strong>in</strong>t column)<br />
…<br />
public boolean isCellEditable(<strong>in</strong>t row,<strong>in</strong>t column)<br />
…<br />
public Str<strong>in</strong>g paramStr<strong>in</strong>g()<br />
…<br />
public void selectAll()<br />
…<br />
public void setMo<strong>de</strong>l(TableMo<strong>de</strong>l dataMo<strong>de</strong>l)<br />
…<br />
public void setRowHeight(<strong>in</strong>t rowHeight)<br />
public void setRowHeight(<strong>in</strong>t row,<strong>in</strong>t rowHeight)<br />
…<br />
public void setUI(TableUI ui)<br />
…<br />
public void tableChanged(TableMoveEvent e)<br />
…<br />
public void updateUI()<br />
public void valueChanged(ListSelectionEvent e)<br />
Abb.: Die Klasse JTable<br />
404
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TableMo<strong>de</strong>l<br />
public void addTableMo<strong>de</strong>lListener(TableMo<strong>de</strong>lListener l)<br />
public Class getColumnClass(<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public <strong>in</strong>t getColumnCount()<br />
public <strong>in</strong>t getRowCount()<br />
public Object getValueAt(<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public boolean isCellEditable(<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
public void removeTableMo<strong>de</strong>lLister(TableMo<strong>de</strong>lListener l)<br />
public void setValueAt(Object aValue,<strong>in</strong>t rowIn<strong>de</strong>x,<strong>in</strong>t columnIn<strong>de</strong>x)<br />
AbstractTableMo<strong>de</strong>l<br />
{ abstract }<br />
…<br />
public <strong>in</strong>t f<strong>in</strong>dColumn(Str<strong>in</strong>g columnName)<br />
public void fireTableCellUpdated(<strong>in</strong>t row,<strong>in</strong>t column)<br />
public void fireTableChanged(TableMo<strong>de</strong>lEvent e)<br />
public void fireTableChanged()<br />
…<br />
public EventListener[] getListeners(Class listenerType)<br />
public TableMo<strong>de</strong>lListener[] getTableMo<strong>de</strong>lListener()<br />
…<br />
DefaultTableMo<strong>de</strong>ll<br />
proteced Vector columnI<strong>de</strong>ntifiers<br />
protected Vector dataVector<br />
><br />
public DefaultTableMo<strong>de</strong>l()<br />
public DefaultTableMo<strong>de</strong>l(<strong>in</strong>t rowCount,<strong>in</strong>t ColumnCount)<br />
public DefaultTableMo<strong>de</strong>l(Object[] columnNames,<strong>in</strong>t rowCount)<br />
public DefaultTableMo<strong>de</strong>l(Vector columnNames,<strong>in</strong>t rowCount)<br />
public DefaultTableMo<strong>de</strong>l(Vector data,Vector columnNames)<br />
><br />
public void addColumn(Object columnName)<br />
public void addColumn(Object columnName,Object[] columnData)<br />
public void addColumn(Object columnName,Vector columnData)<br />
public void addRow(Object[] rowData)<br />
public void addRow(Vector data)<br />
…<br />
public <strong>in</strong>t getColumnCount()<br />
public Str<strong>in</strong>g getColumnName()<br />
public Vector getDataVector()<br />
public <strong>in</strong>t getRowCount()<br />
public Object getValueAt(<strong>in</strong>t row,<strong>in</strong>t column)<br />
public void <strong>in</strong>sertRow(<strong>in</strong>t row,Object[] rowData)<br />
public void <strong>in</strong>sertRow(<strong>in</strong>t row,Vector rowData)<br />
…<br />
public void setDateVector(Object[][] dataVector,Object[] columnI<strong>de</strong>ntifiers)<br />
public setDataVector(Vector dataVector,Vector columnI<strong>de</strong>ntifiers)<br />
405
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public void setNumRows(<strong>in</strong>t rowCount)<br />
public void setRowCount(<strong>in</strong>t rowCount)<br />
public void setValueAt(Object aValue,<strong>in</strong>t row,<strong>in</strong>t column)<br />
><br />
TableCellEditor<br />
public Component getTableCellEditorComponent(JTable table,Object value,<br />
boolean isSelected,<strong>in</strong>t row,<strong>in</strong>t column)<br />
DefaultCellEditor<br />
…<br />
protected JComponent editorComponent<br />
><br />
public DefaultCellEditor(JCheckBox checkBox)<br />
public DefaultCellEditor(JComboBox checkBox)<br />
public DefaultCellEditor(JTextField textField)<br />
><br />
…<br />
public Object getCellEditorValue()<br />
…<br />
public Component getComponent()<br />
…<br />
public boolean isCellEditable(EventObject anEvent)<br />
…<br />
><br />
TableCellRen<strong>de</strong>rer<br />
public Componet getTableCellRen<strong>de</strong>rerComponent(JTable table,Object value,<br />
boolean isSelected, boolean hasFocus,<strong>in</strong>t row,<strong>in</strong>t column)<br />
DefaultTableCellRen<strong>de</strong>rer<br />
><br />
public DefaultTableCellRen<strong>de</strong>rer()<br />
><br />
public void firePropertyChange(Str<strong>in</strong>g propertyName,boolean oldValue,boolean newValue)<br />
…<br />
public void validate()<br />
406
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.5.6 Hierarchische Strukturen<br />
Die Klasse JTree dient zur Darstellung, Navigation und Berabeitung baumartiger,<br />
hierarchischer Strukturen. Die Baumdarstellung basiert auf e<strong>in</strong>em hierarchischen<br />
Datenmo<strong>de</strong>ll. Je<strong>de</strong> Mo<strong>de</strong>llklasse zur Baumdarstellung muß sich auf das Interface<br />
TreeMo<strong>de</strong>l beziehen. JTree besitzt dafür Konstruktoren bzw. die Zugriffsmetho<strong>de</strong>n<br />
getMo<strong>de</strong>l() und setMo<strong>de</strong>l(). Die e<strong>in</strong>zelnen Baumknoten müssen die Interfaces<br />
TreeNo<strong>de</strong> o<strong>de</strong>r MutableTreeNo<strong>de</strong> implementieren. Die Klasse<br />
DefaulMutableTreeNo<strong>de</strong> enthält e<strong>in</strong>e universelle Implementierung (<strong>in</strong>klusive<br />
Navigationsmetho<strong>de</strong>n) für Baumknoten<br />
Erzeugen e<strong>in</strong>es Baums. Liegt e<strong>in</strong> geeignetes Datenmo<strong>de</strong>ll vor, ist das Instanzieren<br />
e<strong>in</strong>es JTree e<strong>in</strong>fach. Die bei<strong>de</strong>n wichtigsten Konstruktoren <strong>de</strong>r Klasse JTree s<strong>in</strong>d:<br />
public JTree(TreeMo<strong>de</strong>l neuesMo<strong>de</strong>ll)<br />
// erwartet wird e<strong>in</strong> vor<strong>de</strong>f<strong>in</strong>iertes TreeMo<strong>de</strong>l zur Darstellung <strong>de</strong>r Baumelemente. E<strong>in</strong> TreeMo<strong>de</strong>l<br />
// kapselt alle relevanten Informationen über die Baumstruktur. Es liefert auf Anfrage die Wurzel<br />
// <strong>de</strong>s Baums, stellt Informationen über e<strong>in</strong>en bestimmten Knoten bereit o<strong>de</strong>r liefert <strong>de</strong>ssen<br />
// Nachfolgeknoten<br />
public JTree(TreeNo<strong>de</strong> wurzel)<br />
// Die Wurzel wird automatisch <strong>in</strong> e<strong>in</strong> geeignetes TreeMo<strong>de</strong>l e<strong>in</strong>gebettet. Der JTree erfragt die zur<br />
// Darstellung <strong>de</strong>r Navigation erfor<strong>de</strong>rlichen Daten immer beim TreeMo<strong>de</strong>l. Das über wurzel<br />
// Baumwurzel) <strong>in</strong>stanzierte DefaultTreeMo<strong>de</strong>l kann diese Informationen aus <strong>de</strong>n Knoten und <strong>de</strong>n<br />
// dar<strong>in</strong> gespeicherten Verweisen auf ihre Nachfolgeknoten entnehmen.<br />
Zugriffsmetho<strong>de</strong>n auf das Datenmo<strong>de</strong>ll.<br />
public TreeMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
public void setMo<strong>de</strong>l(TreeMo<strong>de</strong>l neuesMo<strong>de</strong>ll)<br />
Anzeige bzw. Unterdrücken <strong>de</strong>r Wurzel bei <strong>de</strong>r Baumdarstellung. E<strong>in</strong>e wichtige<br />
Konfigurationsoption regelt, ob die Wurzel <strong>de</strong>s Baums bei se<strong>in</strong>er Darstellung<br />
angezeigt o<strong>de</strong>r unterdrückt wer<strong>de</strong>n soll. Auf sie kann mit <strong>de</strong>n Metho<strong>de</strong>n<br />
public void setRootVisible(boolean rootVisible)<br />
public boolean isRootVisible()<br />
zugegriffen wer<strong>de</strong>n.<br />
Zur Beschriftung e<strong>in</strong>es Knotens bei <strong>de</strong>r visuellen Darstellung verwen<strong>de</strong>t e<strong>in</strong> JTree<br />
die Metho<strong>de</strong> toStr<strong>in</strong>g().<br />
Abfragen zur Selektion von Baumknoten. JTree stellt e<strong>in</strong>e Reihe von Metho<strong>de</strong>n für<br />
Abfragen bereit, ob und welche Knoten selektiert s<strong>in</strong>d, z.B.:<br />
public TreePath getSelectionPath()<br />
// ermittelt das selektierte Element. Bei aktivierter Mehrfachselektion liefert die Metho<strong>de</strong> das erste aller<br />
// selektierten Elemente. Falls ke<strong>in</strong> Knoten selektiert ist, wird null zurückgeliefert.<br />
public TreePath[] getSelectionPaths()<br />
// zurückgegeben wird e<strong>in</strong> Array mit allen selektierten Knoten<br />
public TreePath getLeadSelectionPath()<br />
// liefert das markierte Element<br />
Die angegebenen Metho<strong>de</strong>n liefern Objekte <strong>de</strong>r Klasse TreePath. Diese Klasse<br />
beschreibt e<strong>in</strong>en Knoten im Baum über <strong>de</strong>n Pfad, <strong>de</strong>r von <strong>de</strong>r Wurzel aus beschritten<br />
wer<strong>de</strong>n muß, um zu <strong>de</strong>n Knoten zu gelangen. Mit<br />
public Object getLastSelectedPathComponent()<br />
407
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
<strong>de</strong>r Klasse TreePath kann das letzte Element dieses Pfads bestimmt wer<strong>de</strong>n. Mit<br />
public Object[] getPath()<br />
<strong>de</strong>r Klasse TreePath kann <strong>de</strong>r vollständige Pfad ermittelt wer<strong>de</strong>n. An erster Stelle<br />
liegt die Wurzel <strong>de</strong>s Baums, an letzter Stelle das selektierte Element. Solle ermittelt<br />
wer<strong>de</strong>n, ob und welche Elemente im Baum selektiert s<strong>in</strong>d, können die Metho<strong>de</strong>n<br />
public boolean isSelectionEmpty()<br />
public boolean isPathSelected(TreePath pfad)<br />
aufgerufen wer<strong>de</strong>n.<br />
Verän<strong>de</strong>rn <strong>de</strong>r Selektion. Die Selektion kann programmgesteuert verän<strong>de</strong>rt wer<strong>de</strong>n:<br />
public void clearSelection()<br />
// Löschen <strong>de</strong>r Selektion<br />
public void addSelectionPath(TreePath path)<br />
// Erweitern <strong>de</strong>r Selektion um e<strong>in</strong> e<strong>in</strong>zelnes Element<br />
public void addSelectionPaths(TreePath [] pfa<strong>de</strong>)<br />
// Erweitern <strong>de</strong>r Selektion um e<strong>in</strong>e Menge Knoten<br />
public void setSelectionPath(TreePath path)<br />
// Selektion <strong>de</strong>r als Argument übergebenen Knoten)<br />
public void setSelectionPaths(TreePath[] paths)<br />
// Selektion <strong>de</strong>r als Argument übergebenen Knoten<br />
Zur unmittelbaren Reaktion auf Än<strong>de</strong>rungen <strong>de</strong>r Selektion durch <strong>de</strong>n Anwen<strong>de</strong>r kann<br />
e<strong>in</strong> TreeSelectionListener <strong>in</strong>stanziert wer<strong>de</strong>n (Registrierung mit<br />
addTreeSelectionListener() beim JTree). Bei je<strong>de</strong>r Selektionsän<strong>de</strong>rung wird<br />
public void valueChanged(TreeSelectionEvent event)<br />
aufgerufen. "event" stellt<br />
public TreePath getOldLeadSelectionPath()<br />
public TreePath getNewLeadSelectionPath()<br />
zur Verfügung, um auf <strong>de</strong>n vorherigen und aktuellen Selektionspfad zuzugreifen.<br />
Öffnen und Schließen <strong>de</strong>r Knoten. Der Anwen<strong>de</strong>r kann die Knoten mit Maus- o<strong>de</strong>r<br />
Tastaturkommandos öffnen o<strong>de</strong>r schließen. Dadurch wer<strong>de</strong>n Nachfolgeknoten<br />
sichtbar o<strong>de</strong>r versteckt.<br />
public boolean isExpan<strong>de</strong>d(TreePath pfad)<br />
// liefert true, wenn <strong>de</strong>r Knoten geöffnet ist<br />
public boolean isCollapsed()<br />
// liefert true, wenn <strong>de</strong>r Knoten geschlossen ist<br />
public boolean hasBeenExpan<strong>de</strong>d(TreePath path)<br />
// gibt an, ob <strong>de</strong>r Knoten überhaupt schon e<strong>in</strong>mal geöffnet wur<strong>de</strong><br />
public boolean isVisible(TreePath pfad)<br />
// liefert true, wenn <strong>de</strong>r Knoten sichtbar ist, d.h. all se<strong>in</strong>e Elternknoten geöffnet s<strong>in</strong>d<br />
public void makeVisible(TreePath pfad)<br />
// Sichtbar Machen e<strong>in</strong>es Knoten<br />
public void expandPath(TreePath pfad)<br />
// Öffnen e<strong>in</strong>es Knoten<br />
public void collapsePath(TreePath pfad)<br />
// Schließen e<strong>in</strong>es Knoten<br />
Verän<strong>de</strong>rn <strong>de</strong>r Baumstruktur. Es können neue Knoten e<strong>in</strong>gefügt, bestehen<strong>de</strong> entfernt<br />
o<strong>de</strong>r vorhan<strong>de</strong>ne modifiziert wer<strong>de</strong>n.<br />
408
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Interfaces zur Mo<strong>de</strong>llierung und Sicht auf e<strong>in</strong>en Baum: Drei Interfaces erlauben<br />
Mo<strong>de</strong>llierung und Sicht auf e<strong>in</strong>en Baum: TreeMo<strong>de</strong>l, TreeSelectionMo<strong>de</strong>l,<br />
TreeCellRen<strong>de</strong>rer.<br />
E<strong>in</strong> viertes Interface TreeNo<strong>de</strong> beschreibt, was <strong>in</strong> je<strong>de</strong>m Knoten <strong>de</strong>s Baums<br />
dargestellt wird.<br />
TreeMo<strong>de</strong>l<br />
Dieses Interface beschreibt das e<strong>in</strong>em JTree zugeordnete Datenmo<strong>de</strong>ll. Das<br />
TreeMo<strong>de</strong>l-Interface spezifiziert, wie e<strong>in</strong> Baum (über e<strong>in</strong>e Datenstruktur) abgebil<strong>de</strong>t<br />
wird.<br />
public Object getChild(Object parent, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public <strong>in</strong>t getChildCount(Object parent)<br />
public <strong>in</strong>t getIn<strong>de</strong>xOfChild(Object parent,Object child)<br />
public Object getRoot()<br />
public Object isLeaf(Object no<strong>de</strong>)<br />
Drei weitere Metho<strong>de</strong>n<br />
public void addTreeMo<strong>de</strong>lListener(TreeMo<strong>de</strong>lListener l)<br />
public void removeTreeMo<strong>de</strong>lListener(TreeMol<strong>de</strong>lListener l)<br />
public void valueForPathChanged(TreePath pfad, Object neuerWert)<br />
behan<strong>de</strong>ln H<strong>in</strong>zufügen, Entfernen und die Kentnisnahme von Event-Listeners. Diese<br />
Listeners bemerken Än<strong>de</strong>rungen im TreeMo<strong>de</strong>l nach Empfang von TreeMo<strong>de</strong>lEvent-<br />
Nachrichten.<br />
E<strong>in</strong> Objekt, das diese Metho<strong>de</strong>n <strong>de</strong>f<strong>in</strong>iert, kann Mo<strong>de</strong>ll für e<strong>in</strong>en JTree se<strong>in</strong>. Die<br />
DefaultTreeMo<strong>de</strong>l-Klasse ist e<strong>in</strong>e e<strong>in</strong>fache Implementierung <strong>de</strong>s TreeMo<strong>de</strong>l,<br />
das explizit TreeNo<strong>de</strong>- und MutableTreeNo<strong>de</strong>-Objekte benutzt.<br />
TreeNo<strong>de</strong><br />
JTree-Objekte wer<strong>de</strong>n aus TreeNo<strong>de</strong>-Objekten gebil<strong>de</strong>t (e<strong>in</strong>fache Repräsentationen<br />
e<strong>in</strong>es Baumknoten). Die wichtigsten Metho<strong>de</strong>n von TreeNo<strong>de</strong> s<strong>in</strong>d:<br />
public <strong>in</strong>t getChildCount()<br />
// ermittelt die Anzahl <strong>de</strong>r Nachfolgeknoten. Sie wer<strong>de</strong>n von 0 an durchnummeriert.<br />
public TreeNo<strong>de</strong> getChildAt(<strong>in</strong>t childIn<strong>de</strong>x)<br />
// liefert e<strong>in</strong>en beliebigen Nachfolgeknoten<br />
public TreeNo<strong>de</strong> getParent()<br />
// E<strong>in</strong> Knoten kennt se<strong>in</strong>en Vaterknoten, <strong>de</strong>r mit getParent() ermittelt wer<strong>de</strong>n kann<br />
public boolean isLeaf()<br />
// Abfrage, ob e<strong>in</strong> Knoten e<strong>in</strong> Blatt ist o<strong>de</strong>r weitere Nachfolgeknoten enthält<br />
Die Klasse DefaultMutableTreeNo<strong>de</strong> <strong>de</strong>f<strong>in</strong>iert Metho<strong>de</strong>n zum Anschauen und<br />
Manipulieren von Baumknoten. Diese Klasse implementiert das Interface<br />
MutableTreeNo<strong>de</strong> (Extension <strong>de</strong>s Interface TreeNo<strong>de</strong>).<br />
Anwendungsbezogene Informationen wer<strong>de</strong>n bereits <strong>de</strong>m Konstruktor übergeben:<br />
public DefaultMutableTreeNo<strong>de</strong>(Object benutzerObjekt)<br />
409
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
DefaultMutableTreeNo<strong>de</strong> hat Metho<strong>de</strong>n zum E<strong>in</strong>fügen und Löschen von Knoten<br />
implementiert:<br />
public void add(MutableTreeNo<strong>de</strong> neuesK<strong>in</strong>d)<br />
// e<strong>in</strong> K<strong>in</strong>dknoten wird an das En<strong>de</strong> <strong>de</strong>r Liste <strong>de</strong>r Nachfolgeknoten angefügt<br />
public void <strong>in</strong>sert(MutableTreeNo<strong>de</strong> neuesK<strong>in</strong>d, <strong>in</strong>t K<strong>in</strong>dIn<strong>de</strong>x)<br />
// E<strong>in</strong>fügen e<strong>in</strong>es neuen K<strong>in</strong>dknoten an beliebiger Stelle<br />
public void remove(<strong>in</strong>t k<strong>in</strong>dIn<strong>de</strong>x)<br />
// Entfernen e<strong>in</strong>es beliebigen Knoten<br />
public void removeAllChildren()<br />
// Entfernen aller K<strong>in</strong>dknoten<br />
/* Zugriff auf Infornationen, die <strong>in</strong> e<strong>in</strong>em benutzerObjekt gehalten wer<strong>de</strong>n */<br />
public void setUserObject(Object benutzerObjekt)<br />
public Object getUserObject()<br />
// benutzerObjekt ist auch <strong>de</strong>r Lieferant von Knotenbeschriftungen. Je<strong>de</strong>r Aufruf von toStr<strong>in</strong>g()<br />
// wird an benutzerObjekt weitergeleitet<br />
TreeSelectionMo<strong>de</strong>l<br />
Diese Interface spezifiziert, wie e<strong>in</strong> Benutzer e<strong>in</strong>en Pfad bestimmter Objekte<br />
auswählen kann. JTree benutzt dieses Mo<strong>de</strong>ll zur Auswahl von Regeln.<br />
DefaultTreeSelectionMo<strong>de</strong>l ist e<strong>in</strong>e Implementierung von<br />
TreeSelectionMo<strong>de</strong>l.<br />
TreeSelectionMo<strong>de</strong>l steuert das Selektieren von Knoten. Die Zugriffsmetho<strong>de</strong>n<br />
auf TreeSelectionMo<strong>de</strong>l s<strong>in</strong>d:<br />
public void setSelectionMo<strong>de</strong>l(TreeSelectionMo<strong>de</strong>l selectionMo<strong>de</strong>l)<br />
public TreeSelectionMo<strong>de</strong>l getSelectionMo<strong>de</strong>l()<br />
Standardmäßig erlaubt e<strong>in</strong> JTree das Selektieren mehrerer Knoten. Soll die<br />
Selektionsmöglichkeit auf e<strong>in</strong>en Knoten beschränk wer<strong>de</strong>n, muß e<strong>in</strong> eigenes<br />
TreeSelectionMo<strong>de</strong>l an setSelectionMo<strong>de</strong>l() übergeben wer<strong>de</strong>n. Dazu<br />
kann e<strong>in</strong>e Instanz <strong>de</strong>r Klasse DefaultTreeSelectionMo<strong>de</strong>l erzeugt wer<strong>de</strong>n und<br />
durch Aufruf von<br />
public void setSelectionMo<strong>de</strong>(<strong>in</strong>t mo<strong>de</strong>)<br />
und Übergabe e<strong>in</strong>er <strong>de</strong>r Konstanten<br />
SINGLE_TREE_SELECTION<br />
CONTIGUOUS_TREE_SELECTION<br />
DISCONTIGUOUS_TREE_SELECTION<br />
konfiguriert wer<strong>de</strong>n.<br />
TreeCellRen<strong>de</strong>rer<br />
Dieses Interface wird zur visuellen Repräsentation von Baumknoten benutzt. Es<br />
umfasst nur e<strong>in</strong>e Metho<strong>de</strong>.<br />
Anwendungen<br />
410
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
1. E<strong>in</strong> Baum, <strong>de</strong>r aus DefaultMutableTreeNo<strong>de</strong>s aufgebaut ist 303 .<br />
import java.awt.*;<br />
import javax.sw<strong>in</strong>g.*;<br />
import javax.sw<strong>in</strong>g.tree.*;<br />
public class SimpleTree extends JFrame<br />
{<br />
public SimpleTree()<br />
{<br />
super("Creat<strong>in</strong>g a Simple JTree");<br />
// W<strong>in</strong>dowUtilities.setNativeLookAndFeel();<br />
/* try {<br />
UIManager.setLookAndFeel(<br />
UIManager.getSystemLookAndFeelClassName());<br />
}<br />
catch(Exception e)<br />
{<br />
System.out.pr<strong>in</strong>tln("Error sett<strong>in</strong>g native L&F: " + e);<br />
} */<br />
// addW<strong>in</strong>dowListener(new ExitListener());<br />
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
Conta<strong>in</strong>er content = getContentPane();<br />
Object[] hierarchy =<br />
{ "javax.sw<strong>in</strong>g",<br />
"javax.sw<strong>in</strong>g.bor<strong>de</strong>r",<br />
"javax.sw<strong>in</strong>g.colorchooser",<br />
"javax.sw<strong>in</strong>g.event",<br />
"javax.sw<strong>in</strong>g.filechooser",<br />
new Object[] { "javax.sw<strong>in</strong>g.plaf",<br />
"javax.sw<strong>in</strong>g.plaf.basic",<br />
"javax.sw<strong>in</strong>g.plaf.metal",<br />
"javax.sw<strong>in</strong>g.plaf.multi" },<br />
"javax.sw<strong>in</strong>g.table",<br />
new Object[] { "javax.sw<strong>in</strong>g.text",<br />
new Object[] { "javax.sw<strong>in</strong>g.text.html",<br />
"javax.sw<strong>in</strong>g.text.html.parser" },<br />
"javax.sw<strong>in</strong>g.text.rtf" },<br />
"javax.sw<strong>in</strong>g.tree",<br />
"javax.sw<strong>in</strong>g.undo" };<br />
DefaultMutableTreeNo<strong>de</strong> root = processHierarchy(hierarchy);<br />
JTree tree = new JTree(root);<br />
content.add(new JScrollPane(tree), Bor<strong>de</strong>rLayout.CENTER);<br />
setSize(275, 300);<br />
setVisible(true);<br />
}<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
new SimpleTree();<br />
}<br />
/** Small rout<strong>in</strong>e that will make no<strong>de</strong> out of the first entry<br />
* <strong>in</strong> the array, then make no<strong>de</strong>s out of subsequent entries<br />
* and make them child no<strong>de</strong>s of the first one. The process is<br />
* repeated recursively for entries that are arrays.<br />
*/<br />
private DefaultMutableTreeNo<strong>de</strong><br />
processHierarchy(Object[] hierarchy)<br />
{<br />
DefaultMutableTreeNo<strong>de</strong> no<strong>de</strong> =<br />
new DefaultMutableTreeNo<strong>de</strong>(hierarchy[0]);<br />
DefaultMutableTreeNo<strong>de</strong> child;<br />
for(<strong>in</strong>t i=1; i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Object no<strong>de</strong>Specifier = hierarchy[i];<br />
if (no<strong>de</strong>Specifier <strong>in</strong>stanceof Object[])<br />
// Knoten mit Nachfolgeknoten<br />
child = processHierarchy((Object[])no<strong>de</strong>Specifier);<br />
else<br />
child = new DefaultMutableTreeNo<strong>de</strong>(no<strong>de</strong>Specifier);<br />
// Blatt<br />
no<strong>de</strong>.add(child);<br />
}<br />
return(no<strong>de</strong>);<br />
}<br />
}<br />
Sw<strong>in</strong>g besitzt e<strong>in</strong>en Manager für Benutzerschnittstellen, <strong>de</strong>r das "Look and Feel"<br />
(<strong>Java</strong> L&F) von Komponenten kontrolliert. Das Management <strong>de</strong>s Look and Feel wird<br />
von <strong>de</strong>r Klasse UIManager übernommen. Folgen<strong>de</strong> Auswahlmöglichkeiten stehen <strong>in</strong><br />
Abhängigkeit von <strong>de</strong>r <strong>Java</strong>-Entwicklungsumgebung zur Verfügung:<br />
- das W<strong>in</strong>dows-95- und W<strong>in</strong>dows-NT-Look-and-Feel<br />
- das Motif-x-W<strong>in</strong>dows-System-Look-and-Feel<br />
- Metal<br />
Die Auswahl <strong>de</strong>s Look-and-Feel erfolgt mit <strong>de</strong>r Metho<strong>de</strong><br />
getSystemLookAndFeelClassName() als Argument für die Metho<strong>de</strong><br />
setLookandFeel. Es wer<strong>de</strong>n unterschiedliche Ergebnisse auf unterschiedlichen<br />
Betriebssystemen erzeugt.<br />
412
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
413
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
JComponent<br />
JTree<br />
...<br />
protected TreeCellEditor cellEditor<br />
protected TreeCellRendrer cellRen<strong>de</strong>rer<br />
…<br />
protected boolean rootVisible<br />
protected TreeSelectionMo<strong>de</strong>l selectionMo<strong>de</strong>l<br />
…<br />
protected TreeMo<strong>de</strong>l treeMo<strong>de</strong>l<br />
protected TreeMo<strong>de</strong>llListener treeMo<strong>de</strong>lListener<br />
…<br />
><br />
JTree()<br />
JTree(Hashtable wert)<br />
JTree(TreeMo<strong>de</strong>l neuesMo<strong>de</strong>l)<br />
JTree(TreeNo<strong>de</strong> root)<br />
JTree(Vector wert)<br />
JTree(Object[] wert)<br />
…<br />
><br />
…<br />
public void addSelectionPath(TreePath pfad)<br />
public void addSelectionPaths(TreePath[] pfa<strong>de</strong>)<br />
public TreePath getSelectionPath()<br />
// ermittelt das ausgewählte Element<br />
public TreePath[] getSelectionPaths()<br />
public void setSelectionPath(TreePath pfad)<br />
public void setSelectionPaths(TreePath[] pfa<strong>de</strong>)<br />
public TreePath getLeadSelectionPath()<br />
// liefert das markierte Element<br />
…<br />
public void setRootVisible(boolean rootVisible)<br />
public boolean isRootVisible()<br />
public TreeMo<strong>de</strong>l getMo<strong>de</strong>l()<br />
public void setMo<strong>de</strong>l(TreeMo<strong>de</strong>l neuesMo<strong>de</strong>l)<br />
public TreeCellRen<strong>de</strong>rer getCellRen<strong>de</strong>rer ()<br />
public void setCellRen<strong>de</strong>rer(TreeCellren<strong>de</strong>rer x)<br />
…<br />
public void setUI(TreeUI ui)<br />
public void updateUI()<br />
…<br />
public void setSelectionMo<strong>de</strong>l(TreeSelectionMo<strong>de</strong>l selectionMo<strong>de</strong>l)<br />
…<br />
Abb.: Die Klasse JTree<br />
414
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TreeMo<strong>de</strong>l<br />
public Object getRoot()<br />
public Object getChild(Object parent, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public boolean isLeaf(Object knoten)<br />
public void valueForPathChanged(TreePath pfad,Object neuerWert)<br />
public <strong>in</strong>t getIn<strong>de</strong>xOfChild(Object parent, Object child)<br />
public void addTreeMo<strong>de</strong>lListener(TreeMo<strong>de</strong>lListener l)<br />
public void removeTreeListener(TreeMo<strong>de</strong>lListener l)<br />
DefaultTreeMo<strong>de</strong>ll<br />
…<br />
proteced TreeNo<strong>de</strong> root<br />
protected EventListenerList listenerList<br />
><br />
public DefaultTreeMo<strong>de</strong>l()<br />
public DefaultTreeMo<strong>de</strong>l(TreeNo<strong>de</strong> root,boolean asksAllowsChildren)<br />
><br />
public void addTreeMo<strong>de</strong>lListener l)<br />
public void removeTreeMo<strong>de</strong>lListener(TreeMo<strong>de</strong>lListener l)<br />
…<br />
public Object getChild(Object parent, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public <strong>in</strong>t getChildCount(Object parent)<br />
public <strong>in</strong>t getIn<strong>de</strong>xOfChild(Object parent,Object child)<br />
…<br />
public TreeNo<strong>de</strong>[] getPathToRoot(TreeNo<strong>de</strong> e<strong>in</strong>Knoten)<br />
…<br />
public Object getRoot()<br />
….<br />
public void <strong>in</strong>sertInfo(MutableTreeNo<strong>de</strong> neuesK<strong>in</strong>d, MutableTreeNo<strong>de</strong><br />
parent,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public boolean isLeaf(Object knoten)<br />
public void no<strong>de</strong>Changed(TreeNo<strong>de</strong> knoten)<br />
…<br />
public void removeNo<strong>de</strong>FromParent(MutableTreeNo<strong>de</strong> knoten)<br />
…<br />
public void setRoot(TreeNo<strong>de</strong> root)<br />
public void valueForPathChanged(TreePath path,Object neuerWert)<br />
415
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TreeSelectionMo<strong>de</strong>l<br />
static <strong>in</strong>t CONTIGUOUS_TREE_SELECTION<br />
static <strong>in</strong>t DISCONTIGUOUS_TREE_SELECTION<br />
static <strong>in</strong>t SINGLE_TREE_SELECTION<br />
public void setSelectionMo<strong>de</strong>(<strong>in</strong>t no<strong>de</strong>)<br />
public <strong>in</strong>t setSelectionPath(TreePath path)<br />
public void setSelectionPaths(TreePath [] paths)<br />
public void addSelectionPath(TreePath path)<br />
public void addSelectionPaths(TreePath [] paths)<br />
public void removeSelectionPath(TreePath path)<br />
public void removeSelectionPaths(TreePaths [] paths)<br />
public TreePath getSelectionPath()<br />
public TreePath[] getSelectionPaths()<br />
public <strong>in</strong>t getSelectionCount()<br />
public boolean isPathSelected(TreePath path)<br />
public boolean isSelectionEmpty()<br />
public void clearSelection()<br />
public <strong>in</strong>t [] getSelectionRows()<br />
public boolean isRowSelected(<strong>in</strong>t row)<br />
public void resetRowSelection()<br />
public <strong>in</strong>t getLeadSelecttionRow()<br />
public TreePath getSelectionPath()<br />
public void addPropertyChangeListener(PropertyChangeListener listener)<br />
DefaultTreeSelectionMo<strong>de</strong>l<br />
...<br />
protected <strong>in</strong>t leadIn<strong>de</strong>x<br />
...<br />
protected TreePath [] selection<br />
…<br />
static Str<strong>in</strong>g SELECTION_MODE_PROPERTY<br />
protected <strong>in</strong>t selectionMo<strong>de</strong><br />
…<br />
><br />
public DefaultTreeSelectionMo<strong>de</strong>l()<br />
><br />
public void addSelectionPath(TreePath path)<br />
public void addSelectionPaths(TreePath [] paths)<br />
public void removeSelectionPath(TreePath path)<br />
…<br />
public void addTreeSelectionListener(TreeSelectionListener x)<br />
public void removeTreeSelectionListener(TreeSelectionListener x)<br />
…<br />
public void updateLeadIn<strong>de</strong>x()<br />
public void <strong>in</strong>sureUniqueness<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
public Object clone() throws CloneNotSupportedException<br />
416
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TreeNo<strong>de</strong><br />
public Enumertion children()<br />
public boolean getAllowsChildren()<br />
public TreeNo<strong>de</strong> getChildAt(<strong>in</strong>t childIn<strong>de</strong>x)<br />
public <strong>in</strong>t getChildCount()<br />
public <strong>in</strong>t getIn<strong>de</strong>x(TreeNo<strong>de</strong> no<strong>de</strong>)<br />
public TreeNo<strong>de</strong> getParent()<br />
public boolean isLeaf()<br />
><br />
MutableTreeNo<strong>de</strong><br />
public void <strong>in</strong>sert(MutableTreeNo<strong>de</strong> child,<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public void remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public void remove(MutableTreeNo<strong>de</strong> no<strong>de</strong>)<br />
public void removeFromParent()<br />
public void setParent(MutableTreeNo<strong>de</strong> newParent)<br />
public void setUserObject(Object objekt)<br />
DefaultMutableTreeNo<strong>de</strong><br />
….<br />
protected MutableTreeNo<strong>de</strong> parent<br />
><br />
DefaultMutableTreeNo<strong>de</strong>()<br />
DefaultMutableTreeNo<strong>de</strong>(Object objekt)<br />
DefaultMutableTreeNo<strong>de</strong>(Object benutzerObjekt)<br />
><br />
public void add(MutableTreeNo<strong>de</strong> neuesK<strong>in</strong>d)<br />
public Enumeartion breadFirstEnumeration()<br />
…<br />
public Enumeration <strong>de</strong>pthFirstEnumeration()<br />
…<br />
public TreeNo<strong>de</strong> getChildAfter(TreeNo<strong>de</strong> e<strong>in</strong>K<strong>in</strong>d)<br />
…<br />
public TreeNo<strong>de</strong> getChildBefore(TreeNo<strong>de</strong> e<strong>in</strong>K<strong>in</strong>d)<br />
…<br />
public <strong>in</strong>t getDepth()<br />
…<br />
public <strong>in</strong>t getLevel()<br />
…<br />
public TreeNo<strong>de</strong> getPath()<br />
protected TreeNo<strong>de</strong>[] getPathToRoot(TreeNo<strong>de</strong> e<strong>in</strong>Knoten, <strong>in</strong>t tiefe)<br />
…<br />
public TreeNo<strong>de</strong> getRoot()<br />
…<br />
public boolean isRoot()<br />
…<br />
public void removeAllChildren()<br />
…<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
417
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TreeCellEditor<br />
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected,<br />
Boolean expan<strong>de</strong>d, boolean leaf, <strong>in</strong>t row)<br />
DefaultTreeCellEditor<br />
protected Color bor<strong>de</strong>rSelectionColor<br />
protected booleab canEdit<br />
protected Component edit<strong>in</strong>gComponent<br />
protected Conta<strong>in</strong>er edit<strong>in</strong>gConta<strong>in</strong>er<br />
protected Icob edit<strong>in</strong>gIcon<br />
protected Font font<br />
protected TreePath lstPath<br />
…<br />
protected Timer timer<br />
protected JTree tree<br />
><br />
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRen<strong>de</strong>rer ren<strong>de</strong>rer)<br />
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRen<strong>de</strong>rer ren<strong>de</strong>rer,TreeCellEditor editor)<br />
><br />
public void setBor<strong>de</strong>rSelectionColor(Color newColor)<br />
public Color getBor<strong>de</strong>rSelectionColor()<br />
public void setFont(Font font)<br />
public Font getFont()<br />
…<br />
418
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
TreeCellRen<strong>de</strong>rer<br />
public Component getTreeCellRen<strong>de</strong>rerComponent( JTree tree, Object value, boolean selected,<br />
boolean expan<strong>de</strong>d, bollean leaf, <strong>in</strong>t row,<br />
boolean lostFocus)<br />
DefaultTreeCellRen<strong>de</strong>rer<br />
protected Color backGroundSelectionColor<br />
protected Color bor<strong>de</strong>rSelectionColor<br />
protected Icon closedIcon<br />
protected boolean hasFocus<br />
protected Icon leafIcon<br />
protected Icon openIcon<br />
protected boolean selected<br />
protected Color textNonSelectionColor<br />
protected Color textSelectionColor<br />
><br />
public TreeCellRen<strong>de</strong>rer()<br />
><br />
public void setFont(Font font)<br />
public void setLeafIcon(Icon newIcon)<br />
public void setOpenIcon(Icon newIcon)<br />
public void setTextNonSelectionColor(Color newColor)<br />
public void setTextSelectionColor(Color newColor)<br />
public void validate()<br />
419
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5.6.6 Ereignisbehandlung unter Sw<strong>in</strong>g<br />
420
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6. Utilities<br />
6.1 Kollektionen (Collections)<br />
Kollektionen (Collections) s<strong>in</strong>d Datenstrukturen zur Aufnahme und Verarbeitung von<br />
Datenmengen. Typische Collections s<strong>in</strong>d Stacks, Queues, Priority Queues, Listen<br />
o<strong>de</strong>r Trees (Bäume).<br />
In <strong>Java</strong> existieren seit <strong>de</strong>r Version 1.0 die Collections Vector, Stack, Hashtable<br />
und Bitset. Die Kritik an diesem Collection-Konzept führte zu e<strong>in</strong>er Sammlung von<br />
20 Klassen und Interfaces im Paket java.util <strong>de</strong>s JDK 1.2. Im Wesentlichen s<strong>in</strong>d<br />
dies: 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<br />
sequentiell zugegriffen wer<strong>de</strong>n kann<br />
- E<strong>in</strong> Set ist e<strong>in</strong>e Menge von Elementen (ohne Duplikate), auf die mit typischen Mengenoperationen<br />
zugegriffen wer<strong>de</strong>n 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 an<strong>de</strong>ren Typs (Menge<br />
zusammengehöriger Paare).<br />
Je<strong>de</strong> dieser Grundformen ist als Interface und <strong>de</strong>n angegebenen Namen<br />
implementiert. Zu<strong>de</strong>m gibt es jeweils e<strong>in</strong>e o<strong>de</strong>r 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 Durchwan<strong>de</strong>rn von Datenstrukturen mit Iteratoren<br />
Bei Datenstrukturen gibt es e<strong>in</strong>e Möglichkeit, gespeicherte Daten unabhängig von<br />
<strong>de</strong>r Implementierung immer mit <strong>de</strong>r gleichen Technik abzufragen. Bei<br />
Datenstrukturen han<strong>de</strong>lt es sich meistens um Daten <strong>in</strong> Listen, Bäumen o<strong>de</strong>r<br />
ähnlichem und oft wird nur die Frage nach <strong>de</strong>r Zugehörigkeit e<strong>in</strong>es Worts zum<br />
Datenbestand gestellt (z.B. „Gehört das Wort dazu?“). Auch die Möglichkeit Daten <strong>in</strong><br />
irgen<strong>de</strong><strong>in</strong>er Form aufzuzählen, ist e<strong>in</strong>e häufig gestellte Aufgabe. Hierfür bieten sich<br />
Iteratoren an. In <strong>Java</strong> umfaßt das Interface Enumeration die bei<strong>de</strong>n Funktionen<br />
hasMoreElements() und nextElement(), mit <strong>de</strong>nen durch e<strong>in</strong>e Datenstruktur<br />
iteriert wer<strong>de</strong>n kann.<br />
public <strong>in</strong>terface Enumeration<br />
{<br />
public boolean hasMoreElements();<br />
// Test, ob noch e<strong>in</strong> weiteres Element aufgezählt wer<strong>de</strong>n kann<br />
public Object nextElement() throws NoSuchElementException;<br />
/* setzt <strong>de</strong>n <strong>in</strong>ternen Zeiger auf das nächste Element, d. h. liefert das<br />
das nächste Element <strong>de</strong>r Enumertion zurück. Diese Funktion kann e<strong>in</strong>e<br />
NoSuchException auslösen, wenn nextElement() aufgerufen wird, obwohl<br />
hasMoreElements() unwahr ist<br />
*/<br />
}<br />
421
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Aufzählung erfolgt meistens über<br />
for (Enumeration e = ds.elements(); e.hasMoreElements(); )<br />
System.out.pr<strong>in</strong>tln(e.nextElements());<br />
Die Datenstruktur ds besitzt e<strong>in</strong>e Metho<strong>de</strong> elements(), die e<strong>in</strong> Enumeration-Objekt<br />
zurückgibt, das die Aufzählung erlaubt.<br />
6.1.2 Die Klasse Vector<br />
class java.util.Vector extends AbstractList<br />
implements List, Cloneable, Collection, Serializable<br />
Die Klasse Vector beschreibt e<strong>in</strong> Array mit variabler Länge. Objekte <strong>de</strong>r Klasse<br />
Vector s<strong>in</strong>d Repräsentationen e<strong>in</strong>er l<strong>in</strong>earen Liste. Die Liste kann Elemente<br />
beliebigen Typs enthalten, ihre Länge ist zur Laufzeit verän<strong>de</strong>rbar (Array mit variabler<br />
Länge). 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 <strong>de</strong>s Typs Object. Der Zugriff auf Elemente erfolgt über<br />
Indizes. Es wird dazu aber ke<strong>in</strong> Operator [], son<strong>de</strong>rn es wer<strong>de</strong>n Metho<strong>de</strong>n benutzt,<br />
die e<strong>in</strong>en In<strong>de</strong>x als Parameter annehmen.<br />
Anlegen e<strong>in</strong>es neuen Vektors (Konstruktor): public Vector()<br />
public Vector(<strong>in</strong>t <strong>in</strong>itialCapacity, <strong>in</strong>t capacityIncrement)<br />
// E<strong>in</strong> Vector vergrößert sich automatisch, falls mehr Elemente aufgenommen wer<strong>de</strong>n, als<br />
// ursprünglich vorgesehen (Resiz<strong>in</strong>g). Dabei sollen <strong>in</strong>itialCapacity und capacityIncrement<br />
// passend gewählt wer<strong>de</strong>n.<br />
E<strong>in</strong>fügen von Elementen: public void addElement(Object obj)<br />
// Anhängen an <strong>de</strong>s En<strong>de</strong> <strong>de</strong>r bisher vorliegen<strong>de</strong>n Liste von Elementen<br />
Eigenschaften: public boolean isEmpty()<br />
// Prüfen, ob <strong>de</strong>r Vektor leer ist<br />
public <strong>in</strong>t size()<br />
// bestimmt die Anzahl <strong>de</strong>r Elemente<br />
public <strong>in</strong>t capacity()<br />
// bestimmt die <strong>in</strong>terne Größe <strong>de</strong>s Arrays. Sie kann mit ensureCapacity() geän<strong>de</strong>rt<br />
// wer<strong>de</strong>n<br />
E<strong>in</strong>fügen an beliebiger Stelle <strong>in</strong>nerhalb <strong>de</strong>r Liste:<br />
public void <strong>in</strong>sertElementAt(Object obj, <strong>in</strong>t <strong>in</strong><strong>de</strong>x) throws<br />
ArrayIn<strong>de</strong>xOutOfBoundsException<br />
// fügt obj an die Position <strong>in</strong><strong>de</strong>x <strong>in</strong> <strong>de</strong>n "Vector" e<strong>in</strong>.<br />
Zugriff auf Elemente: Für <strong>de</strong>n sequentiellen Zugriff steht e<strong>in</strong> Iterator zur Verfügung.<br />
Wahlfreier Zugriff erfolgt über:<br />
public Object firstElement() throws NoSuchElementException;<br />
public Object lastElement() throws NoSuchElementException;<br />
public Object elementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x) throws ArrayIn<strong>de</strong>xOutOfBoundException;<br />
firstElement() liefert das erste, lastElement() das letzte Element- Mit<br />
elementAt() wird auf das Element an <strong>de</strong>r Position <strong>in</strong><strong>de</strong>x zugegriffen. Alle 3<br />
Metho<strong>de</strong>n verursachen e<strong>in</strong>e Ausnahme, wenn das gewünschte Element nicht<br />
vorhan<strong>de</strong>n ist.<br />
Arbeitsweise <strong>de</strong>s <strong>in</strong>ternen Arrays. Der Vector vergrößert sich automatisch, falls mehr<br />
Elemente aufgenommen wer<strong>de</strong>n. Die Operation heißt Resiz<strong>in</strong>g.<br />
422
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Größe <strong>de</strong>s Felds. Mit capacity() erhält man die <strong>in</strong>terne Größe <strong>de</strong>s Arrays. Sie kann mit<br />
ensureCapacity() geän<strong>de</strong>rt wer<strong>de</strong>n. ensureCapacity(<strong>in</strong>t m<strong>in</strong>imumCapacity) bewirkt bei<br />
e<strong>in</strong>em Vector, daß er m<strong>in</strong><strong>de</strong>stens m<strong>in</strong>Capacity Elemente aufnehmen soll.<br />
Der Vektor verkle<strong>in</strong>ert nicht die aktuelle Kapazität, falls sie schon höher als m<strong>in</strong>Capacity ist. Zur<br />
Verän<strong>de</strong>rung dieser Größe, dient die Metho<strong>de</strong> trimToSize(). Sie reduziert die Kapazität <strong>de</strong>s<br />
Vectors auf die Anzahl <strong>de</strong>r Elemente, die gera<strong>de</strong> im Vector s<strong>in</strong>d.<br />
Die Anzahl <strong>de</strong>r Elemente kann über die Metho<strong>de</strong> size() erfragt wer<strong>de</strong>n. Sie kann über<br />
setSize(<strong>in</strong>t newSize) geän<strong>de</strong>rt wer<strong>de</strong>n. Ist die neue Größe kle<strong>in</strong>er als die alte, so wer<strong>de</strong>n die<br />
Elemente am En<strong>de</strong> <strong>de</strong>s Vectors abgeschnitten. Ist newSize größer als die alte Größe, wer<strong>de</strong>n die<br />
neu angelegten Elemente mit null <strong>in</strong>itialisiert.<br />
Bereitstellen <strong>de</strong>s Interface Enumerartion. In <strong>de</strong>r Klasse Vector liefert die Metho<strong>de</strong> public<br />
Enumeration elements() e<strong>in</strong>en Enumerator (Iterator) für alle Elemente, die sich <strong>in</strong> Vector bef<strong>in</strong><strong>de</strong>n.<br />
Vector<br />
><br />
public Vector()<br />
// E<strong>in</strong> Vector <strong>in</strong> <strong>de</strong>r Anfangsgröße von 10 Elementen wird angelegt<br />
public Vector(<strong>in</strong>t startKapazitaet)<br />
// E<strong>in</strong> Vector enthält Platz für startKapazitaet Elemente<br />
public Vector(<strong>in</strong>t startKapazitaet, <strong>in</strong>t kapazitaetsSchrittweite)<br />
><br />
public Object elementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// Das an <strong>de</strong>r Stelle <strong>in</strong><strong>de</strong>x bef<strong>in</strong>dliche Objekt wird zurückgegeben<br />
public <strong>in</strong>t size()<br />
public Object firstElement()<br />
public Object lastElement();<br />
public void <strong>in</strong>sertElementAt(Object obj, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// fügt Object obj an <strong>in</strong><strong>de</strong>x e<strong>in</strong> und verschiebt die an<strong>de</strong>ren Elemente<br />
public void setElementAt(Object obj, <strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public copyInto(Object e<strong>in</strong>Array[])<br />
// kopiert die Elemente <strong>de</strong>s Vektors <strong>in</strong> das Array e<strong>in</strong>Array<br />
// Falls das bereitgestellte Objektfeld nicht so groß ist wie <strong>de</strong>r Vektor,<br />
// dann tritt e<strong>in</strong>e In<strong>de</strong>xOutOfBoundsException auf<br />
public boolean conta<strong>in</strong>s(Object obj)<br />
// sucht das Element, liefert true zurück wenn o im Vector vorkommt<br />
public <strong>in</strong>t <strong>in</strong><strong>de</strong>xOf(Object obj)<br />
// sucht im Vector nach <strong>de</strong>m Objekt obj. Falls obj nicht <strong>in</strong> <strong>de</strong>r Liste ist, wird<br />
// -1 übergeben<br />
public <strong>in</strong>t lastIn<strong>de</strong>xOf(Object obj)<br />
public boolean removeElement(Object obj)<br />
// entfernt obj aus <strong>de</strong>r Liste. Konnte es entfernt wer<strong>de</strong>n, wird true<br />
// zurückgeliefert<br />
public void removeElementAt(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// entfernt das Element an Stelle <strong>in</strong><strong>de</strong>x<br />
public void removeAllElements()<br />
// löscht alle Elemente<br />
public <strong>in</strong>t capacity()<br />
// gibt an, wieviel Elemente im Vektor Patz haben<br />
// (, ohne daßautomatische Größenanpassung erfolgt)<br />
public Object clone()<br />
// Implementierung <strong>de</strong>r clone()-metho<strong>de</strong> von Object, d.h. e<strong>in</strong>e Referenz<br />
// <strong>de</strong>s kopierten Fel<strong>de</strong>s wird zurückgegeben. Die Kopie ist flach.<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
Abb.: Die Klasse Vector<br />
423
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.1.3 Die Klasse Stack<br />
class java.util.Stack extends Vector<br />
E<strong>in</strong> Stack ist e<strong>in</strong>e nach <strong>de</strong>m LIFO-Pr<strong>in</strong>zip arbeiten<strong>de</strong> Datenstruktur. Elemente<br />
wer<strong>de</strong>n vorn (am vor<strong>de</strong>ren En<strong>de</strong> <strong>de</strong>r Liste) e<strong>in</strong>gefügt und von dort auch wie<strong>de</strong>r<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 <strong>de</strong>s 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 <strong>de</strong>s 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 gefun<strong>de</strong>nem und<br />
// obersten Stack-Element bzw. –1,<br />
// falls das Element nicht da ist.<br />
Test:public boolean empty()<br />
// bestimmt, ob <strong>de</strong>r Stack leer ist<br />
Vector<br />
Stack<br />
public Stack()<br />
public Object push(Object obj)<br />
public Object pop()<br />
public Object peek()<br />
public <strong>in</strong>t search(Object obj)<br />
public boolean empty()<br />
Abb.: Die Klasse Stack<br />
Anwendungen:<br />
1. Umrechnen von Dezimalzahlen <strong>in</strong> an<strong>de</strong>re Basisdarstellungen<br />
Aufgabenstellung: Defaultmäßig wer<strong>de</strong>n Zahlen <strong>de</strong>zimal ausgegeben. E<strong>in</strong> Stapel, <strong>de</strong>r Ganzzahlen<br />
aufnimmt, kann dazu verwen<strong>de</strong>t wer<strong>de</strong>n, Zahlen bezogen auf e<strong>in</strong>e an<strong>de</strong>re Basis als 10 darzustellen.<br />
Die Funktionsweise <strong>de</strong>r Umrechnung von Dezimalzahlen <strong>in</strong> e<strong>in</strong>e Basis e<strong>in</strong>es an<strong>de</strong>ren Zahlensystem<br />
zeigen die folgen<strong>de</strong>n Beispiele:<br />
424
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2810 = 3⋅ 8 + 4 = 348<br />
7210 = 1⋅ 64 + 0⋅ 16 + 2 ⋅ 4 + 0 = 10204<br />
= ⋅ + ⋅ + ⋅ + ⋅ + ⋅ + =<br />
53 1 32 1 16 0 8 1 4 0 2 1 110101<br />
10 2<br />
Mit e<strong>in</strong>em Stapel läßt sich die Umrechnung folgen<strong>de</strong>rmaßen unterstützen:<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<br />
n/8=444 n/8=55 n/8=6 n/6=0<br />
n = 444 10<br />
n = 55 10<br />
n = 6 10<br />
n = 0 10<br />
Abb.: Umrechnung von 3553 10 <strong>in</strong> 6741 8 mit Hilfe e<strong>in</strong>es Stapel<br />
Algorithmus zur Lösung <strong>de</strong>r Aufgabe:<br />
1) Die am weitesten rechts stehen<strong>de</strong> Ziffer von n ist n%b. Sie ist auf <strong>de</strong>m 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) Wie<strong>de</strong>rhole die Arbeitsschritte 1) und 2) bis ke<strong>in</strong>e signifikanten Ziffern mehr übrig bleiben.<br />
4) Die Darstellung <strong>de</strong>r Zahl <strong>in</strong> <strong>de</strong>r neuen Basis ist aus <strong>de</strong>m Stapel abzulesen. Der Stapel ist zu diesem<br />
Zweck zu entleeren.<br />
Implementierung: Das folgen<strong>de</strong> kle<strong>in</strong>e Testprogramm 304 realisiert <strong>de</strong>n Algorithmus und benutzt dazu<br />
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;<br />
// 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 />
304 pr61210<br />
425
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
2. E<strong>in</strong>lesen e<strong>in</strong>er Folge ganzer Zahlen, Ausgabe <strong>de</strong>r Zahlen <strong>in</strong> umgekehrter<br />
Reihenfolge 305<br />
import java.io.*;<br />
import java.util.*;<br />
public class Reverse<br />
{<br />
public static void ma<strong>in</strong> (Str<strong>in</strong>g args[]) throws IOException<br />
{<br />
<strong>in</strong>t a[]=new <strong>in</strong>t[20];<br />
//Stapel<br />
Stack s = new Stack();<br />
// E<strong>in</strong>lesen <strong>de</strong>r ganzen Zahlen, Aufnahme <strong>de</strong>r Zahlen <strong>in</strong> e<strong>in</strong>en ganzzahligen<br />
// Array, Aufnahme <strong>de</strong>r im ganzzahligen Array gespeicherten Zahlen <strong>in</strong><br />
// e<strong>in</strong>en Stapel<br />
BufferedRea<strong>de</strong>r e<strong>in</strong>=new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r(System.<strong>in</strong>));<br />
for ( <strong>in</strong>t i=0;i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.1.4 Die Klasse Bitset für Bitmengen<br />
class java.util.BitSet implements Cloneable, Serializable<br />
Die Klasse Bitset bietet komfortable Möglichkeiten zur bitweisen Manipulation von<br />
Daten.<br />
Bitset anlegen und füllen. Mit zwei Metho<strong>de</strong>n lassen sich die Bits <strong>de</strong>s Bitsets leicht<br />
än<strong>de</strong>rn: set(<strong>in</strong>t bitNummer) und clear(<strong>in</strong>t bitNummer).<br />
Mengenor<strong>in</strong>tierte Operationen. Das Bitset erlaubt mengenorientierte Operationen mit<br />
e<strong>in</strong>er weiteren Menge.<br />
BitSet<br />
Abb.: Die Klasse BitSet<br />
public void and(BitSet bs)<br />
public void or(BitSet bs)<br />
public void xor(BitSet bs)<br />
public void andNot(Bitset set)<br />
// löscht alle Bits im Bitset, <strong>de</strong>ssen Bit <strong>in</strong> set gesetzt s<strong>in</strong>d<br />
public void clear(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// Löscht e<strong>in</strong> Bit. Ist <strong>de</strong>r In<strong>de</strong>x negativ, kommt es<br />
// zur Auslösung von In<strong>de</strong>xOutOfBoundsException<br />
public void set(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// Setzt e<strong>in</strong> Bit. Ist <strong>de</strong>r In<strong>de</strong>x negativ, kommt es<br />
// zur Auslösung von In<strong>de</strong>xOutOfBoundsException<br />
public boolean get(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// liefert <strong>de</strong>n Wert <strong>de</strong>s Felds am übergebenen In<strong>de</strong>x,<br />
// kann In<strong>de</strong>xOutOfBoundsException auslösen.<br />
public <strong>in</strong>t size()<br />
public boolean equals(Object o)<br />
// Vergleicht sich mit e<strong>in</strong>em an<strong>de</strong>ren Bitset-Objekt o.<br />
Bsp. 306 : Anwendung <strong>de</strong>r Klasse BitSet bei <strong>de</strong>r Konstruktion e<strong>in</strong>er Menge von<br />
Primzahlen<br />
import java.util.*;<br />
public class Primtest<br />
{<br />
f<strong>in</strong>al static <strong>in</strong>t MAXPRIM = 30;<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
BitSet b = new BitSet();<br />
for (<strong>in</strong>t i = 2; i
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
6.1.5 Die Klasse Hashtable und assoziative Speicher<br />
E<strong>in</strong>e Hashtabelle (Hashtable) ist e<strong>in</strong> assoziativer Speicher, <strong>de</strong>r Schlüssel (keys) mit<br />
Werten verknüpft. Die Datenstruktur ist mit e<strong>in</strong>em Wörterbuch vergleichbar. Die<br />
Hashtabelle arbeitet mit Schlüssel/Werte Paaren. Aus <strong>de</strong>m Schlüssel wird nach e<strong>in</strong>er<br />
Funktion – <strong>de</strong>r sog. Hashfunktion – e<strong>in</strong> Hashco<strong>de</strong> berechnet. Dieser dient als In<strong>de</strong>x<br />
für e<strong>in</strong> <strong>in</strong>ternes Array. Dieses Array hat zu Anfang e<strong>in</strong> feste Grösse. Lei<strong>de</strong>r hat dieses<br />
Technik e<strong>in</strong>en entschei<strong>de</strong>n<strong>de</strong>n Nachteil. Besitzen zwei Wörter <strong>de</strong>nselben Hashco<strong>de</strong>,<br />
dann kommt es zu e<strong>in</strong>er Kollision. Auf ihn muß die Datenstruktur vorbereitet se<strong>in</strong>.<br />
Hier gibt es verschie<strong>de</strong>ne Lösungsansätze. Die unter <strong>Java</strong> implementierte Variante<br />
benutzt e<strong>in</strong>e verkettete Liste (separate Cha<strong>in</strong><strong>in</strong>g). Falls e<strong>in</strong>e Kollision auftritt, so wird<br />
<strong>de</strong>r Hashco<strong>de</strong> beibehalten und <strong>de</strong>r Schlüssel bzw. Wert <strong>in</strong> e<strong>in</strong>em Listenelement an<br />
<strong>de</strong>n vorhan<strong>de</strong>nen E<strong>in</strong>trag angehängt. Wenn allerd<strong>in</strong>gs irgendwann e<strong>in</strong>mal e<strong>in</strong>e Liste<br />
durchsucht wer<strong>de</strong>n muß, dann wird die Datenstruktur langsam. E<strong>in</strong> Maß für <strong>de</strong>n<br />
Füllgrad ist <strong>de</strong>r Füllfaktor (Load Factor). Dieser liegt zwischen 0 und 100 %. 0<br />
be<strong>de</strong>utet: ke<strong>in</strong> Listenelement wird verwen<strong>de</strong>t. 100 % be<strong>de</strong>utet: Es ist ke<strong>in</strong> Platz mehr<br />
im Array und es wer<strong>de</strong>n nur noch Listen für alle zukommen<strong>de</strong>n Werte erweitert. Der<br />
Füllfaktor sollte für effiziente Anwendungen nicht höher als 75% se<strong>in</strong>. Ist e<strong>in</strong><br />
Füllfaktor nicht explizit angegeben, dann wird die Hashtabelle „rehashed“, wenn mehr<br />
als 75% aller Plätze besetzt s<strong>in</strong>d.<br />
class java.util.Hashtable extends Dictionary implements Map,<br />
Cloneable, Serializable<br />
Erzeugen von e<strong>in</strong>em Objekt <strong>de</strong>r Klasse Hashtable:<br />
public Hashtable()<br />
/* Die Hashtabelle enthält e<strong>in</strong>e Kapazität von 11 E<strong>in</strong>trägen und e<strong>in</strong>en Füllfaktor von 75 % */<br />
public Hashtable(<strong>in</strong>t <strong>in</strong>itialCapacity)<br />
/* erzeugt e<strong>in</strong>e Hashtabelle mit e<strong>in</strong>er vorgebenen Kapazität und <strong>de</strong>m Füllfaktor 0.75 */<br />
public Hashtable(<strong>in</strong>t <strong>in</strong>itialCapacity, float loadFactor)<br />
/* erzeugt e<strong>in</strong>e Hashtabelle mit e<strong>in</strong>er vorgebenen Kapazität und <strong>de</strong>m angegebenen Füllfaktor */<br />
Daten e<strong>in</strong>fügen: public Object put(Object key, Object value)<br />
/* speichert <strong>de</strong>n Schlüssel und <strong>de</strong>n Wert <strong>in</strong> <strong>de</strong>r Hashtabelle. Falls sich zu <strong>de</strong>m<br />
Schlüssel schon e<strong>in</strong> E<strong>in</strong>trag <strong>in</strong> <strong>de</strong>r Hashtabelle befand, so wird dieser<br />
zurückgegeben. An<strong>de</strong>renfalls ist <strong>de</strong>r Rückgabewert null. Die Metho<strong>de</strong> ist<br />
vorgegeben vom Interface Map. Es überschreibt die Metho<strong>de</strong> von <strong>de</strong>r Superklasse<br />
Dictionary. */<br />
Daten holen: public Object get(Object key)<br />
Schlüssel entfernen. public Object remove(Object key)<br />
Löschen <strong>de</strong>r Werte. public void clear()<br />
Test. public boolean conta<strong>in</strong>sKey(Object key)<br />
// Test auf e<strong>in</strong>en bestimmten Schlüssel<br />
public boolean conta<strong>in</strong>sValue(Object value)<br />
// Test auf e<strong>in</strong>en bestimmten Wert<br />
Aufzählen <strong>de</strong>r Elemente. Mit keys() und elements() bietet die Hashtabelle zwei<br />
Metho<strong>de</strong>n an, die e<strong>in</strong>e Aufzählung zurückgeben:<br />
public Enumeration keys()<br />
// liefert e<strong>in</strong>e Aufzählung aller Schlüssel, überschreibt keys() <strong>in</strong> Dictionary.<br />
428
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public Enumeration elements()<br />
// liefert e<strong>in</strong>e Aufzählung <strong>de</strong>r Werte, überschreibt elements() <strong>in</strong> Dictionary<br />
Wie üblich liefern bei<strong>de</strong> Iteratoren e<strong>in</strong> Objekt, welches das Interface Enumeration<br />
implementiert. Der Zugriff erfolgt daher mit Hilfe <strong>de</strong>r Metho<strong>de</strong>n hasMoreElements()<br />
und nextElement().<br />
Dictionary<br />
{abstract}<br />
public abstract Object put (Object key, Object value)<br />
public abstract Object get(Object key)<br />
public abstract Enumeration elements()<br />
public abstract Enumeration keys()<br />
public abstract <strong>in</strong>t size()<br />
public abstract boolean isEmpty()<br />
public abstract Object remove(Object key)<br />
Hashtable<br />
Map<br />
><br />
public Hashtable(<strong>in</strong>t <strong>in</strong>itialKapazitaet)<br />
public Hashtable(<strong>in</strong>t <strong>in</strong>itialKapazitaet, float La<strong>de</strong>faktor)<br />
public Hashtable()<br />
><br />
public boolean conta<strong>in</strong>s(Object wert)<br />
public boolean conta<strong>in</strong>sKey(Object key)<br />
public void clear()<br />
public Object clone()<br />
protected void rehash()<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
Properties<br />
><br />
public Properties()<br />
// legt e<strong>in</strong>en leeren Conta<strong>in</strong>er an<br />
public Properties(Properties <strong>de</strong>faults)<br />
// füllt e<strong>in</strong>e Property-Liste mit <strong>de</strong>n angegebenen Default-Werten<br />
><br />
public Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key)<br />
public Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key, Str<strong>in</strong>g <strong>de</strong>faultKey)<br />
public void load(InputStream <strong>in</strong>) throws IOException<br />
// Hier muß e<strong>in</strong> InputStream übergeben wer<strong>de</strong>n, <strong>de</strong>r die daten <strong>de</strong>r<br />
// Property-Liste zur Verfügung stellt.<br />
public void store(OutputStream out, Str<strong>in</strong>g hea<strong>de</strong>r)<br />
public void list(Pr<strong>in</strong>tStream out)<br />
public void list(Pr<strong>in</strong>tWriter out)<br />
public Enumeration propertyNames()<br />
// beschafft e<strong>in</strong> Enumerations-Objekt mit <strong>de</strong>nen Eigenschaften<br />
// <strong>de</strong>r Property-Liste aufgezählt wer<strong>de</strong>n können<br />
429
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Abb.: Die Klassen Hashtable und Properties<br />
Die Klasse Hashtable ist e<strong>in</strong>e Konkretisierung <strong>de</strong>r abstrakten Klasse Dictionary.<br />
Diese Klasse beschreibt e<strong>in</strong>en assoziativen Speicher, <strong>de</strong>r Schlüssel auf Werte<br />
abbil<strong>de</strong>t und über <strong>de</strong>n Schlüsselbegriff e<strong>in</strong>en effizienten Zugriff auf <strong>de</strong>n Wert<br />
ermöglicht. E<strong>in</strong>fügen und <strong>de</strong>r Zugriff auf Schlüssel erfolgt nicht auf <strong>de</strong>r Basis <strong>de</strong>s<br />
Operators „==“, son<strong>de</strong>rn mit Hilfe <strong>de</strong>r Metho<strong>de</strong> „equals“. Schlüssel müssen daher<br />
lediglich <strong>in</strong>haltlich gleich se<strong>in</strong>, um als i<strong>de</strong>ntisch angesehen zu wer<strong>de</strong>n.<br />
Beispiele.<br />
1. Hashtabelle zum Test <strong>de</strong>r von Zufallszahlen <strong>de</strong>r Metho<strong>de</strong> Math.random() 307 .<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 />
public 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 />
2. Hashtabelle für direkten Zugriff auf Daten 308<br />
import java.io.*;<br />
import java.util.*;<br />
public class HashTabTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [ ] args)<br />
{<br />
// Map map = new HashMap();<br />
Hashtable h = new Hashtable();<br />
Str<strong>in</strong>g e<strong>in</strong>gabeZeile = null;<br />
BufferedRea<strong>de</strong>r e<strong>in</strong>gabe = null;<br />
try {<br />
e<strong>in</strong>gabe = new BufferedRea<strong>de</strong>r(<br />
new FileRea<strong>de</strong>r("e<strong>in</strong>g.txt"));<br />
}<br />
catch (FileNotFoundException io)<br />
307 pr61310<br />
308 pr61310<br />
430
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
System.out.pr<strong>in</strong>tln("Fehler beim E<strong>in</strong>lesen!");<br />
}<br />
try {<br />
while ( (e<strong>in</strong>gabeZeile = e<strong>in</strong>gabe.readL<strong>in</strong>e() ) != null)<br />
{<br />
Str<strong>in</strong>gTokenizer str = new Str<strong>in</strong>gTokenizer(e<strong>in</strong>gabeZeile);<br />
if (e<strong>in</strong>gabeZeile.equals("")) break;<br />
Str<strong>in</strong>g key = str.nextToken();<br />
Str<strong>in</strong>g daten = str.nextToken();<br />
System.out.pr<strong>in</strong>tln(key);<br />
h.put(key,daten);<br />
// map.put(key,daten);<br />
}<br />
}<br />
catch (IOException ioe)<br />
{<br />
System.out.pr<strong>in</strong>tln("E<strong>in</strong>gefangen <strong>in</strong> ma<strong>in</strong>()");<br />
}<br />
try {<br />
e<strong>in</strong>gabe.close();<br />
}<br />
catch(IOException e)<br />
{<br />
System.out.pr<strong>in</strong>tln(e);<br />
}<br />
System.out.pr<strong>in</strong>tln("Uebersicht zur Hash-Tabelle");<br />
// System.out.pr<strong>in</strong>tln(map);<br />
System.out.pr<strong>in</strong>tln(h);<br />
//h.pr<strong>in</strong>tHashTabelle();<br />
System.out.pr<strong>in</strong>tln("Abfragen bzw. Modifikationen");<br />
// Wie<strong>de</strong>rauff<strong>in</strong><strong>de</strong>n<br />
Str<strong>in</strong>g e<strong>in</strong>gabeKey = null;<br />
BufferedRea<strong>de</strong>r e<strong>in</strong> = new BufferedRea<strong>de</strong>r(<br />
new InputStreamRea<strong>de</strong>r(System.<strong>in</strong>));<br />
System.out.pr<strong>in</strong>tln("Wie<strong>de</strong>rauff<strong>in</strong><strong>de</strong>n von Elementen");<br />
while (true)<br />
{<br />
try {<br />
System.out.pr<strong>in</strong>t("Bitte Schluessel e<strong>in</strong>geben, ! be<strong>de</strong>utet En<strong>de</strong>: ");<br />
e<strong>in</strong>gabeKey = e<strong>in</strong>.readL<strong>in</strong>e();<br />
// System.out.pr<strong>in</strong>tln(e<strong>in</strong>gabeKey);<br />
if (e<strong>in</strong>gabeKey.equals("!")) break;<br />
Str<strong>in</strong>g e<strong>in</strong>tr = (Str<strong>in</strong>g) h.get(e<strong>in</strong>gabeKey);<br />
// Str<strong>in</strong>g e<strong>in</strong>tr = (Str<strong>in</strong>g) map.get(e<strong>in</strong>gabeKey);<br />
if (e<strong>in</strong>tr == null)<br />
System.out.pr<strong>in</strong>tln("Ke<strong>in</strong> E<strong>in</strong>trag!");<br />
else<br />
{<br />
System.out.pr<strong>in</strong>tln(e<strong>in</strong>tr);<br />
System.out.pr<strong>in</strong>tln("Soll dieser E<strong>in</strong>trag geloescht wer<strong>de</strong>n? ");<br />
Str<strong>in</strong>g antwort = e<strong>in</strong>.readL<strong>in</strong>e();<br />
// System.out.pr<strong>in</strong>tln(antwort);<br />
if ((antwort.equals("j")) || (antwort.equals("J")))<br />
{<br />
// System.out.pr<strong>in</strong>tln("E<strong>in</strong>trag wird entfernt!");<br />
h.remove(e<strong>in</strong>gabeKey);<br />
// map.remove(e<strong>in</strong>gabeKey);<br />
}<br />
}<br />
}<br />
catch(IOException ioe)<br />
{<br />
System.out.pr<strong>in</strong>tln(e<strong>in</strong>gabeKey +<br />
" konnte nicht korrekt e<strong>in</strong>gelesen wer<strong>de</strong>n!");<br />
}<br />
431
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
System.out.pr<strong>in</strong>tln(h);<br />
// System.out.pr<strong>in</strong>tln(map);<br />
// System.out.pr<strong>in</strong>tln("Sortierte Tabelle");<br />
// Map sortedMap = new TreeMap(map);<br />
// System.out.pr<strong>in</strong>tln(sortedMap);<br />
}<br />
}<br />
Die Klasse Hashtable benutzt das Verfahren <strong>de</strong>r Schlüsseltransformation (Hash-<br />
Funktion) zur Abbildung von Schlüsseln auf In<strong>de</strong>xpostionen e<strong>in</strong>es Arrays. Die<br />
Kapazität <strong>de</strong>r Hash-Tabelle gibt die Anzahl <strong>de</strong>r Elemente an, die <strong>in</strong>sgesamt<br />
untergebracht wer<strong>de</strong>n können. Der La<strong>de</strong>faktor zeigt an, bei welchem Füllungsgrad<br />
die Hash-Tabelle vergrößert wer<strong>de</strong>n muß. Das Vergrößern erfolgt automatisch, falls<br />
die Anzahl <strong>de</strong>r Elemente <strong>in</strong>nerhalb <strong>de</strong>r Tabelle größer ist als das Produkt aus<br />
Kapazität und La<strong>de</strong>faktor. Seit <strong>de</strong>m JDK 1.2 darf <strong>de</strong>r La<strong>de</strong>faktor auch größer als 1<br />
se<strong>in</strong>. In diesem Fall wird die Hash-Tabelle erst dann vergrößert, wenn <strong>de</strong>r<br />
Füllungsgrad größer als 100% ist und bereits e<strong>in</strong> Teil <strong>de</strong>r Elemente <strong>in</strong> <strong>de</strong>n<br />
Überlaufbereichen untergebracht wur<strong>de</strong>.<br />
Die Klasse Hashtable ist e<strong>in</strong>e beson<strong>de</strong>re Klasse für Wörterbücher. E<strong>in</strong> Wörterbuch<br />
ist e<strong>in</strong>e Datenstruktur, die Elemente mite<strong>in</strong>an<strong>de</strong>r assoziiert. Das Wörterbuchproblem<br />
ist das Problem, wie aus <strong>de</strong>m Schlüssel möglichst schnell <strong>de</strong>r zugehörige Wert<br />
konstruiert wird. Die Lösung <strong>de</strong>s Problems ist: Der Schlüssel wird als Zahl kodiert<br />
(Hashco<strong>de</strong>) und dient <strong>in</strong> e<strong>in</strong>em Array als In<strong>de</strong>x. An e<strong>in</strong>em In<strong>de</strong>x hängen dann noch<br />
die Werte mit gleichem Hashco<strong>de</strong> als Liste an.<br />
6.1.6 Die abstrakte Klasse Dictionary<br />
Die Klasse Dictionary ist e<strong>in</strong>e abstrakte Klasse, die Metho<strong>de</strong>n anbietet, wie<br />
Objekte (also Schlüssel und Wert) mite<strong>in</strong>an<strong>de</strong>r assoziiert wer<strong>de</strong>n:<br />
public abstract Object put(Object key, Object value)<br />
// fügt <strong>de</strong>n Schlüssel key mit <strong>de</strong>m verbun<strong>de</strong>nen Wert value <strong>in</strong> das Wörterbuch<br />
// e<strong>in</strong><br />
public abstract Object get(Object key)<br />
// liefert das zu key gehören<strong>de</strong> Objekt zurück. Falls ke<strong>in</strong> Wert mit <strong>de</strong>m<br />
// Schlüssel verbun<strong>de</strong>n ist, so liefert get() e<strong>in</strong>e null. E<strong>in</strong>e null als<br />
// Schlüssel o<strong>de</strong>r Wert kann nicht e<strong>in</strong>gesetz wer<strong>de</strong>n. In put() wür<strong>de</strong> das zu<br />
// e<strong>in</strong>er NullPo<strong>in</strong>terException führen.<br />
public abstract Object remove(Object key)<br />
// entfernt e<strong>in</strong> Schlüssel/Wertepaar aus <strong>de</strong>m Wörterbuch. Zurückgegeben wird<br />
// <strong>de</strong>r assoziierte Wert.<br />
public abstract boolean isEmpty()<br />
// true, falls ke<strong>in</strong>e Werte im Wörterbuch<br />
public <strong>in</strong>t size()<br />
gibt zurück, wie viele Elemente aktuell im Wörterbuch s<strong>in</strong>d.<br />
public abstract Enumeration keys()<br />
// liefert e<strong>in</strong>e Enumeration für alle Schlüssel<br />
public abstract Enumeration elements()<br />
// liefert e<strong>in</strong>e Enumeration über alle Werte.<br />
432
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.1.7 Die Klasse Properties<br />
Die Properties Klasse ist e<strong>in</strong>e Erweiterung von Hashtable. E<strong>in</strong> Properties Objekt<br />
erweitert die Hashtable um die Möglichkeit, sich unter e<strong>in</strong>em wohl<strong>de</strong>f<strong>in</strong>ierten Format<br />
über e<strong>in</strong>en Strom zu la<strong>de</strong>n und zu speichern.<br />
Erzeugen. public Properties()<br />
// erzeugt e<strong>in</strong> leeres Propertes Objekt ohne Worte.<br />
public Properties(Properties p)<br />
// erzeugt e<strong>in</strong> leeres Properties Objekt mit Standard-werten aus <strong>de</strong>n<br />
// übergebenen Properties<br />
La<strong>de</strong>n e<strong>in</strong>er Properties-Liste. public void load(InputStream is)<br />
Speichern e<strong>in</strong>er Properties-Liste. public void store(OutputStream os,<br />
Str<strong>in</strong>g kennung). An <strong>de</strong>n Kopf <strong>de</strong>r Datei wird e<strong>in</strong>e kennung geschrieben (die im<br />
2. Argument angegeben ist). Die Kennung darf „null“ se<strong>in</strong>.<br />
Enumeration. public void Enumeration propertyNames()<br />
Zeichenketten suchen. Die Metho<strong>de</strong> getProperty(Str<strong>in</strong>g s).<br />
public Str<strong>in</strong>g getProperty(Str<strong>in</strong>g s)<br />
// sucht <strong>in</strong> <strong>de</strong>n Properties nach <strong>de</strong>r Zeichenkette<br />
public Str<strong>in</strong>g getProperty(Str<strong>in</strong>g key, Str<strong>in</strong>g <strong>de</strong>fault)<br />
// sucht <strong>in</strong> <strong>de</strong>n Properties nach <strong>de</strong>r Zeichenkette key. Ist dieser nicht<br />
// vorhan<strong>de</strong>n, wird <strong>de</strong>r Str<strong>in</strong>g <strong>de</strong>fault zurückgegeben<br />
Eigenschaften ausgeben. Die Metho<strong>de</strong> list() wan<strong>de</strong>rt durch die Daten und gibt sie<br />
auf e<strong>in</strong>em Pr<strong>in</strong>tWriter aus:<br />
public void list(Pr<strong>in</strong>tWriter pw)<br />
// listet die Properties auf <strong>de</strong>m Pr<strong>in</strong>tWriter aus.<br />
Bsp.: Systemeigenschaften <strong>de</strong>r <strong>Java</strong>-Umgebung<br />
import java.util.*;<br />
import java.io.*;<br />
public class SaveProp<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
try {<br />
Properties p1 = System.getProperties();<br />
FileOutputStream propAusFile = new<br />
FileOutputStream("properties.txt");<br />
p1.store(propAusFile,null);<br />
propAusFile.close();<br />
Properties p2 = new Properties();<br />
FileInputStream e<strong>in</strong>g = new FileInputStream("properties.txt");<br />
p2.load(e<strong>in</strong>g);<br />
p2.list(System.out);<br />
}<br />
catch(IOException e) { System.err.pr<strong>in</strong>tln(e);}<br />
}<br />
}<br />
433
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2 Collection API<br />
Die <strong>Java</strong> 2 Plattform hat <strong>Java</strong> erweitert um das Collection API. Anstatt Collection<br />
kann man auch Conta<strong>in</strong>er (Behälter) sagen. E<strong>in</strong> Conta<strong>in</strong>er ist e<strong>in</strong> Objekt, das<br />
wie<strong>de</strong>rum Objekte aufnimmt und die Verantwortung für die Elemente übernimmt. Im<br />
„util“-Paket bef<strong>in</strong><strong>de</strong>n sich sechs Schnittstellen, die grundlegen<strong>de</strong> Eigenschaften<br />
<strong>de</strong>r Conta<strong>in</strong>erklassen <strong>de</strong>f<strong>in</strong>ieren.<br />
Das <strong>in</strong> <strong>Java</strong> 1.2 enthaltene Collections Framework be<strong>in</strong>haltet im Wesentlichen drei<br />
Grundformen: Set, List und Map. Je<strong>de</strong> dieser Grudformen ist als Interface<br />
implementiert. Die Interfaces List und Set s<strong>in</strong>d direkt aus Collection abgeleitet. Es<br />
gibt auch noch e<strong>in</strong>e abstrakte Implementierung <strong>de</strong>s Interface, mit <strong>de</strong>ssen Hilfe das<br />
Erstellen eigener Collections erleichtert wird. Bei allen Collections, die das Interface<br />
Collection implementieren, kann e<strong>in</strong> Iterator zum Durchlaufen <strong>de</strong>r Elemente mit <strong>de</strong>r<br />
Metho<strong>de</strong> „iterator()“ beschafft wer<strong>de</strong>n.<br />
Zusätzlich for<strong>de</strong>rt die JDK 1.2-Spezifikation für je<strong>de</strong> Collection-Klasse zwei<br />
Konstruktoren:<br />
- E<strong>in</strong>en parameterlosen Konstruktor zum Anlegen e<strong>in</strong>er neuen Collection.<br />
- E<strong>in</strong> mit e<strong>in</strong>em e<strong>in</strong>zigen Collection-Argument ausgestatteter Konstruktor, <strong>de</strong>r e<strong>in</strong>e neue Collection anlegt und<br />
mit <strong>de</strong>n Elementen <strong>de</strong>r als Argument übergebenen Collection auffüllt.<br />
6.2.1 Die Schnittstellen Collection, Iterator, Comparator<br />
Das Interface Collection bil<strong>de</strong>t die Basis <strong>de</strong>r Collection-Klasse und –Interfaces <strong>de</strong>s<br />
JDK 1.2. Alle Behälterklassen implementieren das Collection Interface und geben<br />
<strong>de</strong>n Klassen damit e<strong>in</strong>en äußeren Rahmen.<br />
434
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Das Interface Collection<br />
><br />
Collection<br />
public void clear();<br />
// Optional: Löscht alle Elemente <strong>in</strong> <strong>de</strong>m Conta<strong>in</strong>er. Eird dies vom Conta<strong>in</strong>er nicht unterstützt,<br />
// kommt es zur UnsupportedOperationException<br />
public boolean add(Object o);<br />
// Optional: Fügt e<strong>in</strong> Objekt <strong>de</strong>m Conta<strong>in</strong>er h<strong>in</strong>zu und gibt true zurück, falls sich das Element<br />
// e<strong>in</strong>fügen läßt. Gibt false zurück, falls schon e<strong>in</strong> Objektwert vorhan<strong>de</strong>n ist und doppelte Werte<br />
// nicht erlaubt s<strong>in</strong>d.<br />
public boolean addAll(Collection c);<br />
// fügt alle Elemente <strong>de</strong>r Collection c <strong>de</strong>m Conta<strong>in</strong>er h<strong>in</strong>zu<br />
public boolean remove(Object o);<br />
// Entfernen e<strong>in</strong>er e<strong>in</strong>zelnen Instanz. Rückgabewert ist true, wenn das Element gefun<strong>de</strong>n und<br />
// entfernt wer<strong>de</strong>n konnte<br />
public boolean removeAll(Collection c);<br />
// Oprtional: Entfernt alle Objekte <strong>de</strong>r Collection c aus <strong>de</strong>m Conta<strong>in</strong>er<br />
public boolean conta<strong>in</strong>s(Object o);<br />
// liefert true, falls <strong>de</strong>r Conta<strong>in</strong>er das Element enthält<br />
// Rückgabewert ist true, falls das vorgegebene Element gefun<strong>de</strong>n wer<strong>de</strong>n konnte<br />
public boolean conta<strong>in</strong>sAll(Collection c);<br />
// liefert true, falls <strong>de</strong>r Conta<strong>in</strong>er alle Elemente <strong>de</strong>r Collection c enthält.<br />
public boolean equals(Object o);<br />
// vergleicht das angegebene Objekt mit <strong>de</strong>m Conta<strong>in</strong>er, ob die gleichen Elemente vorkommen.<br />
public boolean isEmpty();<br />
// liefert true, falls <strong>de</strong>r Conta<strong>in</strong>er ke<strong>in</strong>e Elemente enthält<br />
public <strong>in</strong>t size();<br />
// gibt die Größe <strong>de</strong>s Conta<strong>in</strong>ers zurück<br />
public boolean reta<strong>in</strong>All(Collection c);<br />
public Iterator iterator();<br />
public Object[] toArray();<br />
// gibt e<strong>in</strong> Array mit Elementen <strong>de</strong>s Conta<strong>in</strong>ers zurück<br />
public Object[] toArray(Object[] a);<br />
public <strong>in</strong>t hashCo<strong>de</strong>();<br />
// liefert <strong>de</strong>n Hashwert <strong>de</strong>s Conta<strong>in</strong>ers<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
// Rückgabewert ist die Zeichenketten-Repräsentation <strong>de</strong>r Kollektion.<br />
Abb.: Das Interface Collection<br />
Die abstrakte Basisklasse AbstractCollection implementiert die Metho<strong>de</strong>n <strong>de</strong>s<br />
Interface Collection (ohne iterator() und size()). AbstractCollection<br />
ist die Basisklasse von AbstractList und AbstractSet.<br />
435
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Das Interface Iterator<br />
><br />
Iterator<br />
public boolean hasNext();<br />
// gibt true zurück, wenn <strong>de</strong>r Iterator m<strong>in</strong><strong>de</strong>stens e<strong>in</strong> weiteres Element enthält.<br />
public Object next();<br />
// liefert das nächste Element bzw. löst e<strong>in</strong>e Ausnahme <strong>de</strong>s Typs NoSuchElementException<br />
// aus, wenn es ke<strong>in</strong>e weiteren Elemente gibt<br />
public void remove();<br />
// entfernt das Element, das <strong>de</strong>r Iterator bei next() geliefert hat.<br />
Abb.: Das Interface Iterator<br />
Bei allen Collections, die das Interface Collection implementieren, kann e<strong>in</strong> Iterator<br />
zum Durchlaufen <strong>de</strong>r Elemente mit <strong>de</strong>r Metho<strong>de</strong> „iterator()“ beschafft wer<strong>de</strong>n.<br />
Das Interface Comparator<br />
Vergleiche zwischen Objekten wer<strong>de</strong>n mit speziellen Objekten vorgenommen, <strong>de</strong>n<br />
Comparatoren. E<strong>in</strong> konkreter Comparator implementiert die folgen<strong>de</strong> Schnittstelle.<br />
><br />
java.util.Comparator<br />
public <strong>in</strong>t compare(Object o1, Object o2)<br />
// vergleicht 2 Argumente auf ihre Ordnung<br />
public boolean equals(Object arg)<br />
// testet, ob zwei Objekte bzgl. <strong>de</strong>s Comparator-Objekts gleich s<strong>in</strong>d<br />
Abb. Das Interface Comparator<br />
6.2.2 Die Behälterklassen und Schnittstellen <strong>de</strong>s Typs List<br />
Behälterklassen <strong>de</strong>s Typs List fassen e<strong>in</strong>e Menge von Elementen zusammen, auf die<br />
sequentiell o<strong>de</strong>r über In<strong>de</strong>x (-positionen) zugegriffen wer<strong>de</strong>n kann. Wie Vektoren <strong>de</strong>r<br />
Klasse Vector 309 hat das erste Element <strong>de</strong>n In<strong>de</strong>x 0 und das letzte <strong>de</strong>n In<strong>de</strong>x<br />
„size() – 1“. Es ist möglich an e<strong>in</strong>er beliebigen Stelle e<strong>in</strong> Element e<strong>in</strong>zufügen<br />
o<strong>de</strong>r zu löschen. Die weiter h<strong>in</strong>ten stehen<strong>de</strong>n Elemente wer<strong>de</strong>n dann entsprechend<br />
weiter nach rechts bzw. nach l<strong>in</strong>ks verschoben.<br />
309 seit <strong>Java</strong> 1.2 implementiert die Klasse Vector die Schnittstelle List<br />
436
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Das Interface List 310<br />
><br />
List<br />
public void add(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Object element);<br />
// E<strong>in</strong>fügen e<strong>in</strong>es Elements an <strong>de</strong>r durch In<strong>de</strong>x spezifizierten Position<br />
public boolean add(Object o);<br />
// Anhängen e<strong>in</strong>es Elements ans En<strong>de</strong> <strong>de</strong>r Liste<br />
// Rückgabewert ist true, falls die Liste durch <strong>de</strong>n Aufruf von add verän<strong>de</strong>rt wur<strong>de</strong>. Er ist false,<br />
// wenn die Liste nicht verän<strong>de</strong>rt wur<strong>de</strong>. Das kann bspw. <strong>de</strong>r Fall se<strong>in</strong>, wenn die Liste ke<strong>in</strong>e<br />
// Duplikate erlaubt und e<strong>in</strong> bereits vorhan<strong>de</strong>nes Element noch e<strong>in</strong>mal e<strong>in</strong>gefügt wer<strong>de</strong>n soll.<br />
// Konnte das Element aus e<strong>in</strong>em an<strong>de</strong>ren Grund nicht e<strong>in</strong>gefügt wer<strong>de</strong>n, wird e<strong>in</strong>e Ausnahme<br />
// <strong>de</strong>s Typs UnsupportedOperationException, ClassCastException o<strong>de</strong>r IllegalArgumentException<br />
// ausgelöst<br />
public boolean addAll(Collection c);<br />
// E<strong>in</strong>fügen e<strong>in</strong>er vollständigen Collection <strong>in</strong> die Liste. Der Rückgabewert ist true, falls die Liste<br />
// durch <strong>de</strong>n Ausfruf von add verän<strong>de</strong>r wur<strong>de</strong><br />
public boolean addAll(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Collection c)<br />
public void clear();<br />
public boolean equals(Object object);<br />
public boolean conta<strong>in</strong>s(Object element);<br />
public boolean conta<strong>in</strong>sAll(Collection collection);<br />
public Object remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
public boolean remove(Object element);<br />
public boolean removeAll(Collection c);<br />
// Alle Elemente wer<strong>de</strong>n gelöscht, die auch <strong>in</strong> <strong>de</strong>r als Argument angebenen<br />
// Collection enthalten s<strong>in</strong>d.<br />
public boolean reta<strong>in</strong>All(Collection c);<br />
// löscht alle Elemente außer <strong>de</strong>n <strong>in</strong> <strong>de</strong>r Argument-Collection enthaltenen<br />
public Object get(<strong>in</strong>t <strong>in</strong><strong>de</strong>x);<br />
public <strong>in</strong>t hashCo<strong>de</strong>();<br />
public Iterator iterator();<br />
public ListIterator listIterator():<br />
public ListIterator listIterator(<strong>in</strong>t startIn<strong>de</strong>x);<br />
public Object set(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Object element);<br />
public List subList(<strong>in</strong>t fromIn<strong>de</strong>x, <strong>in</strong>t toIn<strong>de</strong>x);<br />
public Object[] toArray();<br />
public Object[] toArray(Object[] a);<br />
Abb.: Das Interface List<br />
Auf die Elemente e<strong>in</strong>er Liste läßt sich mit e<strong>in</strong>em In<strong>de</strong>x zugreifen und nach Elementen<br />
läßt sich mit l<strong>in</strong>earem Aufwand suchen. Doppelte Elemente s<strong>in</strong>d erlaubt. Die<br />
Schnittstelle List, die <strong>in</strong> ArrayList und L<strong>in</strong>kedList e<strong>in</strong>e Implementierung f<strong>in</strong><strong>de</strong>t, erlaubt<br />
sequentiellen Zugriff auf die gespeicherten gespeicherten Elemente. Das Interface<br />
List wird im JDK von verschie<strong>de</strong>nen Klassen implementiert:<br />
AbstractList<br />
ist e<strong>in</strong>e abstrakte Basisklasse (für eigene List-Implementierungen), bei <strong>de</strong>r alle<br />
Metho<strong>de</strong>n die Ausnahme UnsupportedOperationException auslösen und diverse<br />
Metho<strong>de</strong>n abstract <strong>de</strong>klariert s<strong>in</strong>d. Die direkten Subklassen s<strong>in</strong>d<br />
310 Da ebenfalls das AWT-Paket e<strong>in</strong>e Klasse mit gleichen Namen verwen<strong>de</strong>t, muß <strong>de</strong>r voll qualifizierte Name <strong>in</strong><br />
Anwendungen benutzt wer<strong>de</strong>n.<br />
437
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
AbstractSequentialList, ArrayList und Vector.java.util.<br />
AbstractList implementiert bereits viele Metho<strong>de</strong>n für die bei<strong>de</strong>n Listen-<br />
Klassen 311 :<br />
abstract class AbstractList extends AbstractCollection implements List<br />
><br />
public void add(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Object element)<br />
// Optional: Fügt e<strong>in</strong> Objekt an <strong>de</strong>r spezifizierten stelle e<strong>in</strong><br />
public boolean add(Object o)<br />
// Optional: Fügt das Element am En<strong>de</strong> an<br />
public boolean addAll(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Collection c)<br />
// Optional: Fügt alle Elemente <strong>de</strong>r Collection e<strong>in</strong><br />
public void clear()<br />
// Optional: Löscht alle Elemente<br />
public boolean equals(Object o)<br />
// vergleicht die Liste mit <strong>de</strong>m Objekt<br />
public abstract Object get(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// liefert das Element an dieser Stelle<br />
<strong>in</strong>t hashCo<strong>de</strong>()<br />
// liefert HashCo<strong>de</strong> <strong>de</strong>r Liste<br />
<strong>in</strong>t <strong>in</strong><strong>de</strong>xOf(Object o)<br />
// liefert Position <strong>de</strong>s ersten Vorkommens für o o<strong>de</strong>r –1,<br />
// wenn das Element nicht existiert.<br />
Iterator iterator()<br />
// liefert <strong>de</strong>n Iterator. Überschreibt die Metho<strong>de</strong> AbstractCollection,<br />
// obwohl es auch listIterator() für die spezielle Liste gibt. Die Metho<strong>de</strong><br />
// ruft aber listIterator() auf und gibt e<strong>in</strong> ListIterator-Objekt zurück<br />
Object remove(<strong>in</strong>t <strong>in</strong><strong>de</strong>x)<br />
// löscht e<strong>in</strong> Element an Position <strong>in</strong><strong>de</strong>x.<br />
protected void removeRange(<strong>in</strong>t fromIn<strong>de</strong>x, <strong>in</strong>t toIn<strong>de</strong>x)<br />
// löscht Teil <strong>de</strong>r Liste von fromIn<strong>de</strong>x bis toIn<strong>de</strong>x. fromIn<strong>de</strong>x wird mitgelöscht,<br />
// toIn<strong>de</strong>x nicht.<br />
public Object set(<strong>in</strong>t <strong>in</strong><strong>de</strong>x, Object element)<br />
// Optional. Ersetzt das Element an <strong>de</strong>r Stelle <strong>in</strong><strong>de</strong>x mit element.<br />
public List subList(<strong>in</strong>t fromIn<strong>de</strong>x, <strong>in</strong>t toIn<strong>de</strong>x)<br />
// liefert Teil e<strong>in</strong>er Liste fromIn<strong>de</strong>x (e<strong>in</strong>schließlich) bis toIn<strong>de</strong>x (nicht mehr dabei)<br />
Abb.: Die abstrakte Klasse AbstractList<br />
AbstractSequentialList<br />
bereitet die Klasse L<strong>in</strong>kedList darauf vor, die Elemente <strong>in</strong> e<strong>in</strong>er Liste zu<br />
verwalten und nicht wie ArrayList <strong>in</strong> e<strong>in</strong>em <strong>in</strong>ternen Array.<br />
L<strong>in</strong>kedList<br />
realisiert die doppelt verkettete, l<strong>in</strong>eare Liste und implementiert List.<br />
ArrayList<br />
implementiert die Liste als Feld von Elementen und implementiert List. Da<br />
ArrayList e<strong>in</strong> Feld ist, ist <strong>de</strong>r Zugriff auf e<strong>in</strong> spezielles Element sehr schnell. E<strong>in</strong>e<br />
L<strong>in</strong>kedList muß aufwendiger durchsucht wer<strong>de</strong>n. Die verkettete Liste ist aber<br />
<strong>de</strong>utlich im Vorteil, wenn Elemente gelöscht o<strong>de</strong>r e<strong>in</strong>gefügt wer<strong>de</strong>n.<br />
311 Der Aufruf e<strong>in</strong>er optionalen Metho<strong>de</strong>, die von <strong>de</strong>r Subklasse nicht implementiert wird, führt zur<br />
UnsupportedOperationException.<br />
438
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
Collection<br />
><br />
List<br />
L<strong>in</strong>kedList ArrayList Vector<br />
> ><br />
public L<strong>in</strong>kedList();<br />
public ArrayList();<br />
public L<strong>in</strong>kedList(Collection collection); public ArrayList(Collection collection);<br />
public ArrayList(<strong>in</strong>t anfangsKapazitaet);<br />
> ><br />
public void addFirst(Object object); protected void removeRange<br />
public void addLast(Object object);<br />
(<strong>in</strong>t fromIn<strong>de</strong>x, <strong>in</strong>t toIn<strong>de</strong>x)<br />
public Object getFirst();<br />
// löscht Teil <strong>de</strong>r Liste von<br />
public Object getLast();<br />
// fromIn<strong>de</strong>x bis toIn<strong>de</strong>x. fromIn<strong>de</strong>x wird<br />
public Object removeFirst();<br />
// mitgelöscht, toIn<strong>de</strong>x nicht.<br />
public Object removeLast();<br />
Abb. L<strong>in</strong>kedList, ArrayList, Vector<br />
Das Interface ListIterator<br />
><br />
ListIterator<br />
public boolean hasPrevious();<br />
// bestimmt, ob es vor <strong>de</strong>r aktuellen Position e<strong>in</strong> weiteres Element gibt, <strong>de</strong>r Zugriff ist mit<br />
// previous möglich<br />
public boolean hasNext();<br />
public Object next();<br />
public Object previous();<br />
public <strong>in</strong>t nextIn<strong>de</strong>x();<br />
public <strong>in</strong>t previousIn<strong>de</strong>x();<br />
public void add(Object o);<br />
// E<strong>in</strong>fügen e<strong>in</strong>es neuen Elements an <strong>de</strong>r Stelle <strong>de</strong>r Liste, die unmittelbar vor <strong>de</strong>m nächsten<br />
// Element <strong>de</strong>s Iterators liegt<br />
public void set(Object o);<br />
// erlaubt, das durch <strong>de</strong>n letzten Aufruf von next() bzw. previous() beschaffene Element zu<br />
// ersetzen<br />
public void remove();<br />
Abb.: Das Interface ListIterator<br />
ListIterator ist e<strong>in</strong>e Erweiterung von Iterator. Die Schnittstelle fügt noch<br />
Metho<strong>de</strong>n h<strong>in</strong>zu, damit an aktueller Stelle auch Elemente e<strong>in</strong>gefügt wer<strong>de</strong>n können.<br />
Mit e<strong>in</strong>em ListIterator läßt sich rückwärts laufen und auf das vorgehen<strong>de</strong><br />
Element zugreifen.<br />
439
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.3 Behälterklassen <strong>de</strong>s Typs Set<br />
E<strong>in</strong> Set ist e<strong>in</strong>e Menge, <strong>in</strong> <strong>de</strong>r ke<strong>in</strong>e doppelten E<strong>in</strong>träge vorkommen können. Set hat<br />
die gleichen Metho<strong>de</strong>n wie Collection. Standard-Implementierung für Set s<strong>in</strong>d das<br />
unsortierte HashSet (Array mit verän<strong>de</strong>rlicher Größe) und das sortierte TreeSet<br />
(B<strong>in</strong>ärbaum).<br />
Bsp.<br />
import java.util.*;<br />
public class SetBeispiel<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args [])<br />
{<br />
Set set = new HashSet();<br />
set.add("Gerhard");<br />
set.add("Thomas");<br />
set.add("Michael");<br />
set.add("Peter");<br />
set.add("Christian");<br />
set.add("Valent<strong>in</strong>a");<br />
System.out.pr<strong>in</strong>tln(set);<br />
Set sortedSet = new TreeSet(set);<br />
System.out.pr<strong>in</strong>tln(sortedSet);<br />
}<br />
}<br />
440
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
Collection<br />
><br />
Set<br />
public boolean add(Object element);<br />
public boolean addAll(Collection collection);<br />
public void clear();<br />
public boolean equals(Object object);<br />
public boolean conta<strong>in</strong>s(Object element);<br />
public boolean conta<strong>in</strong>sAll(Collection collection);<br />
public <strong>in</strong>t hashCo<strong>de</strong>();<br />
public Iterator iterator();<br />
public boolean remove(Object element);<br />
public boolean removeAll(Collection collection);<br />
public boolean reta<strong>in</strong>All(Collection collection);<br />
public <strong>in</strong>t size();<br />
public Object[] toArray();<br />
public Object[] toArray(Object[] a);<br />
HashSet ><br />
SortedSet<br />
public HashSet();<br />
public HashSet(Collection collection);<br />
public HashSet(<strong>in</strong>t anfangskapazitaet);<br />
public HashSet(<strong>in</strong>t anfangskapazitaet,<br />
float la<strong>de</strong>faktor);<br />
public Object first();<br />
public Object last();<br />
public SortedSet headSet(Object toElement);<br />
public SortedSet subSet(Object fromElement,<br />
Object toElement);<br />
public SortedSet tailSet(Object fromElement);<br />
public Comparator comparator();<br />
TreeSet 312<br />
public TreeSet()<br />
public TreeSet(Collection collection);<br />
public TreeSet(Comparator vergleich);<br />
public TreeSet(SortedSet collection);<br />
Abb.:<br />
312 implementiert die sortierte Menge mit Hilfe <strong>de</strong>r Klasse TreeMap, verwen<strong>de</strong>t e<strong>in</strong>en Red-Black-Tree als<br />
Datenstruktur<br />
441
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Schnittstelle Set<br />
ist e<strong>in</strong>e im mathematischen S<strong>in</strong>ne <strong>de</strong>f<strong>in</strong>ierte Menge von Objekten. Die Reihenfolge<br />
wird durch das E<strong>in</strong>fügen festgelegt. Wie von mathematischen Mengen bekannt, darf<br />
e<strong>in</strong> Set ke<strong>in</strong>e doppelten Elemente enthalten. Beson<strong>de</strong>re Beachtung muß Objekten<br />
geschenkt wer<strong>de</strong>n, die ihren Wert nachträglich än<strong>de</strong>rn. Die kann e<strong>in</strong> Set nicht<br />
kontrollieren. E<strong>in</strong>e Menge kann sich nicht selbst als Element enthalten.<br />
Zwei Klassen ergeben sich aus Set: die abstrakte Klasse AbstractSet und die<br />
konkrete Klasse HashSet.<br />
Die Schnittstelle SortedSet<br />
erweitert Set so, daß Elemente sortiert ausgelesen wer<strong>de</strong>n können. Das<br />
Sortierkriterium wird durch die Hilfsklasse Comparator gesetzt.<br />
442
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.4 Behälterklassen <strong>de</strong>s Typs Map<br />
E<strong>in</strong> Map ist e<strong>in</strong>e Menge von Elementen, auf die über Schlüssel zugegriffen wird.<br />
Je<strong>de</strong>m Schlüssel (key) ist genau e<strong>in</strong> Wert (value) zugeordnet. Standard-<br />
Implementierungem s<strong>in</strong>d HashMap, HashTable und TreeMap.<br />
Interface Map, SortedMap und implemetieren<strong>de</strong> Klassen<br />
><br />
Collection<br />
><br />
Map<br />
public void clear();<br />
public boolean conta<strong>in</strong>sKey(Object key);<br />
public boolean conta<strong>in</strong>sValue(Object value);<br />
public Set entrySet();<br />
public Object get(Object key);<br />
public boolean isEmpty();<br />
public Set keySet();<br />
public Object remove(Object key);<br />
public <strong>in</strong>t size();<br />
public Collection values();<br />
HashMap ><br />
SortedMap<br />
public HashMap();<br />
public HashMap(Map collection);<br />
public HashMap(<strong>in</strong>t anfangskapazitaet);<br />
public HashMap(<strong>in</strong>t anfangskapazitaet,<br />
<strong>in</strong>t la<strong>de</strong>faktor);<br />
public Comparator comparator();<br />
public Object firstKey();<br />
public Object lastKey();<br />
public SortedMap headMap(Object toKey);<br />
public SortedMap subMap(Object fromKey,<br />
Object toKey);<br />
public SortedMap tailMap(Object fromKey);<br />
Hashtable<br />
TreeMap<br />
public TreeMap();<br />
public TreeMap(Map collection);<br />
public TreeMap(Comparator vergleich);<br />
public TreeMap(SortedMap collection);<br />
Abb.:<br />
Die Schnittstelle Map<br />
443
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
E<strong>in</strong>e Klasse, die Map implementiert, behan<strong>de</strong>lt e<strong>in</strong>en assoziativen Speicher. Dieser<br />
verb<strong>in</strong><strong>de</strong>t e<strong>in</strong>en Schlüssel mit e<strong>in</strong>em Wert. Die Klasse Hashtable erbt von Map.<br />
Map ist für die implementieren<strong>de</strong>n Klassen AbstractMap, HashMap, Hashtable,<br />
Ren<strong>de</strong>r<strong>in</strong>gH<strong>in</strong>ts, WeakHashMap und Attributes das, was die abstrakte Klasse<br />
Dictionary für die Klasse Hashtable ist.<br />
Die Schnittstelle SortedMap<br />
E<strong>in</strong>e Map kann mit Hilfe e<strong>in</strong>es Kriteriums sortiert wer<strong>de</strong>n und nennt sich dann<br />
SortedMap. SortedMap erweitert direkt Map. Das Sortierkriterium wird mit e<strong>in</strong>em<br />
speziellen Objekt, das sich Comparator nennt, gesetzt. Damit besitzt auch <strong>de</strong>r<br />
assoziative Speicher über e<strong>in</strong>en Iterator e<strong>in</strong>e Reihenfolge. Nur die konkrete Klasse<br />
TreeMap implementiert bisher e<strong>in</strong>e SortedMap.<br />
Die abstrakte Klasse AbstractMap<br />
implementiert die Schnittstelle Map.<br />
Die konkrete Klasse HashMap<br />
implementiert e<strong>in</strong>en assoziativen Speicher, erweitert die Klasse AbstractMap und<br />
implementiert die Schnittstelle Map.<br />
Die konkrete Klasse TreeMap<br />
Erweitert AbstractMap und implementiert SortedMap. E<strong>in</strong> Objekt von TreeMap hält<br />
Elemente <strong>in</strong> e<strong>in</strong>em Baum sortiert.<br />
444
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.5 Algorithmen<br />
Die Wahl e<strong>in</strong>er geeigneten Datenstruktur ist <strong>de</strong>r erste Schritt. Im zweiten Schritt<br />
müssen die Algorithmen implementiert wer<strong>de</strong>n. Die <strong>Java</strong> Bibliothek hilft mit e<strong>in</strong>igen<br />
Standardalgorithmen weiter. Dazu zählen Funktionen zum Sortieren und Suchen <strong>in</strong><br />
Conta<strong>in</strong>ern und das Füllen von Conta<strong>in</strong>ern. Zum flexiblen E<strong>in</strong>satz dieser Funktionen<br />
haben die <strong>Java</strong>-Entwickler die Klasse Collections bereitgestellt. Collections bietet<br />
Algorithmen statischer Funktionen an, die als Parameter e<strong>in</strong> Collection Objekt<br />
erwarten. Lei<strong>de</strong>r s<strong>in</strong>d viele Algorithmen nur auf List Objekte <strong>de</strong>f<strong>in</strong>iert, z.B.<br />
public static void shuffle(List list)<br />
// würfelt die Werte e<strong>in</strong>er Liste durche<strong>in</strong>an<strong>de</strong>r<br />
Bsp.<br />
import java.util.*;<br />
public class VectorShuffle<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Vector v = new Vector();<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
v.add(new Integer(i));<br />
Collections.shuffle(v);<br />
System.out.pr<strong>in</strong>tln(v);<br />
}<br />
}<br />
public static void shuffle(List list, Random rnd)<br />
// würfelt die werte <strong>de</strong>r Liste durche<strong>in</strong>an<strong>de</strong>r und benutzt dabei <strong>de</strong>n Random Generator rnd.<br />
Nur die Metho<strong>de</strong>n m<strong>in</strong>() und max() arbeiten auf allgeme<strong>in</strong>en Collection-Objekten.<br />
6.2.5.1 Datenmanipulation<br />
Daten umdrehen. Die Metho<strong>de</strong> reverse() dreht die Werte e<strong>in</strong>er Liste um. Die<br />
Laufzeit ist l<strong>in</strong>ear zu <strong>de</strong>r Anzahl <strong>de</strong>r Elemente.<br />
public static void reverse(List l)<br />
// dreht die Elemente <strong>in</strong> <strong>de</strong>r Liste um<br />
Listen füllen. Mit <strong>de</strong>r fill()-Metho<strong>de</strong> läßt sich e<strong>in</strong>e Liste <strong>in</strong> l<strong>in</strong>earer Zeit belegen.<br />
Nützlich ist dies, wenn e<strong>in</strong>e Liste mit Werten <strong>in</strong>itialisiert wer<strong>de</strong>n muß.<br />
public static void fill (List l, Object o)<br />
// füllt e<strong>in</strong>e Liste mit <strong>de</strong>m Element o<br />
Daten zwischen Listen kopieren. Die Metho<strong>de</strong> copy(List quelle, List ziel)<br />
kopiert alle Elemente von quelle <strong>in</strong> die Liste ziel und überschreibt dabei<br />
Elemente, die evtl. an dieser Stelle liegen.<br />
public static void copy(List quelle, List ziel)<br />
// kopiert Elemente von quelle nach ziel. Ist ziel zu kle<strong>in</strong>, gibt es e<strong>in</strong>e In<strong>de</strong>xOutOfBoundsException<br />
445
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.5.2 Größter und kle<strong>in</strong>ster Wert e<strong>in</strong>er Collection<br />
Die Metho<strong>de</strong>n m<strong>in</strong>() und max() suchen das größte und kle<strong>in</strong>ste Element e<strong>in</strong>er<br />
Collection. Die Laufzeit ist l<strong>in</strong>ear zur Größe <strong>de</strong>r Collection. Die Metho<strong>de</strong>n machen<br />
ke<strong>in</strong>en Unterschied, ob die Liste schon sortiert ist o<strong>de</strong>r nicht.<br />
public static Object m<strong>in</strong>(Collection c)<br />
//<br />
public static Object max(Collection c)<br />
/* Falls m<strong>in</strong>() bzw. max() auf e<strong>in</strong> Collection-Objekt angewen<strong>de</strong>t wird, erfolgt die Bestimmung <strong>de</strong>s<br />
M<strong>in</strong>imums bzw. Maximums nach <strong>de</strong>r Metho<strong>de</strong> compareTo <strong>de</strong>r Comparable Schnittstelle. Byte,<br />
Character, Double, File, Float, Long, Short, Str<strong>in</strong>g, Integer, BigInteger, ObjectStreamField, Date und<br />
Calendar haben diese Schnittstelle implementiert. Lassen sich die Daten nicht vergleichen, dann gibt<br />
es e<strong>in</strong>e ClassCastException<br />
*/<br />
public static Object m<strong>in</strong>(Collection c, Comparator vergl)<br />
//<br />
public static Object max(Collection c, Comparator vergl)<br />
6.2.5.3 Sortieren<br />
Die Collection Klasse bietet zwei sort() Metho<strong>de</strong>n an, die die Elemente e<strong>in</strong>er Liste<br />
stabil 313 sortieren. Die Metho<strong>de</strong> sort() sortiert die Elemente <strong>in</strong> ihrer natürlichen<br />
Ordnung, z.B.:<br />
- Zahlen nach <strong>de</strong>r Größe (13 < 40)<br />
- Zeichenketten alphanumerisch (Juergen < Robert < Ulli)<br />
E<strong>in</strong>e zweite überla<strong>de</strong>ne Form von sort() arbeitet mit e<strong>in</strong>em speziellen Comparator<br />
Objekt, das zwei Objekte mit <strong>de</strong>r Metho<strong>de</strong> compare() vergleicht.<br />
public static void sort(List liste)<br />
// sortiert die Liste<br />
public static void sort(List liste, Comparator c)<br />
// sortiert die Liste mit <strong>de</strong>m Comparator c<br />
Die Sortierfunktion arbeitet nur mit List-Objekten. „sort()“ gibt es aber auch <strong>in</strong> <strong>de</strong>r<br />
Klasse Arrays.<br />
Bsp.: Das folgen<strong>de</strong> Programm sortiert e<strong>in</strong>e Reihe von Zeichenketten <strong>in</strong> aufsteigen<strong>de</strong>r<br />
Folge. Es nutzt die Metho<strong>de</strong> Arrays.asList() zur Konstruktion e<strong>in</strong>er Liste aus<br />
e<strong>in</strong>em Array 314 .<br />
import java.util.*;<br />
public class CollectionsSortDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g feld[] =<br />
{ "Reg<strong>in</strong>a","Angela","Michaela","Maria","Josepha",<br />
"Amalia","Vera","Valent<strong>in</strong>a","Daniela","Saida",<br />
313 Stabile Sortieralgorithmen beachten die Reihenfolge von gleichen Elementen, z.B. beim Sortieren von<br />
Nachrichten <strong>in</strong> e<strong>in</strong>em Email-Programm, zuerst nach <strong>de</strong>m Datum und anschließend nach <strong>de</strong>m Sen<strong>de</strong>r, soll die<br />
Liste <strong>in</strong>nerhalb <strong>de</strong>s Datum sortiert bleiben.<br />
314 Lei<strong>de</strong>r gibt es ke<strong>in</strong>en Konstruktor für ArrayList, <strong>de</strong>r e<strong>in</strong>en Array mit Zeichenketten zuläßt.<br />
446
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
"L<strong>in</strong>da","Elisa"<br />
};<br />
List l = Arrays.asList(feld);<br />
Collections.sort(l);<br />
System.out.pr<strong>in</strong>tln(l);<br />
}<br />
}<br />
Die <strong>Java</strong> Bibliothek bietet nicht viel zur Umwandlung von Fel<strong>de</strong>rn („Array“) <strong>in</strong><br />
dynamische Datenstrukturen. E<strong>in</strong>e Ausnahme bil<strong>de</strong>t die Hilfsklasse Arrays, die die<br />
Metho<strong>de</strong> asList() anbietet. Die Behälterklassen ArrayList und L<strong>in</strong>kedList wer<strong>de</strong>n<br />
über asList() nicht unterstützt, d.h. Über asList() wird zwar e<strong>in</strong>e <strong>in</strong>terne Klasse<br />
ArrayList benutzt, die e<strong>in</strong>e Erweiterung von AbstractList ist, aber nur das<br />
notwendigste implementiert.<br />
Sortieralgorithmus. Es han<strong>de</strong>lt sich um e<strong>in</strong>en optimierten „Merge-Sort“. Se<strong>in</strong>e<br />
Laufzeit beträgt N ⋅ log(N)<br />
.<br />
Die sort() Metho<strong>de</strong> arbeitet mit <strong>de</strong>r toArray() Funktion <strong>de</strong>r Klasse List. Damit<br />
wer<strong>de</strong>n die Elemente <strong>de</strong>r Liste <strong>in</strong> e<strong>in</strong>em Feld (Array) abgelegt. Schließlich wird die<br />
sort() Metho<strong>de</strong> <strong>de</strong>r Klasse Arrays genutzt und mit e<strong>in</strong>em ListIterator wie<strong>de</strong>r<br />
<strong>in</strong> die Liste e<strong>in</strong>gefügt.<br />
Daten <strong>in</strong> umgekehrter Reihenfolge sortieren. Das wird über e<strong>in</strong> spezielles<br />
Comparator-Objekt geregelt, das von Collections über die Metho<strong>de</strong><br />
reverseOr<strong>de</strong>r() angefor<strong>de</strong>rt wer<strong>de</strong>n kann.<br />
Bsp.:<br />
import java.util.*;<br />
public class CollectionsReverseSortDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Vector v = new Vector();<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
{<br />
v.add(new Double(Math.random()));<br />
}<br />
Comparator comparator = Collections.reverseOr<strong>de</strong>r();<br />
Collections.sort(v,comparator);<br />
System.out.pr<strong>in</strong>tln(v);<br />
}<br />
}<br />
E<strong>in</strong>e an<strong>de</strong>re Möglichkeit für umgekehrt sortierte Listen besteht dar<strong>in</strong>, erst die Liste<br />
mit sort() zu sortieren und anschließend mit reverse() umzudrehen.<br />
447
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.5.4 Suchen von Elementen<br />
Die Behälterklassen enthalten die Metho<strong>de</strong> conta<strong>in</strong>s(), mit <strong>de</strong>r sich Elemente<br />
suchen lassen. Für sortierte Listen gibt es e<strong>in</strong>e wesentlich schnellere Suchmetho<strong>de</strong>:<br />
b<strong>in</strong>arySearch():<br />
public static <strong>in</strong>t b<strong>in</strong>arySearch(List liste, Object key)<br />
// sucht e<strong>in</strong> Element <strong>in</strong> <strong>de</strong>r Liste. Gibt die Position zurück o<strong>de</strong>r e<strong>in</strong> Wert kle<strong>in</strong>er 0,<br />
// falls key nicht <strong>in</strong> <strong>de</strong>r Liste ist.<br />
public static <strong>in</strong>t b<strong>in</strong>arySearch(List liste, Object key, Comparator c)<br />
// Sucht e<strong>in</strong> Element mit Hilfe <strong>de</strong>s Comparator Objekts <strong>in</strong> <strong>de</strong>r Liste. Gibt die Position zurück o<strong>de</strong>r<br />
// e<strong>in</strong>en Wert kle<strong>in</strong>er als 0, falls <strong>de</strong>r key nicht <strong>in</strong> <strong>de</strong>r Liste ist.<br />
Bsp.: Das folgen<strong>de</strong> Programm sortiert (zufällig ermittelte) Daten und bestimmt Daten<br />
<strong>in</strong> Listen mit Hilfe <strong>de</strong>r b<strong>in</strong>ären Suche.<br />
import java.util.*;<br />
public class ListSort<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
f<strong>in</strong>al <strong>in</strong>t GR = 20;<br />
// Verwen<strong>de</strong>n e<strong>in</strong>er natuerliche Ordnung<br />
List a = new ArrayList();<br />
for (<strong>in</strong>t i = 0; i < GR; i++)<br />
a.add(new VglClass((<strong>in</strong>t)(Math.random() * 100)));<br />
Collections.sort(a);<br />
Object f<strong>in</strong><strong>de</strong> = a.get(GR / 2);<br />
<strong>in</strong>t ort = Collections.b<strong>in</strong>arySearch(a,f<strong>in</strong><strong>de</strong>);<br />
System.out.pr<strong>in</strong>tln("Ort von " + f<strong>in</strong><strong>de</strong> + " = " + ort);<br />
// Verwen<strong>de</strong>n e<strong>in</strong>es Comparator<br />
List b = new ArrayList();<br />
// Bestimmt zufaellig Zeichenketten <strong>de</strong>r Laenge 4<br />
for (<strong>in</strong>t i = 0; i < GR; i++)<br />
b.add(Fel<strong>de</strong>r.randStr<strong>in</strong>g(4));<br />
// Instanz fuer <strong>de</strong>n Comparator<br />
AlphaVgl av = new AlphaVgl();<br />
// Sortieren<br />
Collections.sort(b,av);<br />
// B<strong>in</strong>aere Suche<br />
f<strong>in</strong><strong>de</strong> = b.get(GR / 2);<br />
ort = Collections.b<strong>in</strong>arySearch(b,f<strong>in</strong><strong>de</strong>,av);<br />
System.out.pr<strong>in</strong>tln(b);<br />
System.out.pr<strong>in</strong>tln("Ort von " + f<strong>in</strong><strong>de</strong> + " = " + ort);<br />
}<br />
}<br />
448
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.2.6 Generics<br />
6.2.6.1 Sammlungsklassen<br />
Mit <strong>Java</strong> 1.5 wur<strong>de</strong> durch E<strong>in</strong>führung <strong>de</strong>r sog. Generics das Feld <strong>de</strong>r Templatebasierten<br />
Metaprogrammierung eröffnet. Das s<strong>in</strong>nvollste E<strong>in</strong>satzfeld dieses<br />
Mechanismus bil<strong>de</strong>t die Anwendung auf die vorhan<strong>de</strong>nen Klassen <strong>de</strong>r Collection API<br />
zur Realisierung typsicherer Objektsammlungen.<br />
Allgeme<strong>in</strong>e Syntax: Nachstellung <strong>de</strong>s durch spitze W<strong>in</strong>kellammern e<strong>in</strong>geschlossenen<br />
Typnamens nach <strong>de</strong>m Namen <strong>de</strong>r so typisierten Sammlung, z.B.<br />
Def<strong>in</strong>ition e<strong>in</strong>er Liste, die ausschließlich Objekte <strong>de</strong>s Typs Str<strong>in</strong>g enthält: List<br />
Bsp. 315 :<br />
import java.util.*;<br />
import java.util.List;<br />
class ListTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
List xs = new ArrayList();<br />
xs.add("Shakespeare");<br />
xs.add("Schiller");<br />
xs.add("Goethe");<br />
xs.add("Brecht");<br />
xs.add("Thomas Mann");<br />
Str<strong>in</strong>g x = xs.get(3);<br />
System.out.pr<strong>in</strong>tln(xs);<br />
}<br />
}<br />
Test:<br />
Aus Kompatiblitätsgrün<strong>de</strong>n mit bestehen<strong>de</strong>m Co<strong>de</strong> können generische Klassen auch<br />
weiter h<strong>in</strong> ohne konkrete Angabe <strong>de</strong>s Typparameters benutzt wer<strong>de</strong>n. Während <strong>de</strong>r<br />
Übersetzung wird <strong>in</strong> diesen Fällen e<strong>in</strong>e Warnung ausgegeben.<br />
import java.util.*;<br />
import java.util.List;<br />
class WarnTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
List xs = new ArrayList();<br />
xs.add("Shakespeare");<br />
xs.add("Schiller");<br />
xs.add("Goethe");<br />
315 pr66100<br />
449
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
xs.add("Brecht");<br />
xs.add("Thomas Mann");<br />
System.out.pr<strong>in</strong>tln(xs);<br />
}<br />
}<br />
Konventionsgemäß erlaubt <strong>Java</strong> ausschließlich die Festlegung von Klassen als<br />
Inhaltstypen von Objektsammlungen. Primitivtypen s<strong>in</strong>d von <strong>de</strong>r Verwendung<br />
ausgeschlossen.<br />
6.2.6.2 Generische Metho<strong>de</strong>n<br />
Generische Typen s<strong>in</strong>d nicht an e<strong>in</strong>en objektorientierten Kontext gebun<strong>de</strong>n. In <strong>Java</strong><br />
verlässt man <strong>de</strong>n objektorientierten Kontext <strong>in</strong> statischen Metho<strong>de</strong>n. Statische<br />
Metho<strong>de</strong>n s<strong>in</strong>d nicht an e<strong>in</strong> Objekt gebun<strong>de</strong>n und lassen sich generisch <strong>in</strong> <strong>Java</strong><br />
<strong>de</strong>f<strong>in</strong>ieren. Hierzu ist vor <strong>de</strong>r Metho<strong>de</strong>nsignatur <strong>in</strong> spitzen Klammern e<strong>in</strong>e Liste <strong>de</strong>r<br />
für die statischen Metho<strong>de</strong>n benutzten Typvariablen anzugeben.<br />
Bsp.: Generische Metho<strong>de</strong>n <strong>de</strong>r Klasse TestGenericB<strong>in</strong>aerBaumKnoten<br />
Die folgen<strong>de</strong> Darstellung zeigt die Def<strong>in</strong>ition e<strong>in</strong>er generischen Klasse für Knoten <strong>in</strong> e<strong>in</strong>em b<strong>in</strong>ären<br />
Suchbaums mit e<strong>in</strong>er Typvariablen, die für alle Subtypen <strong>de</strong>r Schnittstelle Comparable steht.<br />
// Elementarer Knoten e<strong>in</strong>es b<strong>in</strong>aeren Baums, <strong>de</strong>r nicht ausgeglichen ist<br />
class B<strong>in</strong>aerBaumknoten<br />
{<br />
// Instanzvariable<br />
protected B<strong>in</strong>aerBaumknoten l<strong>in</strong>ks;<br />
// l<strong>in</strong>ker Teilbaum<br />
protected B<strong>in</strong>aerBaumknoten rechts; // rechter Teilbaum<br />
public T daten; // Daten<strong>in</strong>halt <strong>de</strong>r Knoten<br />
// Konstruktor<br />
public B<strong>in</strong>aerBaumknoten(T datenElement)<br />
{<br />
this(datenElement, null, null );<br />
}<br />
public B<strong>in</strong>aerBaumknoten(T datenElement,<br />
B<strong>in</strong>aerBaumknoten l,<br />
B<strong>in</strong>aerBaumknoten r)<br />
{<br />
daten = datenElement;<br />
l<strong>in</strong>ks = l;<br />
rechts = r;<br />
}<br />
public void <strong>in</strong>sert (T x)<br />
{<br />
if (x.compareTo(daten) > 0) // dann rechts<br />
{<br />
if (rechts == null) rechts = new B<strong>in</strong>aerBaumknoten(x);<br />
else rechts.<strong>in</strong>sert(x);<br />
}<br />
else // sonst l<strong>in</strong>ks<br />
{<br />
if (l<strong>in</strong>ks == null) l<strong>in</strong>ks = new B<strong>in</strong>aerBaumknoten (x);<br />
else l<strong>in</strong>ks.<strong>in</strong>sert(x);<br />
}<br />
}<br />
public B<strong>in</strong>aerBaumknoten getL<strong>in</strong>ks()<br />
{<br />
return l<strong>in</strong>ks;<br />
450
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
public B<strong>in</strong>aerBaumknoten getRechts()<br />
{<br />
return rechts;<br />
}<br />
}<br />
Die Klasse TestGenericB<strong>in</strong>aerBaumKnoten erzeugt e<strong>in</strong>en b<strong>in</strong>ären Baum mit Hilfe <strong>de</strong>r<br />
vorliegen<strong>de</strong>n Klasse B<strong>in</strong>aerBaumknoten. Die Knoten <strong>de</strong>s b<strong>in</strong>ären Baums wer<strong>de</strong>n über zahlreiche<br />
generische Metho<strong>de</strong>n durchlaufen.<br />
public class TestGenericB<strong>in</strong>aerBaumKnoten<br />
{<br />
public static void ma<strong>in</strong> (Str<strong>in</strong>g args[])<br />
{<br />
B<strong>in</strong>aerBaumknoten baum = null;<br />
/*<br />
for (<strong>in</strong>t i = 0; i < 20; i++) // 20 Zusfallsstr<strong>in</strong>gs speichern<br />
{<br />
Str<strong>in</strong>g s = "Zufallszahl " + (<strong>in</strong>t)(Math.random() * 100);<br />
if (baum == null) baum = new B<strong>in</strong>aerBaumknoten(s);<br />
}<br />
pr<strong>in</strong>t(baum); // Sortiert wie<strong>de</strong>r ausdrucken<br />
*/<br />
for (<strong>in</strong>t i = 0; i < 10; i++)<br />
{<br />
// Erzeuge e<strong>in</strong>e Zahl zwischen 0 und 100<br />
Integer r = new Integer((<strong>in</strong>t)(Math.random()*100));<br />
if (baum == null) baum = new B<strong>in</strong>aerBaumknoten(r);<br />
else baum.<strong>in</strong>sert(r);<br />
}<br />
System.out.pr<strong>in</strong>tln("Inor<strong>de</strong>r-Durchlauf");<br />
pr<strong>in</strong>t(baum);<br />
System.out.pr<strong>in</strong>tln();<br />
System.out.pr<strong>in</strong>tln("Baumdarstellung um 90 Grad versetzt");<br />
ausgB<strong>in</strong>aerBaum(baum,0);<br />
System.out.pr<strong>in</strong>t("Kle<strong>in</strong>ster Wert: ");<br />
System.out.pr<strong>in</strong>t(((Integer)(f<strong>in</strong><strong>de</strong>M<strong>in</strong>(baum))).<strong>in</strong>tValue());<br />
System.out.pr<strong>in</strong>tln();<br />
System.out.pr<strong>in</strong>t("Groesster Wert: ");<br />
System.out.pr<strong>in</strong>t(((Integer)(f<strong>in</strong><strong>de</strong>Max(baum))).<strong>in</strong>tValue());<br />
System.out.pr<strong>in</strong>tln();<br />
}<br />
// Generische Metho<strong>de</strong>n<br />
public static <br />
void pr<strong>in</strong>t (B<strong>in</strong>aerBaumknoten
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
public static T f<strong>in</strong><strong>de</strong>M<strong>in</strong>(B<strong>in</strong>aerBaumknoten b)<br />
{<br />
return datenZugriff( f<strong>in</strong>dM<strong>in</strong>(b) );<br />
}<br />
public static T f<strong>in</strong><strong>de</strong>Max(B<strong>in</strong>aerBaumknoten b)<br />
{<br />
return datenZugriff( f<strong>in</strong>dMax(b) );<br />
}<br />
public static T datenZugriff(B<strong>in</strong>aerBaumknoten b)<br />
{<br />
return b == null ? null : b.daten;<br />
}<br />
public static <br />
B<strong>in</strong>aerBaumknoten f<strong>in</strong>dM<strong>in</strong>(B<strong>in</strong>aerBaumknoten b)<br />
{<br />
if (b == null) return null;<br />
else if (b.getL<strong>in</strong>ks() == null) return b;<br />
return f<strong>in</strong>dM<strong>in</strong>(b.getL<strong>in</strong>ks());<br />
}<br />
public static <br />
B<strong>in</strong>aerBaumknoten f<strong>in</strong>dMax(B<strong>in</strong>aerBaumknoten b)<br />
{<br />
if (b != null)<br />
while (b.getRechts() != null)<br />
b = b.getRechts();<br />
return b;<br />
}<br />
}<br />
6.2.6.3 Iteration<br />
In typischer Weise wird <strong>in</strong> e<strong>in</strong>em Programm über die Elemente e<strong>in</strong>es Sammlungstyps<br />
iteriert o<strong>de</strong>r über alle Elemente e<strong>in</strong>es Array (Reihung). <strong>Java</strong> kennt dafür<br />
verschie<strong>de</strong>nene Schleifenkonstrukte. Lei<strong>de</strong>r kannte <strong>Java</strong> bis zur Version 1.4 ke<strong>in</strong><br />
eigenes Schleifenkonstrukt, das bequem e<strong>in</strong>e Iteration über die Elemente e<strong>in</strong>er<br />
Sammlung (Collection) ausdrücken konnte.<br />
Bsp. 316 :<br />
import java.util.List;<br />
import java.util.ArrayList;<br />
import java.util.Iterator;<br />
class AlteIteration<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Str<strong>in</strong>g [] ar =<br />
{ "Brecht", "Schiller", "Goethe", "Shakespeare", "Thomas Mann" };<br />
List xs = new ArrayList();<br />
for (<strong>in</strong>t i = 0;i < ar.length; i++)<br />
{<br />
f<strong>in</strong>al Str<strong>in</strong>g s = ar[i];<br />
xs.add(s);<br />
}<br />
for (Iterator it = xs.iterator(); it.hasNext();)<br />
{<br />
f<strong>in</strong>al Str<strong>in</strong>g s = (Str<strong>in</strong>g) it.next();<br />
316 pr66100<br />
452
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
}<br />
System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
Mit <strong>Java</strong> 1.5 gibt es endlich die Möglichkeit, direkt zu bestimmen: "Mache für alle<br />
Elemente im nachfolgen<strong>de</strong>n Sammlungsobjekt etwas ...". Vorgesehen ist dafür e<strong>in</strong>e<br />
Kontrollstrukturanweisung 317 von folgen<strong>de</strong>r Form:<br />
for (Type i<strong>de</strong>ntifier expr) { body }<br />
Dieser Konstrukt wird so gelesen: "Für je<strong>de</strong>s i<strong>de</strong>ntifier <strong>de</strong>s Typs Type <strong>in</strong> expr<br />
führe aus". Die Kontrollstrukturanweisung gilt für alle Objekte vom Typ <strong>de</strong>r<br />
Schnittstelle Iterable, wozu auf je<strong>de</strong>m Fall alle Datenstrukturen (e<strong>in</strong>schl. Array)<br />
zählen.<br />
Bsp. 318 :<br />
import java.util.List;<br />
import java.util.ArrayList;<br />
class NeueIteration<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g [] args)<br />
{<br />
Str<strong>in</strong>g [] ar =<br />
{ "Brecht", "Schiller", "Goethe", "Shakespeare", "Thomas Mann" };<br />
List xs = new ArrayList();<br />
for (Str<strong>in</strong>g s:ar) xs.add(s);<br />
for (Str<strong>in</strong>g s:xs) System.out.pr<strong>in</strong>tln(s.toUpperCase());<br />
}<br />
}<br />
Def<strong>in</strong>ition <strong>de</strong>r Schnittstelle Iterable: public <strong>in</strong>terface Iterable<br />
{ SimpleIterator iterator();}<br />
Iterable schreibt die Existenz e<strong>in</strong>er Funktion iterator() vor, die e<strong>in</strong>en<br />
java.lang.SimpleIterator liefert. SimpleIterator ist e<strong>in</strong> Iterator 319 ohne<br />
remove():<br />
public <strong>in</strong>terface SimpleIterator<br />
{<br />
boolean hasNext();<br />
T next();<br />
}<br />
Der konkrete SimpleIterator muß nur die Metho<strong>de</strong>n hasNext() und next()<br />
implementieren, um das nächste Element <strong>in</strong> <strong>de</strong>r Aufzählung zu beschaffen und das<br />
En<strong>de</strong> anzuzeigen.<br />
java.util.Iterator() implementiert seit <strong>Java</strong> 1.5 <strong>de</strong>n SimpleIterator:<br />
public <strong>in</strong>terface Iterator extends SimpleIterator<br />
{<br />
boolean hasNext();<br />
E next();<br />
void remove();<br />
}<br />
317 vgl. 2.4.7<br />
318 pr66100<br />
319 vgl. 6.2.1<br />
453
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Das bekannte Programmierer-Idiom<br />
for (Iterator i = c.iterator(); i.hasNext)<br />
{<br />
Typ o = (Typ) i.next();<br />
}<br />
kann durch das erweiterte for erfolgreich abgekürzt wer<strong>de</strong>n:<br />
for (i : c)<br />
{<br />
Typ o = (Typ) i;<br />
}<br />
Bsp. 320 :<br />
import java.util.Iterator;<br />
import java.util.Str<strong>in</strong>gTokenizer;<br />
class WordIterable implements Iterable, Iterator<br />
{<br />
private Str<strong>in</strong>gTokenizer st;<br />
public WordIterable( Str<strong>in</strong>g s )<br />
{<br />
st = new Str<strong>in</strong>gTokenizer( s );<br />
}<br />
// Metho<strong>de</strong> vom Iterable<br />
public Iterator iterator()<br />
{<br />
return this;<br />
}<br />
// Metho<strong>de</strong>n vom Iterator<br />
public boolean hasNext()<br />
{<br />
return st.hasMoreTokens();<br />
}<br />
public Object next()<br />
{<br />
return st.nextToken();<br />
}<br />
public void remove() { }<br />
}<br />
public class WordIterableDemo<br />
{<br />
public static void ma<strong>in</strong>( Str<strong>in</strong>g args[] )<br />
{<br />
Str<strong>in</strong>g s =<br />
"Am Anfang war das Wort - am En<strong>de</strong> die Phrase. (Stanislaw Jerzy Lec)";<br />
for ( Object word : new WordIterable(s) )<br />
System.out.pr<strong>in</strong>tln( word );<br />
}<br />
}<br />
320 pr66100<br />
454
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.3 Die Klasse Str<strong>in</strong>gTokenizer<br />
Die Str<strong>in</strong>gTokenizer-Klasse unterstützt das Aufteilen e<strong>in</strong>es Str<strong>in</strong>gs <strong>in</strong> Teilworte bzw.<br />
Zeichen, sog. Tokens. Tokens wer<strong>de</strong>n mit Hilfe von Trennzeichen erkannt, die e<strong>in</strong><br />
Token vom an<strong>de</strong>ren trennen. E<strong>in</strong> Token ist e<strong>in</strong>e Zeichenkette, <strong>in</strong> <strong>de</strong>r ke<strong>in</strong>e<br />
Trennzeichen vorkommen. In <strong>de</strong>r Regel wer<strong>de</strong>n Whitespaces 321 als Trennzeichen<br />
verwen<strong>de</strong>t. Der Str<strong>in</strong>gTokenizer ist nicht an bestimmte Trennzeichen gebun<strong>de</strong>n, sie<br />
können vielmehr frei gewählt wer<strong>de</strong>n. Nur <strong>in</strong> <strong>de</strong>r Vore<strong>in</strong>stellung s<strong>in</strong>d Tabulator,<br />
Leerzeichen und Zeilentrenner die Delimiter.<br />
Konstruktor: public Str<strong>in</strong>gTokenizer(Str<strong>in</strong>g str)<br />
E<strong>in</strong> Str<strong>in</strong>gTokenizer mit Whitespaces als Trennzeichen wird erzeugt. Der zu<br />
untersuchen<strong>de</strong> Str<strong>in</strong>g ist str. Sollen an<strong>de</strong>re Zeichen als Trennzeichen angegeben<br />
wer<strong>de</strong>n, so müssen diese ebenfalls an <strong>de</strong>n Konstruktor übergeben wer<strong>de</strong>n:<br />
public Str<strong>in</strong>gTokenizer(Str<strong>in</strong>g str, Str<strong>in</strong>g <strong>de</strong>limiters)<br />
Metho<strong>de</strong>n:<br />
public Str<strong>in</strong>g nextToken() throws NoSuchElementException<br />
gibt das jeweils nächste Token an<br />
public boolean hasMoreTokens()<br />
gibt Auskunft darüber, ob es noch weitere Tokens gibt.<br />
public <strong>in</strong>t countTokens()<br />
gibt Auskunft darüber, wie viele Tokens <strong>in</strong> e<strong>in</strong>em Str<strong>in</strong>g vorhan<strong>de</strong>n s<strong>in</strong>d.<br />
public Str<strong>in</strong>g nextToken(Str<strong>in</strong>g neueDelimiter)<br />
bewirkt nach e<strong>in</strong>em Aufruf die Verän<strong>de</strong>rung <strong>de</strong>r Trennzeichen.<br />
Das Enumerations-Interface ist <strong>in</strong> die Str<strong>in</strong>gTokenizer-Klasse implementiert:<br />
public boolean hasMoreElements()<br />
{<br />
return hasMoreTokens();<br />
}<br />
public Object nextElement()<br />
{<br />
return nextToken();<br />
}<br />
Bsp.: Ausgabe <strong>de</strong>r Worte e<strong>in</strong>es Satzes 322<br />
import java.util.Str<strong>in</strong>gTokenizer;<br />
import java.io.*;<br />
public class Str<strong>in</strong>gTokenizerTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args)<br />
{<br />
System.out.pr<strong>in</strong>tln("\nStr<strong>in</strong>gTokenizerTest\n");<br />
System.out.pr<strong>in</strong>tln("Gib e<strong>in</strong>ige Saetze fuer <strong>de</strong>n Test an.");<br />
System.out.pr<strong>in</strong>tln("Term<strong>in</strong>iere ueber e<strong>in</strong>e leere Zeile");<br />
boolean moreInput;<br />
do {<br />
System.out.pr<strong>in</strong>t("> ");<br />
Str<strong>in</strong>g e<strong>in</strong>gabeZeile = null;<br />
BufferedRea<strong>de</strong>r e<strong>in</strong>gabe = null;<br />
e<strong>in</strong>gabe = new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r(System.<strong>in</strong>));<br />
try {<br />
321 Zu <strong>de</strong>n Whitespaces gehören Leerzeichen, Tabulator, Zeilenvorschub und Zeilenumbruch. Wird beim<br />
Erzeugen e<strong>in</strong>es Tokenizer ke<strong>in</strong>e Trennzeichen-Zeichenkette angegeben, so wer<strong>de</strong>n Whitespaces als<br />
Trennzeichen angenommen.<br />
322 vgl. pr66100<br />
455
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
}<br />
e<strong>in</strong>gabeZeile =e<strong>in</strong>gabe.readL<strong>in</strong>e();<br />
}<br />
catch(IOException e) { System.out.pr<strong>in</strong>tln(e); }<br />
if (e<strong>in</strong>gabeZeile.equals("")) break;<br />
Str<strong>in</strong>gTokenizer st = new Str<strong>in</strong>gTokenizer(e<strong>in</strong>gabeZeile);<br />
if (st.hasMoreTokens())<br />
{<br />
moreInput = true;<br />
Str<strong>in</strong>g wort = st.nextToken();<br />
System.out.pr<strong>in</strong>t(wort);<br />
while (st.hasMoreTokens())<br />
{<br />
System.out.pr<strong>in</strong>t(" / ");<br />
System.out.pr<strong>in</strong>t(st.nextToken());<br />
}<br />
System.out.pr<strong>in</strong>tln();<br />
}<br />
else { moreInput = false; }<br />
} while (moreInput);<br />
6.4 Die Klasse Random<br />
Konstruktoren<br />
Random()<br />
// Erzeugt e<strong>in</strong>en neuen Zufallszahlengenerator. Der Seed 323 wird auf die aktuelle Zeit gesetzt.<br />
Random(long seed)<br />
// Erzeugt e<strong>in</strong>en neuen Zufallszahlengenerator und benutzt <strong>de</strong>n Parameter als Seed.<br />
Metho<strong>de</strong>n<br />
public void setSeed(long seed)<br />
// setzt <strong>de</strong>n Zufallswert neu<br />
Die Random-Klasse kann Zufallszahlen <strong>in</strong> vier verschie<strong>de</strong>nen Datentypen erzeugen:<br />
public <strong>in</strong>t nextInt()<br />
// liefert die nächste Zufallszahl<br />
public long nextLong()<br />
// liefert die nächste Zufallszahö<br />
public float nextFloat()<br />
// liefert die nächste Zufallszahl zwischen 0.0 und 1.0<br />
public double nextDouble()<br />
erzeugt e<strong>in</strong>e Zufallszahl im double-Format zwischen 0.0 und 1.0 324 .<br />
323 Startwert für je<strong>de</strong> Zufallszahl ist e<strong>in</strong> 48 Bit Seed. Das Wort „Seed“ kommt vom englischen Wort für Samen<br />
und <strong>de</strong>utet an, daß es bei <strong>de</strong>r Generierung von Zufalsszahlen wie bei Pflanzen e<strong>in</strong>en Samen gibt, <strong>de</strong>r zu<br />
Nachkommen führt. Aus diesem Startwert ermitteln sich anschließend die an<strong>de</strong>ren Zahlen durch l<strong>in</strong>eare<br />
Kongruenzen. Dadurch s<strong>in</strong>d die Zahlen nicht wirklich zufällig, sie gehorchen e<strong>in</strong>em mathematischen Verfahren<br />
324 wird von Math.random() verwen<strong>de</strong>t.<br />
456
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.5 Datumsberechnungen<br />
6.5.1 Die Klassen Date, Calendar, GregorianCalendar<br />
Die Klasse Date<br />
Die Date-Klasse repräsentiert e<strong>in</strong> bestimmtes Datum bzw. e<strong>in</strong>en bestimmten<br />
Zeitpunkt. Ausgangspunkt ist <strong>de</strong>r 1. Januar 1970 0:00 h Greenwich-Zeit.<br />
Date<br />
><br />
public Date()<br />
// erzeugt e<strong>in</strong>e Datums-Angabe und <strong>in</strong>itialisiert es mit <strong>de</strong>r Zeit, die bei <strong>de</strong>r Erzeugung gelesen<br />
// wur<strong>de</strong><br />
public Date(long d)<br />
// erzeugt e<strong>in</strong> Datums-Objekt und <strong>in</strong>itialisiertes mit <strong>de</strong>r angegebenen Anzahl von Millisekun<strong>de</strong>n<br />
// seit <strong>de</strong>m 1. Januar 1970, 00:00:00 GMT<br />
><br />
public long getTime()<br />
// liefert die Anzahl <strong>de</strong>r Millisekun<strong>de</strong>n seit <strong>de</strong>m 1. Januar 1970, 00:00:00 GMT zurück<br />
public void setTime(long t)<br />
// setzt die Anzahl Millisekun<strong>de</strong>n <strong>de</strong>s Datums-Objekts neu. Die akuelle Zeit kann über<br />
// today.setTime(new java.util.Date()) gesetzt wer<strong>de</strong>n.<br />
public boolean before(Date d)<br />
public boolean after(Date d)<br />
// testet, ob das eigene Datum vor / nach <strong>de</strong>m Datum <strong>de</strong>s Parameters ist. „true“, wenn getTime() für<br />
// bei<strong>de</strong> <strong>de</strong>n gleichen Wert ergibt und <strong>de</strong>r Parameter nicht null ist.<br />
public <strong>in</strong>t compareTo(Date d)<br />
// vergleicht zwei Datum-Objekte und gibt 0 zurück, falls bei<strong>de</strong> die gleiche Zeit repräsentieren.<br />
//<br />
public <strong>in</strong>t compareTo(Object o)<br />
// Ist das übergebene Objekt vom Typ Date, dann verhält sich die Funktion wie das zuvor<br />
// angegebene compareTo(). An<strong>de</strong>renfalls wirft die Metho<strong>de</strong> e<strong>in</strong>e ClassCastException<br />
...<br />
Abb.: Die Klasse Date<br />
Bsp. 325 :<br />
import java.util.Date;<br />
class DatumundZeit<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
System.out.pr<strong>in</strong>tln(new Date() );<br />
}<br />
}<br />
325 pr65100<br />
457
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klasse Calendar<br />
(abstract class java.util.Calendar implements Serializable, Cloneable)<br />
Sie wird e<strong>in</strong>gesetzt zur Konvertierung zwischen verschie<strong>de</strong>nen Datumsformaten. Die<br />
Klasse Calendar besitzt nur e<strong>in</strong>ige statisch Funktionen, z.B. getInstance(). Mit<br />
<strong>de</strong>r Klassenmetho<strong>de</strong> getInstance() bekommt man e<strong>in</strong> nutzbares Format:<br />
public static Calendar getInstance()<br />
liefert e<strong>in</strong>en Calendar <strong>in</strong> <strong>de</strong>r Ausprägung von GregorianCalendar mit <strong>de</strong>r dargestellten Zeitzone und<br />
Lokalisierung.<br />
Die Klasse GregorianCalendar<br />
Die abstrakte Klasse Calendar wird durch die Klasse GregorianCalendar<br />
implementiert. In <strong>de</strong>r gegenwärtigen Implementierung <strong>de</strong>ckt die Klasse <strong>de</strong>n Zeitraum<br />
von 4716 v. Chr. bis zum Jahre 5.000.000.<br />
GregorianCalendar<br />
><br />
public GregorianCalendar()<br />
// erzeugt e<strong>in</strong> standardmäßiges GregorianCalendar-Objekt mit <strong>de</strong>r aktuellen Zeit <strong>in</strong> <strong>de</strong>r<br />
// vore<strong>in</strong>gestellten Zeitzone und Lokalisierung<br />
public GregorianCalendar(<strong>in</strong>t jahr, <strong>in</strong>t monat, <strong>in</strong>t tag)<br />
// erzeugt e<strong>in</strong> GregorianCalendar-Objekt <strong>in</strong> <strong>de</strong>r vore<strong>in</strong>gestellten Zeitzone und Lokalisierung. Das<br />
// Datum wird durch jahr, monat (0
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Feldbezeichner M<strong>in</strong>imalwert Maximalwert Erklärung<br />
ERA 0(BC) 1(AD) Datum vor o<strong>de</strong>r nach Christi<br />
YEAR 1 5000000 Jahr<br />
MONTH 0 11 Monat<br />
DAY_OF_MONTH 1 31 Tag<br />
WEEK_OF_YEAR 1 54 Woche<br />
WEEK_OF_MONTH 1 6 Woche <strong>de</strong>s Monats<br />
DAY_OF_YEAR 1 366 Tag <strong>de</strong>s Jahres<br />
DAY_OF_WEEK 1 7 Tag <strong>de</strong>r Woche (1 = Sonntag, 7 =<br />
Samstag<br />
DAY_OF_WEEK_IN_MONTH -1 6 Tag <strong>de</strong>r Woche im Monat<br />
HOUR 0 12 Stun<strong>de</strong> von 12<br />
HOUR_OF_DAY 0 23 Stun<strong>de</strong> von 24<br />
MINUTE 0 59 M<strong>in</strong>ute<br />
SECOND 0 59 Sekun<strong>de</strong>n<br />
MILLISECOND 0 999 Millisekun<strong>de</strong>n<br />
AM_PM 0 1 Vor 12, nach 12<br />
ZONE_OFFSET -12*60*60*1000 12*60*60*1000 Zeitzonenabweichnung <strong>in</strong><br />
Millisekun<strong>de</strong>n<br />
DST_OFFSET 0 1*60*60*1000 Sommerzeitabweichnung <strong>in</strong><br />
Millisekun<strong>de</strong>n<br />
Abb.: Konstanten aus <strong>de</strong>r Klasse Calendar<br />
Bsp.: Ausgabe wichtiger Datumsfel<strong>de</strong>r 326<br />
import java.util.*;<br />
public class DateDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
GregorianCalendar cal = new GregorianCalendar();<br />
cal.setTimeZone(TimeZone.getTimeZone("ECT"));<br />
cal.setTime(cal.getTime());<br />
pr<strong>in</strong>tCalendar(cal);<br />
cal.set(Calendar.DATE,12);<br />
cal.set(Calendar.MONTH,Calendar.MARCH);<br />
cal.set(Calendar.YEAR,1973);<br />
pr<strong>in</strong>tCalendar(cal);<br />
}<br />
public static void pr<strong>in</strong>tCalendar(Calendar cal)<br />
{<br />
Str<strong>in</strong>g wochenTag = (new Str<strong>in</strong>g[]{"Sonntag",<br />
"Montag","Dienstag","Mittwoch","Donnerstag",<br />
"Freitag","Samstag"})<br />
[cal.get(Calendar.DAY_OF_WEEK)];<br />
System.out.pr<strong>in</strong>tln(wochenTag + ", " +<br />
cal.get(Calendar.DATE) + "." +<br />
(cal.get(Calendar.MONTH)+1) + "." +<br />
cal.get(Calendar.YEAR) + ", " +<br />
cal.get(Calendar.HOUR_OF_DAY) + ":" +<br />
o(cal.get(Calendar.MINUTE)) + ":" +<br />
o(cal.get(Calendar.SECOND)) + " und " +<br />
cal.get(Calendar.MILLISECOND) + " ms ");<br />
System.out.pr<strong>in</strong>tln("Es ist die " +<br />
cal.get(Calendar.WEEK_OF_YEAR) + ". Woche im Jahr und ");<br />
System.out.pr<strong>in</strong>tln(cal.get(Calendar.WEEK_OF_MONTH) +<br />
". Woche im Monat\n");<br />
}<br />
public static Str<strong>in</strong>g o(<strong>in</strong>t i)<br />
326 pr65100<br />
459
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
{<br />
return (i >= 10) ? Integer.toStr<strong>in</strong>g(i) : "0" + i;<br />
}<br />
}<br />
Die Klasse TimeZone (abstract class java.util.TimeZone implements<br />
Serializable, Cloneable)<br />
Die Klasse TimeZone repräsentiert e<strong>in</strong>e Zeitzone <strong>in</strong>klusive Zeitverschiebung und<br />
benutzt dazu folgen<strong>de</strong> statische Metho<strong>de</strong>n:<br />
public static TimeZone getDefault()<br />
// gibt die Zeitzone für die Umgebung zurück<br />
public static Str<strong>in</strong>g[] getAvailableIDs()<br />
// liefert alle verfügbaren IDs<br />
public static TimeZone getTimeZone(Str<strong>in</strong>g ID)<br />
// liefert die Zeitzone für e<strong>in</strong>e gegebene ID<br />
Bsp.: Gib e<strong>in</strong>e Aufzählung aller unterstützten Zeitzonen 327 an.<br />
import java.util.*;<br />
public class AlleZonen<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Str<strong>in</strong>g s[] = TimeZone.getAvailableIDs();<br />
Arrays.sort(s);<br />
for (<strong>in</strong>t i = 0; i < s.length; i++)<br />
System.out.pr<strong>in</strong>tln(s[i]);<br />
}<br />
}<br />
327 Unter W<strong>in</strong>dows mit <strong>de</strong>m JDK 1.3 s<strong>in</strong>d dies 321 Zeitzonen, pr65100<br />
460
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.5.2 Formatieren <strong>de</strong>r Datumsangaben<br />
Die Klasse DateFormat<br />
DateFormat<br />
><br />
public f<strong>in</strong>al Str<strong>in</strong>g format(Date d)<br />
// formatiert das Datum <strong>in</strong> e<strong>in</strong>en Datum / Zeit-Str<strong>in</strong>g<br />
public static f<strong>in</strong>al DateFormat getDateInstance()<br />
public static f<strong>in</strong>al DateFormat getTimeInstance()<br />
public static f<strong>in</strong>al DateFormat getDateTimeInstance()<br />
// liefert e<strong>in</strong>en Datum/Zeit-Formatierer mit <strong>de</strong>m vorgegebenen stil aus <strong>de</strong>r Standardumgebung<br />
public static f<strong>in</strong>al DateFormat getDateInstance(<strong>in</strong>t dateStil)<br />
public static f<strong>in</strong>al DateFormat getTimeInstance(<strong>in</strong>t stil)<br />
// liefert e<strong>in</strong>en Datum/Zeit-Formatierer mit <strong>de</strong>n Stil stil und <strong>de</strong>r Standardsprache<br />
public static f<strong>in</strong>al DateFormat getDateInstance(<strong>in</strong>t stil, Locale lokal 328 )<br />
public static f<strong>in</strong>al DateFormat getTimeInstance(<strong>in</strong>t stil, Locale lokal)<br />
// liefert e<strong>in</strong>en Datum/Zeit-Formatierer und <strong>de</strong>r Sprache lokal<br />
public static f<strong>in</strong>al DateFormat getDateTimeInstance(<strong>in</strong>t dateStil, <strong>in</strong>t timeStil)<br />
// gibt e<strong>in</strong>en Datum/Zeit-Formatierer für die gesetzte Sprache im angegebenen<br />
// Formatierungsstil zurück<br />
public static f<strong>in</strong>al DateFormat getDateTimeInstance(<strong>in</strong>t dateStil, <strong>in</strong>t timeStil, Locale lokal)<br />
// gibt e<strong>in</strong> Datum/Zeit-Formatierer für die Sprache lokal im angegebenen Formatierungsstil zurück<br />
public Date parse(Str<strong>in</strong>g fs) throws ParseException<br />
// „parst“ e<strong>in</strong> Datum o<strong>de</strong>r e<strong>in</strong>en Zeit-Str<strong>in</strong>g<br />
...<br />
Abb.: Die Klasse DateFormat<br />
(abstract class java.text.DateFormat extends Format implements Cloneable, Serializable<br />
Die Klasse DateFormat bietet die Metho<strong>de</strong>n getDateInstance(),<br />
getTimeInstance(), getDateTimeInstance() mit <strong>de</strong>n Paramtern<br />
DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG,<br />
DateFormat.FULL an, die die Zeit bzw. das Datum auf vier verschie<strong>de</strong>ne Arten<br />
formatieren:<br />
Konstante Beispiel für das Datum Beispiel für die Zeit<br />
SHORT 29.9.01 21:51<br />
MEDIUM 29.9.2001 21:51:45<br />
LONG 22. September 2001 21:53:20 GMT+02:00<br />
FULL Samstag, 22. September 2001 21:53 Uhr GMT+02:00<br />
Abb.: Konstanten aus DateFormat<br />
Da DateFormat abstrakt ist, ist erst die aus DateFormat abgeleitete Klasse<br />
SimpleDateFormat e<strong>in</strong>satzbereit.<br />
Bsp. mit Sprachen 329 : Das folgen<strong>de</strong> Programm erzeugt die Ausgabe für Deutschland<br />
und anschließend für Italien.<br />
328 Unter Locale s<strong>in</strong>d für e<strong>in</strong>ige Sprachen Konstanten vor<strong>de</strong>f<strong>in</strong>iert: ENGLISH, FRENCH, GERMAN,<br />
ITALIAN, JAPANESE, KOREAN, CHINESE, SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE<br />
461
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
import java.util.*;<br />
import java.text.*;<br />
public class SimpleDateFormatierer<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
Calendar cal;<br />
cal = new GregorianCalendar(TimeZone.getTimeZone("ECT") );<br />
cal.setTime(cal.getTime());<br />
DateFormat format;<br />
format = DateFormat.getDateTimeInstance(<br />
DateFormat.FULL, DateFormat.MEDIUM);<br />
System.out.pr<strong>in</strong>tln(format.format(cal.getTime() ) );<br />
format = DateFormat.getDateTimeInstance(<br />
DateFormat.FULL, DateFormat.MEDIUM, Locale.ITALY);<br />
System.out.pr<strong>in</strong>tln(format.format(cal.getTime() ) );<br />
}<br />
}<br />
Die Klasse SimpleDateFormat<br />
Zum Formatieren e<strong>in</strong>es Datum-Objekts muß zunächst e<strong>in</strong> Objekt von<br />
SimpleDateFormat erzeugt wer<strong>de</strong>n. Dieses bekommt dann evtl.<br />
Formatierungsanweisungen (über e<strong>in</strong>e an<strong>de</strong>re Metho<strong>de</strong> o<strong>de</strong>r über e<strong>in</strong>en weiteren<br />
Konstruktor) mit und formatiert dann mit <strong>de</strong>r format() das Datum.<br />
SimpleDateFormat<br />
><br />
public SimpleDateFormat()<br />
// erzeugt e<strong>in</strong>e neues SimpleDateFormat-Objekt <strong>in</strong> <strong>de</strong>r e<strong>in</strong>gestellten Sprache<br />
public SimpleDateFormat(Str<strong>in</strong>g fs)<br />
// erzeugt e<strong>in</strong> SimpleDateFormat-Objekt mit <strong>de</strong>m vorgegebenen Formatierungsstr<strong>in</strong>g <strong>in</strong> <strong>de</strong>r<br />
// vore<strong>in</strong>gestellten Sprache<br />
public SimpleDateFormat(Str<strong>in</strong>g fs, Locale loc)<br />
// erzeugt e<strong>in</strong> SimpleDateFormat-Objekt mit <strong>de</strong>m vorgebenen Formatierungsstr<strong>in</strong>g <strong>in</strong> <strong>de</strong>r Sprache<br />
// loc.<br />
><br />
public void applyPattern(Str<strong>in</strong>g fs)<br />
// setze <strong>de</strong>n Formatieruns-Str<strong>in</strong>g<br />
public void applyLocalizedPattern(Str<strong>in</strong>g pattern)<br />
// sertzt <strong>de</strong>n Formatierungs-str<strong>in</strong>g für die gegebenen Sprache<br />
public Str<strong>in</strong>g toPattern()<br />
// liefert <strong>de</strong>n Formatierungsstr<strong>in</strong>g<br />
public Str<strong>in</strong>g toLocalizedPattern()<br />
// liefert <strong>de</strong>n übersetzten Formatierungsstr<strong>in</strong>g<br />
Abb.: Die Klasse SimpleDateFormat (class java.text.SimpleDateFormat extends<br />
DateFormat)<br />
Zur <strong>in</strong>dividuellen Anpassung <strong>de</strong>r Ausgabe kann e<strong>in</strong> Formatierungsstr<strong>in</strong>g angegeben<br />
wer<strong>de</strong>n. Diese Formatierungsanweisung wird entwe<strong>de</strong>r <strong>de</strong>m Konstruktor übergeben<br />
o<strong>de</strong>r kann nachträglich mit <strong>de</strong>r Metho<strong>de</strong> applyPattern() geän<strong>de</strong>rt wer<strong>de</strong>n.<br />
329 vgl. pr65200<br />
462
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Symbol Be<strong>de</strong>utung Präsentation Beispiel<br />
G Ära Text AD<br />
Y Jahr Nummer 1998<br />
M Monat im Jahr Nummer 7<br />
MM Monat im Jahr m. Null Nummer 07<br />
MMM Monat im Jahr (kurz) Text Sep<br />
MMMM Monat im Jahr (lang) Text September<br />
d Tag im Monat Nummer 26<br />
h Stun<strong>de</strong> (1-12) Nummer 9<br />
H Stun<strong>de</strong> am Tag (0-23) Nummer 0<br />
m M<strong>in</strong>ute <strong>de</strong>r Stun<strong>de</strong> Nummer 13<br />
s Sekun<strong>de</strong> <strong>de</strong>r M<strong>in</strong>ute Nummer 22<br />
S Millisekun<strong>de</strong> Nummer 257<br />
E Tag <strong>de</strong>r Woche (kurz) Text Mi<br />
EEEE Tag <strong>de</strong>r Woche (lang) Text Mittwoch<br />
D Tag im Jahr Nummer 304<br />
F Tag <strong>de</strong>r Woche i. Mon. Nummer 3<br />
w Woche im Jahr Nummer 13<br />
W<br />
Woche im Monat<br />
a am/pm-Text Text AM<br />
k Stun<strong>de</strong> am Tg (1-24) Nummer 24<br />
K Stun<strong>de</strong> (0-11) Nummer 0<br />
Z Zeitzone Text GMT+02:00<br />
‘ Zeichen für Text Trennzeichen<br />
‘ ' E<strong>in</strong>zelnes Hochkomma Literal ‘<br />
Abb.: Symbole im Formatstr<strong>in</strong>g zur Steuerung <strong>de</strong>r Ausgabe<br />
6.6 Formatieren mit Format-Objekten<br />
Zahlen, Datumsangaben und Text können auf verschie<strong>de</strong>ne Art und Weise formatiert<br />
wer<strong>de</strong>n. Unter <strong>Java</strong> wird das Formatierungsverhalten <strong>in</strong> e<strong>in</strong>er abstrakten Klasse<br />
Format (abstract class java.text.Format implements Serializable,<br />
Cloneable) fixiert. Format stellt die Metho<strong>de</strong>n format() und parseObject()<br />
bereit. Je<strong>de</strong> Zeichenkette, die vom Format-Objekt erzeugt wur<strong>de</strong>, ist auch mit <strong>de</strong>m<br />
Parser wie<strong>de</strong>r e<strong>in</strong>lesbar.<br />
Im JDK erweitern drei Klassen Format: DateFormat, MessageFormat und<br />
NumberFormat. Sie übernehmen die E<strong>in</strong>-/Ausgabe für das Datum, allgeme<strong>in</strong>e<br />
Botschaften (Nachrichten) und Zahlen. Je<strong>de</strong> <strong>de</strong>r Klassen implementiert die Metho<strong>de</strong>n<br />
zur Ausgabe format() und zum Erkennen parseObject(). In <strong>Java</strong> 5 realisiert die<br />
format()-Funktion e<strong>in</strong>e Ausgabe, so wie sie unter <strong>de</strong>r Programmiersprache C mit<br />
pr<strong>in</strong>tf() gesetzt wur<strong>de</strong>.<br />
463
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.6.1 Die Klasse Numberformat für die Ausgabe von Prozenten, Zahlen,<br />
Währungen<br />
Für die häufigsten Ausgaben als Prozentzahlen o<strong>de</strong>r als Währungszahlen gibt es die<br />
speziellen statischen Funktionen getPercentInstance(),<br />
getNumberInstance(), getIntegerInstance() und<br />
getCurrencyInstance() 330 .<br />
6.6.2 Ausgabe formatieren mit MessageFormat<br />
MessageFormat ist e<strong>in</strong>e konkrete Unterklasse <strong>de</strong>r abstrakten Klasse Format. Sie<br />
dient dazu, Nachrichten sprachunabhängig zu erzeugen.<br />
6.6.3 Dezimalzahlenformatierung mit DecimalFormat<br />
Die Klasse DecimalFormat dient zur formatierten Ausgabe von ganzen Zahlen.<br />
Dem Konstruktor wird e<strong>in</strong> Formatierungs- Str<strong>in</strong>g übergeben. Die Formatierung erfolgt<br />
unter Berücksichtigung <strong>de</strong>r e<strong>in</strong>gestellten Sprache.<br />
Bsp.: Die Klasse DecimalFormatTest 331<br />
import java.text.*;<br />
public class DecimalFormatTest<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
double d = 12345.67890;<br />
DecimalFormat df = new DecimalFormat("###,##0.00");<br />
System.out.pr<strong>in</strong>tln(df.format(d));<br />
}<br />
}<br />
Symbol Be<strong>de</strong>utung<br />
0 repräsentiert e<strong>in</strong>e Zahl<br />
# e<strong>in</strong>e Zahl. Ist an dieser Stelle ke<strong>in</strong>e Zahl angegeben, dann bleibt die Stelle leer<br />
. trennt Vor- und Nachkommastellen<br />
, gruppiert die Zahl (E<strong>in</strong>e Gruppe ist so graß wie <strong>de</strong>r Abstand von ',' zu '.'.<br />
; Trennzeichen für mehrere Formate<br />
- Standardzeichen für negatives Präfix<br />
% die Zahl wird mit 100 multipliziert und als Prozent ausgewiesen<br />
%% genau wie Prozent nur mit Promille<br />
- Nationales Währungssymbol<br />
-- Internationales Währungssymbol<br />
X alle an<strong>de</strong>re Zeichen können normal benutzt wer<strong>de</strong>n<br />
' Ausmarkieren von speziellen Symbolen (im Präfix o<strong>de</strong>r Suffix benutzt).<br />
Abb.: Formatierungsanweisungen für DecimalFormat<br />
330 jeweils <strong>in</strong> <strong>de</strong>r parmeterlosen Variante und <strong>in</strong> <strong>de</strong>r Variante mit e<strong>in</strong>em Locale-Objekt.<br />
331 vgl. pr65200<br />
464
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
6.6.4 Formatieren mit format()<br />
Die Klasse f<strong>in</strong>al class java.lang.Str<strong>in</strong>g implements CharSequence,<br />
Comparable, Serializable stellt mit <strong>de</strong>r statischen Funktion format() e<strong>in</strong>e<br />
Metho<strong>de</strong> bereit, Zeichenketten nach e<strong>in</strong>er Vorlage zu formatieren<br />
static Str<strong>in</strong>g format(Locale l, Str<strong>in</strong>g format, Object ... args)<br />
liefert e<strong>in</strong>en formatierten Str<strong>in</strong>g, <strong>de</strong>r aus <strong>de</strong>r gewünschten Sprache, <strong>de</strong>m Str<strong>in</strong>g und Argumenten<br />
hervorgeht.<br />
static Str<strong>in</strong>g format(Str<strong>in</strong>g format,Object ... args)<br />
liefert e<strong>in</strong>en formatierten Str<strong>in</strong>g, <strong>de</strong>r aus <strong>de</strong>m format-Str<strong>in</strong>g und <strong>de</strong>n Argumenten hervorgeht.<br />
Der Str<strong>in</strong>g format nennt sich Format-Str<strong>in</strong>g. Er enthält neben <strong>de</strong>m auszugeben<strong>de</strong>n<br />
Zeichen sogenannte Format-Spezifierer, die <strong>de</strong>m Formatierer darüber Auskunft<br />
geben, wie das Argument formatiert wer<strong>de</strong>n soll. "%s" steht für e<strong>in</strong>e unformatierte<br />
Ausgabe e<strong>in</strong>es Str<strong>in</strong>gs.<br />
Die Anzahl <strong>de</strong>r Format-Spezifierer ist groß und vielfältig. Intern übernehmen diese<br />
Aufgabe java.util.Formatter, die sich auch direkt verwen<strong>de</strong>n lassen.<br />
Praktischerweise ist das Formatieren und Ausgaben zu e<strong>in</strong>er neuen Funktion<br />
pr<strong>in</strong>tf() <strong>in</strong> <strong>de</strong>n Pr<strong>in</strong>tWriter und Pr<strong>in</strong>tStream 332 gewan<strong>de</strong>rt<br />
332 das System.out-Objekt ist vom Typ Pr<strong>in</strong>tStream<br />
465
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7. E<strong>in</strong>- und Ausgabe<br />
In <strong>Java</strong> wer<strong>de</strong>n E<strong>in</strong>-, Ausgabeoperationen über sog. Datenströme 333 realisiert. Es<br />
stehen zur Behandlung <strong>de</strong>s Datenstrommo<strong>de</strong>lls zwei abstrakte Klassen zur<br />
Verfügung: InputStream und OutputStream. Die bei<strong>de</strong>n Klassen gehören zu<br />
<strong>de</strong>m Paket java.io 334 , das bei je<strong>de</strong>m Programm mit E<strong>in</strong>-/Ausgabeoperationen<br />
importiert wer<strong>de</strong>n muß.<br />
E<strong>in</strong>fache Strom-Metho<strong>de</strong>n erlauben nur das Versen<strong>de</strong>n von Bytes mit Hilfe von<br />
Datenströmen 335 . E<strong>in</strong> nicht <strong>in</strong>terpretierbarer Bytestrom kann von je<strong>de</strong>r beliebigen<br />
Quelle kommen. Quelle bzw. Ziel <strong>de</strong>s Stroms s<strong>in</strong>d völlig verschie<strong>de</strong>ne Erzeuger bzw.<br />
Verbraucher von Bytes.<br />
Allgeme<strong>in</strong>e Metho<strong>de</strong>n, die von je<strong>de</strong>r beliebigen Quelle lesen können, akzeptieren e<strong>in</strong><br />
Stromargument zur Bezeichnung <strong>de</strong>r Quelle. Allgeme<strong>in</strong>e Metho<strong>de</strong>n 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 Sen<strong>de</strong>n/Empfangen verschie<strong>de</strong>ner Datentypen gibt es die Schnittstellen<br />
DataInput und DataOutput. Sie legen Metho<strong>de</strong>n zum Sen<strong>de</strong>n/Empfangen<br />
an<strong>de</strong>rer <strong>Java</strong>-Datentypen fest. Mit Hilfe <strong>de</strong>r Schnittstellen ObjectInput und<br />
ObjectOutput lassen sich ganze Objekte über e<strong>in</strong>en Strom sen<strong>de</strong>n.<br />
Alle Metho<strong>de</strong>n, die sich mit E<strong>in</strong>- und Ausgabeoperationen beschäftigen, wer<strong>de</strong>n <strong>in</strong><br />
<strong>de</strong>r Regel mit throws IOException abgesichert. Diese Subklasse von Exception<br />
enthält alle potentiellen I/O-Fehler, die bei <strong>de</strong>r 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 o<strong>de</strong>r an<br />
übergeordnete Metho<strong>de</strong>n weitergegeben wer<strong>de</strong>n.<br />
333 Der Begriff Strom kommt aus <strong>de</strong>m Betriebssystem Unix und bezieht sich auf „Pipes“. E<strong>in</strong>e Pipe ist e<strong>in</strong> nicht<br />
<strong>in</strong>terpretierbarer Strom von Bytes, <strong>de</strong>r zur Kommunikation zwischen Programmen (bzw. „gegabelten Kopien“<br />
e<strong>in</strong>es Programms) o<strong>de</strong>r zum Lesen und Schreiben von verschie<strong>de</strong>nen Geräten und Dateien benutzt wird.<br />
E<strong>in</strong> Strom ist e<strong>in</strong> Kommunikationspfad zwischen <strong>de</strong>r Quelle und <strong>de</strong>m Ziel e<strong>in</strong>es Informationsblocks.<br />
334 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 />
335 E<strong>in</strong> Strom von Bytes kann mit e<strong>in</strong>em Wasserstrom verglichen wer<strong>de</strong>n. 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 verwen<strong>de</strong>t. Die Verb<strong>in</strong>dung von Strömen kann mit <strong>de</strong>m Verb<strong>in</strong><strong>de</strong>n von Wasserschläuchen<br />
verglichen wer<strong>de</strong>n.<br />
467
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
DataInput<br />
ByteArrayInputStream<br />
FileInputStream<br />
BufferedInputStream<br />
DataInputStream<br />
FilterInputStream<br />
L<strong>in</strong>eNumberInputStream<br />
InputStream PipedInputStream PushbackInputStream<br />
SequenceInputStream<br />
Str<strong>in</strong>gBufferedInputStream<br />
Object<br />
RandomAccessFile<br />
DataOutput<br />
OutputStream<br />
ByteArrayOutputStream<br />
FileOutputStream<br />
FilterOutputStream<br />
PipedOutputStream<br />
BufferedOutputStream<br />
DataOutputStream<br />
Pr<strong>in</strong>tStream<br />
EOFException<br />
FileNotFoundException<br />
Throwable Exception IOException InterruptedIOException<br />
UTFDataFormatException<br />
Abb.: java.io<br />
468
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 wer<strong>de</strong>n.<br />
Woher die Bytes kommen und wie sie beför<strong>de</strong>rt wer<strong>de</strong>n, spielt ke<strong>in</strong>e Rolle. Sie<br />
müssen <strong>de</strong>m e<strong>in</strong>lesen<strong>de</strong>n Objekt nur zur Verfügung stehen. Die Aufgabe <strong>de</strong>r Klasse<br />
InputStream ist die Repräsentation von Klassen, die E<strong>in</strong>gaben aus verschie<strong>de</strong>nen<br />
Quellen produzieren.<br />
Klasse Funktion Argument für <strong>de</strong>n Konstruktor<br />
Nutzungsmöglichkeit<br />
ByteArrayInputStream<br />
E<strong>in</strong> Puffer im arbeitsspeicher Der Puffer aus <strong>de</strong>m Bytes geholt<br />
wird ald E<strong>in</strong>gabestrom benutzt. wer<strong>de</strong>n.<br />
Als Datenquelle. Verbun<strong>de</strong>n mit<br />
e<strong>in</strong>em FileInputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Str<strong>in</strong>gBufferInputStream<br />
Konvertiert e<strong>in</strong>en Str<strong>in</strong>g <strong>in</strong> e<strong>in</strong>en<br />
InputStream<br />
469<br />
Interface gestaltet wer<strong>de</strong>n.<br />
E<strong>in</strong> Str<strong>in</strong>g. Die zugrun<strong>de</strong>liegen<strong>de</strong><br />
Implementierung benutzt e<strong>in</strong>en<br />
Str<strong>in</strong>gBuffer.<br />
Als Datenquelle. Verbun<strong>de</strong>n mit<br />
e<strong>in</strong>em FiIeInputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Interface gestaltet wer<strong>de</strong>n.<br />
FileInputStream Dient zum Lesen aus e<strong>in</strong>er Datei E<strong>in</strong> Str<strong>in</strong>g <strong>de</strong>r <strong>de</strong>n Date<strong>in</strong>amen<br />
enthält o<strong>de</strong>r e<strong>in</strong> File- bzw.<br />
FileDescriptor-Objekt<br />
Als Datenquelle. Verbun<strong>de</strong>n mit<br />
PipedInputStream Produziert Daten für <strong>de</strong>n<br />
PipedOutputStream (implentiert<br />
das „Pipe“-Konzept.<br />
SequenceInputStream<br />
Abb.: E<strong>in</strong>gabestrom-Typen<br />
Konvertiert zwei o<strong>de</strong>r mehrere<br />
„InputStream“-Objekte <strong>in</strong> e<strong>in</strong>en<br />
e<strong>in</strong>zelnen InputStream.<br />
Quellen zu e<strong>in</strong>em E<strong>in</strong>gabestrom können se<strong>in</strong>:<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 />
e<strong>in</strong>em FilterInputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Interface gestaltet wer<strong>de</strong>n.<br />
PipedOutputStream.<br />
Als Datenquelle im<br />
Multithread<strong>in</strong>g. Verbun<strong>de</strong>n mit<br />
e<strong>in</strong>em FilterInputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Interface gestaltet wer<strong>de</strong>n.<br />
Zwei InputStream-Objekte o<strong>de</strong>r<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. Verbun<strong>de</strong>n mit<br />
e<strong>in</strong>em FilterInputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Interface gestaltet wer<strong>de</strong>n.
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
5. E<strong>in</strong>e Folge von Strömen, die zu e<strong>in</strong>em umfassen<strong>de</strong>n, e<strong>in</strong>zelnen Strom gesammelt wer<strong>de</strong>n können.<br />
6. An<strong>de</strong>rs beschaffene Quellen, z.B. e<strong>in</strong>e Internet-Verb<strong>in</strong>dung<br />
Die „read“-Metho<strong>de</strong>n<br />
Zum E<strong>in</strong>lesen von Datenströmen gibt es die „read“-Metho<strong>de</strong>. 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 <strong>de</strong>m E<strong>in</strong>gabestrom gelesen und ausgegeben. Falls <strong>de</strong>r Bytestrom das En<strong>de</strong><br />
erreicht hat, wird „-1“ 336 ausgageben. Die Metho<strong>de</strong> führt e<strong>in</strong> blockieren<strong>de</strong>s Lesen<br />
aus, d.h.: Es wird auf Daten gewartet, falls sie nicht unmittelbar zur Verfügung<br />
stehen.<br />
Die Metho<strong>de</strong> 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 wur<strong>de</strong>n und gibt die Anzahl<br />
Bytes zurück. Bei Bedarf (z.B. im Datenstrom s<strong>in</strong>d nicht genügend Bytes vorhan<strong>de</strong>n)<br />
wer<strong>de</strong>n 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) throws<br />
IOException füllt e<strong>in</strong> Datenfeld ab Position „offset“ mit bis zu length Bytes aus<br />
<strong>de</strong>m Strom. Es wird entwe<strong>de</strong>r die Anzahl <strong>de</strong>r gelesenen Bytes o<strong>de</strong>r –1 für das<br />
Dateien<strong>de</strong> ausgegeben.<br />
Weitere nützliche Metho<strong>de</strong>n<br />
public <strong>in</strong>t available throws IOException<br />
Allen „read“-Metho<strong>de</strong>n ist geme<strong>in</strong>sam: Sie warten auf das En<strong>de</strong> aller angefor<strong>de</strong>rten<br />
E<strong>in</strong>gaben. Es kann dabei zu längeren Blocka<strong>de</strong>n beim E<strong>in</strong>lesen von Daten kommen.<br />
Die Metho<strong>de</strong> „available“ gibt die Anzahl Bytes zurück, die ohne Blockieren<br />
gelesen wer<strong>de</strong>n kann.<br />
public long skip(long n) throws IOException<br />
Die „skip“-Metho<strong>de</strong> benutzt „read“ zum Überspr<strong>in</strong>gen und blockiert <strong>de</strong>shalb unter<br />
<strong>de</strong>n gleichen Bed<strong>in</strong>gungen wie „read“. Die gibt die Anzahl Bytes zurück, die sie<br />
übersprungen hat, o<strong>de</strong>r „-1“, falls das En<strong>de</strong> <strong>de</strong>s Stroms erreicht wur<strong>de</strong><br />
public boolean markSupported()<br />
Die Metho<strong>de</strong> gibt „true“ zurück, falls <strong>de</strong>r Sttrom Markierungen unterstützt.<br />
public void mark(<strong>in</strong>t readLimit)<br />
Die Metho<strong>de</strong> markiert die aktuelle Position im Strom für e<strong>in</strong>e spätere Rückkehr.<br />
public void reset() throws IOException<br />
Mit dieser Metho<strong>de</strong> kann <strong>de</strong>r Strom auf die Markierung zurücksetzen.<br />
public void close() throws IOException<br />
Diese Metho<strong>de</strong> schließt die Verarbeitung von e<strong>in</strong>em Strom. Die meisten Ströme<br />
wer<strong>de</strong>n automatisch bei <strong>de</strong>r Garbage Collection geschlossen.<br />
336 Rückgabe „-1“ be<strong>de</strong>utet zum Unterschied von C nicht, daß e<strong>in</strong> Fehler aufgetreten ist.<br />
470
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.1.2 OutputStream<br />
Aufgabenbeschreibung<br />
Der Ausgabestrom ist e<strong>in</strong> Empfänger von Daten. Man f<strong>in</strong><strong>de</strong>t Ausgabeströme fast nur<br />
<strong>in</strong> Verb<strong>in</strong>dung mit E<strong>in</strong>gabeströmen. Die Aufgabe <strong>de</strong>r Klasse OutputStream ist die<br />
Repräsentation von Klassen zur Festlegung <strong>de</strong>r Datensenke. Das kann e<strong>in</strong> „Array<br />
von Bytes“, e<strong>in</strong>e Datei o<strong>de</strong>r e<strong>in</strong>e „Pipe“ se<strong>in</strong>.<br />
Klasse Funktion Argumente für <strong>de</strong>n Konstruktur<br />
Nutzungsmöglichkeit<br />
ByteArrayOutputStream Kreiert e<strong>in</strong>en Arbeits-speicher-<br />
Puffer. Alle vom Strom<br />
gesen<strong>de</strong>ten Daten wer<strong>de</strong>n hier<br />
plaziert.<br />
Optional: zu <strong>in</strong>itialisieren<strong>de</strong><br />
Puffergröße<br />
Zum Bestimmen <strong>de</strong>s Datenziels.<br />
Verbun<strong>de</strong>n mit e<strong>in</strong>em<br />
FilterOutputStream-Objekt kann<br />
daraus e<strong>in</strong> nützliches Interface<br />
gestaltet wer<strong>de</strong>n.<br />
FileOutputStream Zum Schreiben e<strong>in</strong>er Datei E<strong>in</strong>e Zeichenkette, die <strong>de</strong>n<br />
Namen <strong>de</strong>r Datei repräsentiert ,<br />
bzw. e<strong>in</strong> File- o<strong>de</strong>r<br />
FileDescriptor-Objekt.<br />
Zum Bestimmen e<strong>in</strong>es<br />
Datenziels. Verbun<strong>de</strong>n mit<br />
e<strong>in</strong>em FileOutputStream-Objekt<br />
kann daraus e<strong>in</strong> nützliches<br />
Interface gestaltet wer<strong>de</strong>n.<br />
PipedOutputStream<br />
Abb.: Ausgabestrom-Typen<br />
Information zum Schreiben ist<br />
E<strong>in</strong>gabe für <strong>de</strong>n assoziierten<br />
PipedInputStream<br />
PipedInputStream<br />
Zum Bestimmen <strong>de</strong>s datenziels<br />
für „Multithread<strong>in</strong>g“. Verbun<strong>de</strong>n<br />
mit e<strong>in</strong>em FilterOutputStream-<br />
Objekt kann daraus e<strong>in</strong><br />
nützliches Interface gestaltet<br />
wer<strong>de</strong>n.<br />
Die „write“-Metho<strong>de</strong>n<br />
public abstract void write(<strong>in</strong>t b) throws IOException<br />
Die Metho<strong>de</strong> schreibt e<strong>in</strong> e<strong>in</strong>zelnes Byte <strong>in</strong> <strong>de</strong>n Ausgabestrom.<br />
public void write(byte[] bytes) throws IOException<br />
Die Metho<strong>de</strong> schreibt <strong>de</strong>n Inhalt <strong>de</strong>s Datenfelds bytes <strong>in</strong> <strong>de</strong>n Ausgabestrom.<br />
public void write(byte[] bytes, <strong>in</strong>t offset, <strong>in</strong>t length) throws<br />
IOException<br />
Die Metho<strong>de</strong> schreibt „length“ Bytes ab Position „offset“ aus <strong>de</strong>m Datenfeld<br />
bytes.<br />
public void flush() throws IOException<br />
Diese Metho<strong>de</strong> leert e<strong>in</strong>en Ausgabestrom<br />
public void close() throws IOException<br />
Auch Ausgabeströme sollten am En<strong>de</strong> e<strong>in</strong>er Verarbeitung geschlossen wer<strong>de</strong>n.<br />
471
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><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 Metho<strong>de</strong>n.<br />
Der große Vorteil liegt <strong>in</strong> <strong>de</strong>r Verb<strong>in</strong>dung mit e<strong>in</strong>em an<strong>de</strong>ren Strom. Die<br />
Konstruktoren für <strong>de</strong>n FilterInputStream und <strong>de</strong>n FilterOutputStream<br />
haben <strong>de</strong>shalb InputStream- und OutputStream-Objekte als Parameter:<br />
protected FilterInputStream(InputStream 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<br />
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 />
E<strong>in</strong>gabestrom. Die Metho<strong>de</strong><br />
getL<strong>in</strong>eNumber()<br />
und<br />
setL<strong>in</strong>eNumber(<strong>in</strong>t) können<br />
verwen<strong>de</strong>t wer<strong>de</strong>n<br />
PushbackInputStream Hat e<strong>in</strong>en Byte großen<br />
„Pushback“-Puffer, das letzte<br />
gelesene Zeichen kann <strong>in</strong> <strong>de</strong>n<br />
strom zurückgelegt wer<strong>de</strong>n.<br />
Abb.: „FilterInputStream“-Typen<br />
Nützliche Subklassen von FilterOutputStream s<strong>in</strong>d:<br />
Angabe <strong>de</strong>r Puffergröße<br />
InputStream<br />
Fügt e<strong>in</strong>e Zeilennummerierung<br />
h<strong>in</strong>zu<br />
InputStream<br />
Braucht <strong>de</strong>r <strong>Java</strong>-Compiler<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 />
Formatierte Ausgabe<br />
BufferedOutputStream<br />
Abb.: „FilterOutputStream“-Typen<br />
Gepufferte Ströme<br />
Gepufferte Ausgabe, <strong>de</strong>r Puffer<br />
kann mit flush() geleert wer<strong>de</strong>n<br />
OutputStream<br />
Gepufferte Ausgabe<br />
Gepufferte Ströme wer<strong>de</strong>n mit <strong>de</strong>r 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 />
472
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Klasse BufferedInputStream implementiert die vollen Fähigkeiten <strong>de</strong>r<br />
InputStream-Metho<strong>de</strong>n, 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 <strong>de</strong>r<br />
OutputStream-Metho<strong>de</strong>n, 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-Metho<strong>de</strong> auf, wenn ihr Puffer voll ist o<strong>de</strong>r wenn flush<br />
aufgerufen wird.<br />
Datenströme<br />
Die Filter DataInputStream und DataOutputStream s<strong>in</strong>d nützliche Filter <strong>de</strong>s<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 />
<strong>de</strong>f<strong>in</strong>iert Metho<strong>de</strong>n zum Lesen von primitiven Datentypen <strong>in</strong> <strong>Java</strong> (sowie noch e<strong>in</strong><br />
paar weitere Metho<strong>de</strong>n).<br />
DataOutputStream implementiert e<strong>in</strong>e DataOutput-Schnittstelle mit Ausgabe-<br />
Metho<strong>de</strong>n, die <strong>de</strong>n E<strong>in</strong>gabe-Metho<strong>de</strong>n <strong>de</strong>r DataInput-Schnittstelle entsprechen.<br />
Die Konstruktoren zu <strong>de</strong>n DataInputStream- und DataOutputStream-Klassen<br />
s<strong>in</strong>d Stromfilter-Konstruktoren, die <strong>de</strong>n zu filtern<strong>de</strong>n Strom als Parameter verwen<strong>de</strong>n:<br />
public DataInputStream (InputStream e<strong>in</strong>)<br />
public DataOutputStream(OutputStream aus)<br />
Die Schnittstelle DataInput. Sie enthält Metho<strong>de</strong>n zum Lesen primitiver Typen:<br />
public boolean readBoolean() throws EOFException, IOException<br />
public byte readByte() throws EOFException, IOException<br />
public <strong>in</strong>t readUnsignedByte() throws EOFException, IOException<br />
public char readChar() throws EOFException, IOException<br />
public short readShort() throws EOFException, IOException<br />
public <strong>in</strong>t readUnsignedShort() throws EOFException, IOException<br />
public <strong>in</strong>t readInt() throws EOFException, IOException<br />
public long readLong() throws EOFException, IOException<br />
public float readFloat() throws EOFException, IOException<br />
public double readDouble() throws EOFException, IOException<br />
public Str<strong>in</strong>g readUTF() throws EOFException, IOException 337 ,<br />
UTFDataFormatException<br />
Ausgeworfene Ausnahmen s<strong>in</strong>d vom Typ IOException o<strong>de</strong>r EOFException.<br />
EOFException wird ausgeworfen, wenn das En<strong>de</strong> <strong>de</strong>s Stroms erreicht wird. Die<br />
Ausnahme läßt sich überall e<strong>in</strong>setzen, wo bisher auf „-1“ überprüft wur<strong>de</strong>.<br />
Zum Lesen e<strong>in</strong>er durch Zeilenumschaltung (\r, \n) begrenzten Zeile aus e<strong>in</strong>er<br />
Textdateigibt es die Metho<strong>de</strong>: public Str<strong>in</strong>g readL<strong>in</strong>e() throws<br />
IOException. „\r, \n, \r\n“ wer<strong>de</strong>n entfernt, bevor die Zeile als Zeichenkette<br />
wie<strong>de</strong>rgegeben wird.<br />
Bsp.: E<strong>in</strong>lesen von <strong>de</strong>r Standar<strong>de</strong><strong>in</strong>gabe und Ausgabe<br />
337 UTF (Unico<strong>de</strong> Transmission Format) ist e<strong>in</strong> spezielles Format zum Kodieren von 16-Bit-Unico<strong>de</strong>-Werten<br />
473
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Mit <strong>de</strong>r Metho<strong>de</strong> 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 folgen<strong>de</strong> Metho<strong>de</strong>n zur<br />
Ausgabe primitiver Typen <strong>de</strong>f<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 <strong>de</strong>n Metho<strong>de</strong>n<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 o<strong>de</strong>r Zeichen abgelegt wer<strong>de</strong>n.<br />
Die Pr<strong>in</strong>tStream-Klasse<br />
Der „System.out“-Strom mit <strong>de</strong>n Metho<strong>de</strong>n „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 />
existieren<strong>de</strong>n Ausgabestrom angehangen wer<strong>de</strong>n. Über e<strong>in</strong>en optionalen Parameter<br />
kann automatisch die Metho<strong>de</strong> flush() aufgerufen wer<strong>de</strong>n:<br />
public Pr<strong>in</strong>tStream(OutputStream aus)<br />
public Pr<strong>in</strong>tStream(OutputStream aus, boolean autoFlush)<br />
Metho<strong>de</strong> für die Ausgabe von Objekten.<br />
public void flush()<br />
public void close()<br />
public 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(boolean 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(boolean 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 />
474
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.3 Die Klasse File<br />
E<strong>in</strong> File-Objekt kann sich auf e<strong>in</strong>e Datei o<strong>de</strong>r e<strong>in</strong> Verzeichnis beziehen und läßt<br />
sich auf verschie<strong>de</strong>ne 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 wur<strong>de</strong>.<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 <strong>de</strong>m <strong>in</strong> date<strong>in</strong>ame angegebenen Date<strong>in</strong>amen und <strong>de</strong>m <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 <strong>de</strong>m <strong>in</strong> date<strong>in</strong>ame angegebenen Date<strong>in</strong>amen und <strong>de</strong>m <strong>in</strong><br />
verzeichnis angegebenen Verzeichnis zusammensetzt.<br />
Die Klasse File (class java.io.File implements Serializable,<br />
Comparable) umfaßt Metho<strong>de</strong>n zum Bearbeiten von Dateien bzw. Verzeichnissen.<br />
Nach<strong>de</strong>m e<strong>in</strong> File-Objekt erzeugt wur<strong>de</strong>, können Metho<strong>de</strong>n zum Zugriff auf die<br />
e<strong>in</strong>zelnen Bestandteile <strong>de</strong>s Date<strong>in</strong>amens aufgerufen wer<strong>de</strong>n:<br />
public Str<strong>in</strong>g getName();<br />
// liefert <strong>de</strong>n Namen <strong>de</strong>r Datei<br />
public Str<strong>in</strong>g getPath();<br />
// liefert <strong>de</strong>n kompletten Namen (Datei o<strong>de</strong>r Verzeichnis)<br />
public Str<strong>in</strong>g getAbsolutePath();<br />
// liefert <strong>de</strong>n absoluten Pfadnamen für das File-Objekt<br />
public Str<strong>in</strong>g getParent();<br />
Die Metho<strong>de</strong>n<br />
public boolean isFile()<br />
public boolean isDirectory()<br />
überprüfen, ob e<strong>in</strong>e Datei o<strong>de</strong>r e<strong>in</strong> Verzeichnis vorliegt. Mit<br />
public boolean canRead()<br />
public boolean canWrite()<br />
wird Lese- bzw. Schreiberlaubnis überprüft. Die Metho<strong>de</strong><br />
public long lastModified()<br />
zeigt an, wann die Datei bzw. das Verzeichnis geän<strong>de</strong>rt wur<strong>de</strong>. Mit<br />
public boolean exists()<br />
wird die physikalische Existenz e<strong>in</strong>er Datei o<strong>de</strong>r e<strong>in</strong>es Verzeichnisses überprüft. Über<br />
public Str<strong>in</strong>g getName()<br />
wird <strong>de</strong>r Name e<strong>in</strong>er Datei bzw. e<strong>in</strong>es Verzeichnisses ermittelt.<br />
Wur<strong>de</strong> e<strong>in</strong> File-Objekt für e<strong>in</strong> Verzeichnis konstruiert, stehen folgen<strong>de</strong> Metho<strong>de</strong>n zur<br />
Verfügung:<br />
public Str<strong>in</strong>g[] list();<br />
liefert e<strong>in</strong>en Array von Str<strong>in</strong>gs, <strong>de</strong>r für je<strong>de</strong>n gefun<strong>de</strong>nen Verzeichnise<strong>in</strong>trag e<strong>in</strong><br />
Element enthält. Die Liste enthält <strong>de</strong>n Namen aller Dateien und Unterverzeichnisse<br />
mit Ausnahme von „.“ und „..“. Die e<strong>in</strong>fache Funktion list() liefert nur relative<br />
475
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Pfa<strong>de</strong> (Date<strong>in</strong>ame o<strong>de</strong>r Verzeichnisname). Komplette File-Objekte beschafft die<br />
Metho<strong>de</strong> listFiles), die ihre vollständige Pfadangabe kennen. Der vollständige Pfad<br />
kann dann mit getName() erfragt wer<strong>de</strong>n.<br />
In e<strong>in</strong>er Variante von list() kann die Auswahl <strong>de</strong>r Verzeichnise<strong>in</strong>träge<br />
e<strong>in</strong>geschränkt wer<strong>de</strong>n. Es muß aber dann e<strong>in</strong> Objekt übergeben wer<strong>de</strong>n, das das<br />
Interface FilenameFilter implementiert. Dieses besitzt die Metho<strong>de</strong> accept 338 ,<br />
die für je<strong>de</strong> gefun<strong>de</strong>ne Datei aufgerufen wird und entschei<strong>de</strong>t, ob sie <strong>in</strong> die Liste<br />
aufgenommen wer<strong>de</strong>n soll o<strong>de</strong>r nicht. Zusätzlich gibt es die statische Metho<strong>de</strong><br />
listRoots, mit <strong>de</strong>r e<strong>in</strong>e Liste <strong>de</strong>r Wurzeln verfügbarer Dateisysteme beschafft<br />
wer<strong>de</strong>n kann.<br />
public static File[] listRoots()<br />
liefert die verfügbaren Wurzeln <strong>de</strong>r Dateisysteme o<strong>de</strong>r null, falls diese nicht<br />
festgestellt wer<strong>de</strong>n konnten.<br />
Neben <strong>de</strong>m Zugriff auf Verzeichnise<strong>in</strong>träge gibt es Metho<strong>de</strong>n 339 für Löschen,<br />
Umbenennen von Dateien bzw. Verzeichnissen und für das Neuanlegen von<br />
Verzeichnissen.<br />
public boolean mkdir()<br />
// Anlegen <strong>de</strong>s spezifizierten Verzeichnisses<br />
public boolean mkdirs()<br />
// auch "Vater"-Verzeichnisse wer<strong>de</strong>n automatisch angelegt.<br />
public boolean renameTo(File ziel)<br />
public boolean <strong>de</strong>lete();<br />
// löscht die durch das File-Objekt bezeichnete Datei<br />
Da es bei URL-Objekten häufig vorkommt, daß e<strong>in</strong>e Datei die Basis ist, wur<strong>de</strong> ab<br />
Version 1.2 von <strong>Java</strong> die Metho<strong>de</strong> toURL() aufgenommen:<br />
public URL toURL() throws MalformedURLException<br />
// liefert e<strong>in</strong> URL-Objekt vom File-Objekt<br />
Es muß e<strong>in</strong> File-Objekt erzeugt wer<strong>de</strong>n. Anschließend erzeugt toURL() e<strong>in</strong> URL-<br />
Objekt, das das Protokoll „file“ trägt und danach e<strong>in</strong>e absolute Pfadangabe zur Datei<br />
bzw. zum Verzeichnis enthält.<br />
338 public boolean accept(File verzeichnis, Str<strong>in</strong>g dateiName)<br />
339 Alle Metho<strong>de</strong>n geben true zurück, wenn sie ihre Aufgabe erfolgreich ausführen konnten; an<strong>de</strong>renfalls geben<br />
sie false zurück<br />
476
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.4 Die RandomAccessFile-Klasse<br />
Für <strong>de</strong>n Zugriff auf Random-Access-Dateien stellt das Paket java.io die Klasse<br />
RandomAccessFile zur Verfügung. Es kann nur auf Dateien zugegriffen wer<strong>de</strong>n,<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 <strong>de</strong>n Konstruktoren:<br />
public RandomAccessFile(File datei, Str<strong>in</strong>g mo<strong>de</strong>) throws<br />
FileNotFoundException<br />
Bei <strong>de</strong>r Übergabe <strong>de</strong>s File-Objekts wird die durch dieses Objekt spezifizierte Datei<br />
geöffnet.<br />
public RandomAccessFile(Str<strong>in</strong>g name, Str<strong>in</strong>g mo<strong>de</strong>) throws<br />
FileNotFoundException<br />
Bei <strong>de</strong>r Übergabe <strong>de</strong>s Str<strong>in</strong>g-Parametres „name“ wird die Datei mit diesem Namen<br />
geöffnet. Der zweite Parameter mo<strong>de</strong> bestimmt die Art <strong>de</strong>s 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> <strong>de</strong>r Klasse RandomAccessFile ke<strong>in</strong>e explizite Differenzierung zwischen<br />
Öffnen <strong>de</strong>r Datei und Neuanlegen. Implizit gilt: E<strong>in</strong>e Datei wird neu angelegt, wenn<br />
beim Öffnen im Modus „w“ nicht vorhan<strong>de</strong>n ist. Existiert die Datei bereits, wird sie<br />
unverän<strong>de</strong>rt geöffnet, und es gibt ke<strong>in</strong>e Möglichkeit, ihren Inhalt zu löschen o<strong>de</strong>r die<br />
Dateilänge auf e<strong>in</strong>en bestimmten Wert zusetzen.<br />
Das Schliessen erfolgt durch Aufruf <strong>de</strong>r parameterlosen Metho<strong>de</strong> close.<br />
Positionieren <strong>de</strong>s Dateizeigers. Je<strong>de</strong>r Schreib- und Lesezugriff erfolgt an <strong>de</strong>r<br />
Position, die durch <strong>de</strong>n aktuellen Inhalt <strong>de</strong>s Satzzeigers bestimmt wird und<br />
positioniert <strong>de</strong>n Zeiger um die Anzahl gelesener bzw. geschriebener Bytes weiter.<br />
Die Klasse RandomAccessFile stellt e<strong>in</strong>e Reihe von Metho<strong>de</strong>n zum Zugriff auf <strong>de</strong>n<br />
Satzzeiger zur Verfügung.<br />
Die Metho<strong>de</strong> seek. Die RandomAccessFile-Klasse besitzt alle Metho<strong>de</strong>n, die <strong>in</strong><br />
<strong>de</strong>n Schnittstellen DataInput und DataOutput verfügbar s<strong>in</strong>d. Mit public void<br />
seek(long dateiPosition) throws IOException kann man an je<strong>de</strong><br />
beliebige Position <strong>de</strong>r Datei spr<strong>in</strong>gen. Mit <strong>de</strong>r Metho<strong>de</strong> public long<br />
getFilePo<strong>in</strong>ter() throws IOException kann die <strong>de</strong>rzeitige Dateiposition 340<br />
bestimmt wer<strong>de</strong>n.<br />
Weiterh<strong>in</strong> stehen lesen<strong>de</strong> und schreiben<strong>de</strong> Zugriffsmetho<strong>de</strong>n zur Verfügung.<br />
340 Der Dateipositionswert <strong>in</strong> <strong>de</strong>n Metho<strong>de</strong>n seek und getFilePo<strong>in</strong>ter() ist die Anzahl <strong>de</strong>r Bytes vom<br />
Anfang bis zum En<strong>de</strong> <strong>de</strong>r Datei.<br />
477
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
RandomAccessFile<br />
<br />
public RandomAccessFile(File datei, Str<strong>in</strong>g zugriffsmodus) throws FileNotFoundException;<br />
// erzeugt e<strong>in</strong>en Random-Access-Datei-Strom vom File-Objekt.<br />
// Ob aus <strong>de</strong>r datei gelesen o<strong>de</strong>r geschrieben wird, bestimmt<br />
// e<strong>in</strong> Str<strong>in</strong>g, <strong>de</strong>r <strong>de</strong>n Modus angibt: „r“, „w“ o<strong>de</strong>r „rw“.<br />
public RandomAccessFile(Str<strong>in</strong>g datei, Str<strong>in</strong>g zugriffsmodus) throws FileNotFoundException;<br />
><br />
public long getFilePo<strong>in</strong>ter() throws IOException;<br />
publc void seek(long pos) throws IOException;<br />
// setzt <strong>de</strong>n Dateizeiger – bezogen auf <strong>de</strong>n Dateianfang – auf e<strong>in</strong>e<br />
// bestimmte Stelle, an <strong>de</strong>r <strong>de</strong>r nächste Lese- und Schreibzugriff<br />
// stattf<strong>in</strong><strong>de</strong>t<br />
public <strong>in</strong>t skipBytes(<strong>in</strong>t n) throws IOException;<br />
public long length() throws IOException;<br />
public f<strong>in</strong>al boolean readBoolean() throws IOException;<br />
public f<strong>in</strong>al byte readByte() throws IOException;<br />
public f<strong>in</strong>al char readChar() throws IOException;<br />
public f<strong>in</strong>al double readDouble() throws IOException;<br />
public f<strong>in</strong>al float readFloat() throws IOException;<br />
public f<strong>in</strong>al <strong>in</strong>t readInt() throws IOException;<br />
public f<strong>in</strong>al long readLong() throws IOException;<br />
public f<strong>in</strong>al short readShort() throws IOException;<br />
public f<strong>in</strong>al Str<strong>in</strong>g readUTF() throws IOException;<br />
public f<strong>in</strong>al void readFully(byte b[]) throws IOException;<br />
public f<strong>in</strong>al void readFully(byte[], <strong>in</strong>t off, <strong>in</strong>t laenge) throws IOException;<br />
public f<strong>in</strong>al Str<strong>in</strong>g readL<strong>in</strong>e() throws IOException;<br />
public f<strong>in</strong>al <strong>in</strong>t readUnsignedByte() throws IOException;<br />
public f<strong>in</strong>al <strong>in</strong>t readUnsignedShort() throws IOException;<br />
public <strong>in</strong>t read() throws IOException;<br />
public <strong>in</strong>t read(byte b[]) throws IOException;<br />
public <strong>in</strong>t read(byte b[], <strong>in</strong>t off, <strong>in</strong>t laenge) throws IOException;<br />
public f<strong>in</strong>al void writeBoolean(boolean w) throws IOException;<br />
public f<strong>in</strong>al void writeByte(<strong>in</strong>t w) throws IOException;<br />
public f<strong>in</strong>al void writeBytes(Str<strong>in</strong>g s) throws IOException;<br />
public f<strong>in</strong>al void writeChar(<strong>in</strong>t w) throws IOException;<br />
public f<strong>in</strong>al void writeChars(Str<strong>in</strong>g s) throws IOException;<br />
public f<strong>in</strong>al void writeDouble(double w) throws IOException;<br />
public f<strong>in</strong>al void writeFloat(float w) throws IOException;<br />
public f<strong>in</strong>al void writeInt(<strong>in</strong>t w) throws IOException;<br />
public f<strong>in</strong>al void writeLong(long w) throws IOException;<br />
public f<strong>in</strong>al void writeShort(<strong>in</strong>t w) throws IOException;<br />
public f<strong>in</strong>al void writeUTF(Str<strong>in</strong>g str) throws IOException;<br />
public void write(<strong>in</strong>t b) throws IOException;<br />
public void write(byte b[]) throws IOException;<br />
public void write(byte b[], <strong>in</strong>t off, <strong>in</strong>t laenge) throws IOException;<br />
Abb.: Die Klasse RandomAccessFile<br />
478
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.5 Die Klasse StreamTokenizer<br />
Die Klasse StreamTokenizer arbeitet im Gegensatz zum Str<strong>in</strong>gTokenizer aus<br />
<strong>de</strong>m Paket java.util auf e<strong>in</strong>em Datenstrom, genauer auf e<strong>in</strong>em Rea<strong>de</strong>r. Sie<br />
beachtet ke<strong>in</strong>e Unico<strong>de</strong>-E<strong>in</strong>gabe, son<strong>de</strong>rn nur Zeichen aus <strong>de</strong>m Bereich von \u0000<br />
bid \u00FF. Wahrend <strong>de</strong>s Parsens wer<strong>de</strong>n bestimmte Merkmale aus <strong>de</strong>m Text<br />
erkannt, so u. a. I<strong>de</strong>ntifier (etwa Schlüsselworte), Zahlen, Str<strong>in</strong>gs <strong>in</strong><br />
Anführungszeichen und verschie<strong>de</strong>ne Kommentararten (C-Stil o<strong>de</strong>r C++-Stil). Der<br />
Erkennungsvorgang wird anhand e<strong>in</strong>er Syntaxtabelle überprüft. Diese Tabelle enthält<br />
bspw. die Zeichen, die e<strong>in</strong> Schlüsselwort i<strong>de</strong>ntifizieren o<strong>de</strong>r die Zeichen, die<br />
Trennzeichen s<strong>in</strong>d. Je<strong>de</strong>s gelesene Zeichen wird dann ke<strong>in</strong>em, e<strong>in</strong>em o<strong>de</strong>r mehreren<br />
Attributen zugeordnet. Diese Attribute fallen <strong>in</strong> die Kategorie Trennzeichen,<br />
alphanumerische Zeichen, Zahlen, Hochkomma bzw. Anführungszeichen.<br />
Zur Benutzung <strong>de</strong>r Klasse wird zunächst e<strong>in</strong> StreamTokenizer-Objekt erzeugt und<br />
dann die Syntaxtabellen <strong>in</strong>itialisiert. Das Überlesen von Kommentarzeilen wird durch<br />
st.slashSlashComments(true); // Kommentar<br />
st.slashStarComments(true); /* Kommentart */<br />
gesteuert. Die erste Metho<strong>de</strong> überliest im E<strong>in</strong>gabestrom alle Zeichen bis zum Return.<br />
Die zweite Metho<strong>de</strong> überliest alles bis zum Stern / Slash.<br />
Beim Lesen <strong>de</strong>s Datenstroms mit nextToken() kann über bestimmte Flags erfragt<br />
wer<strong>de</strong>n, ob im Stream e<strong>in</strong> Wort (TT_WORD) e<strong>in</strong>e Zahl (TT_NUMBER), das En<strong>de</strong> <strong>de</strong>r<br />
Datei (TT_EOF) o<strong>de</strong>r das En<strong>de</strong> <strong>de</strong>r Zeile (TT_EOL) vorliegt. Wichtig ist<br />
eolIsSignificant(true) zu setzen, da an<strong>de</strong>rnfalls <strong>de</strong>r StreamTokenizer nie e<strong>in</strong><br />
TT_EOL f<strong>in</strong><strong>de</strong>t. Wur<strong>de</strong> e<strong>in</strong> Wort erkannt, dann wer<strong>de</strong>n alle Zeichen <strong>in</strong><br />
Kle<strong>in</strong>buchstaben konvertiert.<br />
Bsp. 341 : StreamTokenizerDemo.java<br />
import java.io.*;<br />
public class StreamTokenizerDemo<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]) throws IOException<br />
{<br />
Str<strong>in</strong>g fn = "StreamTokenizerDemo.java";<br />
StreamTokenizer st = new StreamTokenizer(new FileRea<strong>de</strong>r(fn));<br />
st.slashSlashComments(true);<br />
st.ord<strong>in</strong>aryChar('/');<br />
st.parseNumbers();<br />
st.eolIsSignificant(true);<br />
<strong>in</strong>t tval;<br />
while ((tval = st.nextToken()) != st.TT_EOF)<br />
{<br />
if (tval == st.TT_NUMBER)<br />
System.out.pr<strong>in</strong>tln("Nummer: " + st.nval);<br />
else if (tval == st.TT_WORD)<br />
System.out.pr<strong>in</strong>tln("Wort: " + st.sval);<br />
else if (tval == st.TT_EOL)<br />
System.out.pr<strong>in</strong>tln("En<strong>de</strong> <strong>de</strong>r Zeile");<br />
else System.out.pr<strong>in</strong>tln("Zeichen: " + (char) st.ttype);<br />
}<br />
}<br />
}<br />
341 vgl. pr75100<br />
479
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
480
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
class java.io.StreamTokenizer<br />
><br />
StreamTokenizer(Rea<strong>de</strong>r r)<br />
><br />
public void resetSyntax<br />
// Re<strong>in</strong>itialisiert die Syntaxtabelle <strong>de</strong>s Tokenizers, so dass ke<strong>in</strong> Zeichen e<strong>in</strong>e So<strong>de</strong>rstellung<br />
// geniesst.<br />
public void wordChars(<strong>in</strong>t low, <strong>in</strong>t hi)<br />
// Zeichen im Bereich von low bis hi wer<strong>de</strong>n als Trennzeichen erkannt<br />
public void whitespaceChars(<strong>in</strong>t low, <strong>in</strong>t hi)<br />
// Zeichen im Bereich von low bis hi wer<strong>de</strong>n als Trennzeichen erkannt.<br />
public void ord<strong>in</strong>aryChars(<strong>in</strong>t low, <strong>in</strong>t hi)<br />
// Zeichen im Bereich von low bis hi geniessen ke<strong>in</strong>e Son<strong>de</strong>rbehandlung, wer<strong>de</strong>n als<br />
// normale zeichen behan<strong>de</strong>lt.<br />
public void ord<strong>in</strong>aryChar(<strong>in</strong>t ch)<br />
// Das Zeichen besitzt ke<strong>in</strong>e zusätzliche Funktion, ist bspw. ke<strong>in</strong> Kommentarzeichen,<br />
// trennsymbol o<strong>de</strong>r Nummernzeichen<br />
public void parseNumbers()<br />
// Nummern sollen vom Tokenizer erkannt wer<strong>de</strong>n. In <strong>de</strong>r Syntaxtabelle gelten die 12<br />
// Zeichen 0, 1, 2, 3, 4, 5, 6., 7, 8, 9, ., - als numerisch. Liegt e<strong>in</strong> Gleipunktzahl an,<br />
// so wird <strong>de</strong>r Vorkommateil <strong>in</strong> nval abgelegt und das Token ergibt im Attribut ttype<br />
// <strong>de</strong>n Wert TT_NUMBER<br />
public void commentChar(<strong>in</strong>t ch)<br />
// Gibt das Zeichen an, das e<strong>in</strong>en e<strong>in</strong>zeiligen Kommentar e<strong>in</strong>leitet<br />
public void slashStarComments(boolean flag)<br />
// Der Tokenizer soll Kommentare im C-Stil (/* .. */) erkennen o<strong>de</strong>r nicht<br />
public void slashSlashComments(boolean flag)<br />
// Der Tokenizer soll Kommentare im C++-Stil (// ..) erkennen o<strong>de</strong>r nicht<br />
public void lowerCaseMo<strong>de</strong>(boolean fl)<br />
// liegt <strong>in</strong> ttype e<strong>in</strong> Token vom Typ TT_WORD vor, so wird das automatisch <strong>in</strong><br />
// Kle<strong>in</strong>schreibweise konvertiert, falls fi gleich true ist<br />
public <strong>in</strong>t nextToken() throws IOException<br />
// liefert das nächste Token im Strom. Der Typ <strong>de</strong>s Token wird im Attribut ttype h<strong>in</strong>terlegt.<br />
// Zusätzliche Informationen bef<strong>in</strong><strong>de</strong>n sich im Attribut nval (Nummer) o<strong>de</strong>r sval (Zeichenkette).<br />
// In <strong>de</strong>r Regel wird solange geparst, bis das Token TT_EOF zurückgegeben wird.<br />
public void pushBack()<br />
// Der Aufruf von nextToken() liefert <strong>de</strong>n aktuellen wert im Attribut ttype und än<strong>de</strong>rt nval o<strong>de</strong>r sval<br />
// nicht<br />
public <strong>in</strong>t l<strong>in</strong>eno()<br />
// liefert die Zeilennummer<br />
Abb.: Die Klasse StreamTokenizer<br />
481
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.6 Klassen für spezielle nützliche Ströme<br />
Die L<strong>in</strong>eInputStream-Klasse<br />
Die SequenceInputStream-Klasse<br />
Die PushbackInputStream-Klasse<br />
482
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.7 <strong>Java</strong> 1.1 IO-Ströme<br />
7.7.1 Grundlagen<br />
Bis zur Version 1.0 <strong>de</strong>s JDK gab es nur Byte-Streams <strong>in</strong> <strong>Java</strong>. Das ergab<br />
Schwierigkeiten bei <strong>de</strong>r Umwandlung zwischen Bytes und 16 Bit langen Unico<strong>de</strong>-<br />
Zeichen, die <strong>in</strong>nerhalb von <strong>Java</strong> benutzt wer<strong>de</strong>n. Im JDK 1.1. wur<strong>de</strong>n daher<br />
„Character“-Streams auf <strong>de</strong>r Basis von 16 Bit langen Unico<strong>de</strong>-Zeichen e<strong>in</strong>geführt.<br />
Die Kompatibilität wur<strong>de</strong> 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 Korrespondieren<strong>de</strong> Klassen <strong>in</strong> <strong>Java</strong> 1.1<br />
InputStream<br />
Rea<strong>de</strong>r<br />
Konverter: InputStreamRea<strong>de</strong>r<br />
OutputStream<br />
Writer<br />
Konverter: OutputStreamWriter<br />
FileInputStream<br />
FileRea<strong>de</strong>r<br />
FileOutputStream<br />
FileWriter<br />
Str<strong>in</strong>gBufferInputStream<br />
Str<strong>in</strong>gRea<strong>de</strong>r<br />
Str<strong>in</strong>gWriter<br />
ByteArrayInputStream<br />
CharArrayRea<strong>de</strong>r<br />
ByteArrayOutputStream<br />
CharArrayWriter<br />
PipedInputStream<br />
PipedRea<strong>de</strong>r<br />
PipedOutputStream<br />
PipedWriter<br />
Abb. Wichtige Klassen zur E<strong>in</strong>gabe<br />
In Filterklassen kann nur e<strong>in</strong>e etwas gröbere Zuordnung von Klassen aus <strong>Java</strong> 1.0 zu<br />
<strong>Java</strong> 1.1 angegeben wer<strong>de</strong>n. So ist „BufferedOutputStream“ e<strong>in</strong>e Subklasse von<br />
FilterOutputStream, BufferedWriter ist dagegen ke<strong>in</strong>e Subklasse von<br />
FilterWriter.<br />
Filter: Klassen <strong>in</strong> <strong>Java</strong> 1.0 Korrespondieren<strong>de</strong> Klassen <strong>in</strong> <strong>Java</strong> 1.1<br />
FilterInputStream<br />
FilterRea<strong>de</strong>r<br />
FilterOutputStream<br />
FilterWriter (abstrakte Klasse ohne Subklassen)<br />
BufferedInputStream<br />
BufferedRea<strong>de</strong>r (mit readL<strong>in</strong>e)<br />
BufferedOutputStream<br />
BufferedWriter<br />
DataInputStream<br />
DataInputStream, bei readL<strong>in</strong>e() BufferedRea<strong>de</strong>r<br />
verwen<strong>de</strong>n<br />
Pr<strong>in</strong>tStream<br />
Pr<strong>in</strong>tWriter<br />
L<strong>in</strong>eNumberInputStream<br />
L<strong>in</strong>eNumberRea<strong>de</strong>r<br />
StreamTokenizer<br />
StreamTokenizer<br />
PushbackInputStream<br />
PushbackRea<strong>de</strong>r<br />
Abb. Wichtige Klassen zur Ausgabe<br />
E<strong>in</strong>ige Klassen bleiben von <strong>de</strong>r Umstellung unberührt: DataOutputStream, File,<br />
RandomAccessFile, SequenceInputStream.<br />
483
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.7.2 Die abstrakte Klassen Rea<strong>de</strong>r und ihre Ableitungen<br />
Basis aller sequentiellen E<strong>in</strong>gaben ist die abstrakte Klasse Rea<strong>de</strong>r, 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.Rea<strong>de</strong>r<br />
{<br />
protected Rea<strong>de</strong>r();<br />
public abstract void close() throws IOException;<br />
// schliesst <strong>de</strong>n E<strong>in</strong>gabestrom<br />
public void mark(<strong>in</strong>t readAheadlimit) throws IOException;<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() throws IOException;<br />
// liest das nächste Zeichen aus <strong>de</strong>m E<strong>in</strong>gabestrom und liefert es als<br />
// "<strong>in</strong>t". Der Rückgabewert –1 kennzeichnet das En<strong>de</strong> <strong>de</strong>s E<strong>in</strong>gabestroms<br />
public <strong>in</strong>t read(char cbuf[]) throws IOException;<br />
// übernimmt e<strong>in</strong>e Reihe von Zeichen <strong>in</strong> <strong>de</strong>n als Parameter angegebenen<br />
// Array<br />
public abstract <strong>in</strong>t read(char cbuf[], <strong>in</strong>t off, <strong>in</strong>t len) throws IOException;<br />
// übernimmt e<strong>in</strong>e Reihe von zeichen <strong>in</strong> e<strong>in</strong>en Bereich <strong>de</strong>s Puffers, <strong>de</strong>r<br />
// durch Versatz (Offset) und die gewünschte Länge gekennzeichnet ist<br />
public long skip(long n) throws IOException;<br />
// überliest Zeichen im E<strong>in</strong>gabestrom<br />
public boolean ready() throws IOException;<br />
// liefert True, falls <strong>de</strong>r nächste Aufruf von read erfolgen kann, ohne<br />
// daß die E<strong>in</strong>gabe been<strong>de</strong>t ist<br />
public void reset() throws IOException;<br />
// setzt <strong>de</strong>n Lesezeiger an die markierte Stelle zurück<br />
}<br />
Von <strong>de</strong>r abstrakten Basisklasse Rea<strong>de</strong>r können ke<strong>in</strong>e Instanzen abgeleitet wer<strong>de</strong>n.<br />
Es gibt e<strong>in</strong>e Reihe aus Rea<strong>de</strong>r 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<br />
InputStreamRea<strong>de</strong>r<br />
FileRea<strong>de</strong>r<br />
PushbackRea<strong>de</strong>r<br />
BufferedRea<strong>de</strong>r<br />
L<strong>in</strong>eNumberRea<strong>de</strong>r<br />
Str<strong>in</strong>gRea<strong>de</strong>r<br />
CharArrayRea<strong>de</strong>r<br />
PipedRea<strong>de</strong>r<br />
Be<strong>de</strong>utung<br />
Abstrakte Klasse für alle Rea<strong>de</strong>r, die e<strong>in</strong>en Byte-<br />
Strom <strong>in</strong> e<strong>in</strong>en Character-Strom umwan<strong>de</strong>ln<br />
Konkrete Ableitung von InputStreamRea<strong>de</strong>r zum<br />
E<strong>in</strong>lesen e<strong>in</strong>er Datei<br />
E<strong>in</strong>gabefilter mit <strong>de</strong>r Möglichkeit zur Rückgabe<br />
von Zeichen<br />
Rea<strong>de</strong>r zur E<strong>in</strong>gabepufferung und zum Lesen<br />
kompletter Zeilen<br />
Ableitung von BufferedRea<strong>de</strong>r mit <strong>de</strong>r Fähigkeit<br />
zum Zählen von Zeilen<br />
Rea<strong>de</strong>r zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />
Str<strong>in</strong>g<br />
Rea<strong>de</strong>r zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />
Zeichen-Array<br />
Rea<strong>de</strong>r zum E<strong>in</strong>lesen von Zeichen aus e<strong>in</strong>em<br />
PipedWriter<br />
Abb.: Von Rea<strong>de</strong>r abgeleitete Klassen<br />
InputStreamRea<strong>de</strong>r<br />
Diese Klasse konvertiert Byte- <strong>in</strong> Character-Streams.<br />
484
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
FileRea<strong>de</strong>r<br />
Sie ermöglicht die E<strong>in</strong>gabe e<strong>in</strong>er Datei. Die Klasse FileRea<strong>de</strong>r geht direkt aus e<strong>in</strong>em<br />
InputStreamRea<strong>de</strong>r hervor.<br />
Konstruktoren. Mit ihnen ermöglicht FileRea<strong>de</strong>r das Öffnen von Dateien:<br />
public FileRea<strong>de</strong>r(Str<strong>in</strong>g dateiName) throws FileNotFoundException;<br />
Bei Übergabe <strong>de</strong>r Zeichenkette dateiName wird die Datei mit <strong>de</strong>m angegebenen<br />
Namen zum Lesen geöffnet. Falls sie nicht vorhan<strong>de</strong>n ist, kommt es zur Ausnahme<br />
<strong>de</strong>s Typs FileNotFoundException<br />
public FileRea<strong>de</strong>r(File datei) throws FileNotFoundException;<br />
erwartet e<strong>in</strong> File-Objekt zur Spezifikation e<strong>in</strong>er zu öffnen<strong>de</strong>n Datei.<br />
public FileRea<strong>de</strong>r(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>gRea<strong>de</strong>r<br />
Diese Klasse erlaubt das Lesen von Zeichen aus e<strong>in</strong>em Str<strong>in</strong>g.<br />
CharArrayRea<strong>de</strong>r<br />
Diese Klasse erlaubt das Lesen von Zeichen aus e<strong>in</strong>en „Zeichen-Array“<br />
BufferedRea<strong>de</strong>r<br />
Diese Klasse dient zur Pufferung von E<strong>in</strong>gaben. BufferedRea<strong>de</strong>r implementiert die<br />
vollen Fähigkeiten <strong>de</strong>r Metho<strong>de</strong>n von Rea<strong>de</strong>r. Diese Klasse verwen<strong>de</strong>t dazu<br />
gepufferte Zeichen-Arrays.<br />
Konstruktoren: public BufferedRea<strong>de</strong>r(Rea<strong>de</strong>r e<strong>in</strong>)<br />
public BufferedRea<strong>de</strong>r(Rea<strong>de</strong>r e<strong>in</strong>, <strong>in</strong>t gr)<br />
Der erste Parameter ist e<strong>in</strong> Rea<strong>de</strong>r-Objekt, auf das e<strong>in</strong> BufferedRea<strong>de</strong>r aufgesetzt<br />
wer<strong>de</strong>n soll. Der optionale Parameter gr gibt die Größe <strong>de</strong>s <strong>in</strong>ternen Puffer an. Fehlt<br />
er, so wird e<strong>in</strong>e für die meisten Situationen angemessene Standar<strong>de</strong><strong>in</strong>stellung<br />
verwen<strong>de</strong>t.<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 <strong>de</strong>m Zeichen<strong>in</strong>halt (ohne Begrenzungszeichen) o<strong>de</strong>r<br />
„null“, falls das En<strong>de</strong> von „Stream“ erreicht wur<strong>de</strong>.<br />
L<strong>in</strong>eNumberRea<strong>de</strong>r<br />
Diese Klasse ist e<strong>in</strong>e Ableitung von BufferedRea<strong>de</strong>r, die zusätzlich noch die<br />
Anzahl <strong>de</strong>r 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 <strong>de</strong>r aktuelle Stand <strong>de</strong>s Zeilenzählers abgefragt. Mit<br />
public void setL<strong>in</strong>eNumber(<strong>in</strong>t L<strong>in</strong>eNumber) kann <strong>de</strong>r aktuelle Stand <strong>de</strong>s<br />
Zeilenzählers verän<strong>de</strong>rt wer<strong>de</strong>n.<br />
485
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.7.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 <strong>de</strong>s Ausgabestroms<br />
public abstract void close() throws IOException;<br />
// Schliessen <strong>de</strong>s Ausgabestroms<br />
public abstract void flush() throws IOException;<br />
// Leeren <strong>de</strong>r 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 />
// <strong>de</strong>r als Byte <strong>in</strong> <strong>de</strong>n Ausgabestrom geschrieben wird<br />
public void write(char e<strong>in</strong>Puffer[]) throws IOException;<br />
// Varianten von write, die e<strong>in</strong> Array von Bytes o<strong>de</strong>r e<strong>in</strong> Str<strong>in</strong>g-Objekt<br />
// erwarten und dieses durch Aufruf von write() ausgeben<br />
public abstract void write(char e<strong>in</strong>Puffer[], <strong>in</strong>t off, <strong>in</strong>t len) throws<br />
IOException;<br />
public void write(Str<strong>in</strong>g str) throws IOException;<br />
public void write(Str<strong>in</strong>g str, <strong>in</strong>t off, <strong>in</strong>t len) throws IOException;<br />
}<br />
Von <strong>de</strong>r abstrakten Basisklasse Writer können ke<strong>in</strong>e Instanzen abgeleitet wer<strong>de</strong>n.<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<br />
OutputStreamWriter<br />
FileWriter<br />
FilterWriter<br />
Pr<strong>in</strong>tWriter<br />
BufferedWriter<br />
Str<strong>in</strong>gWriter<br />
CharArrayWriter<br />
PipedWriter<br />
Be<strong>de</strong>utung<br />
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 umwan<strong>de</strong>ln<br />
Konkrete Ableitung von OutputStreamWriter zur Ausgabe e<strong>in</strong>er Datei<br />
Abstrakte Basisklasse für die Konstruktion von Ausgabefiltern<br />
Ausgabe aller Basistypen im Textformat<br />
Writer mit Ausgabepufferung<br />
Writer zur Ausgabe <strong>in</strong> e<strong>in</strong>em Str<strong>in</strong>g<br />
Writer zur Ausgabe im Zeichen-Array<br />
Writer zur Ausgabe <strong>in</strong> e<strong>in</strong>em PipedRea<strong>de</strong>r<br />
Abb.: Aus Writer abgeleitete Klassen<br />
Von <strong>de</strong>n abgeleiteten Klassen wird erwartet: Überlagerung <strong>de</strong>r Metho<strong>de</strong>n 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"-Metho<strong>de</strong><br />
e<strong>in</strong>es <strong>de</strong>rart geschachtelten "Writer" aufgerufen wird, gibt sie Daten nicht mehr<br />
direkt an <strong>de</strong>n <strong>in</strong>ternen "Writer", son<strong>de</strong>rn führt Filterfunktionen aus.<br />
OutputStreamWriter<br />
Diese Klasse übernimmt e<strong>in</strong>e Konvertierung zwischen Character- und Byte-Streams.<br />
486
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
FileWriter<br />
ermöglicht die Ausgabe <strong>in</strong> e<strong>in</strong>e Datei. Sie implementiert die abstrakten Eigenschaften<br />
von Writer. Die Klasse FileWriter bietet 4 Konstruktoren für das Öffnen von<br />
Dateien an:<br />
public FileWriter(Str<strong>in</strong>g dateiName) throws IOException<br />
Falls dateiName e<strong>in</strong>e bereits vorhan<strong>de</strong>ne Datei bezeichnet, wird sie geöffnet und ihr bisheriger Inhalt<br />
gelöscht, an<strong>de</strong>renfalls 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 <strong>de</strong>r Parameter append mit <strong>de</strong>m Wert true an <strong>de</strong>n Konstruktor übergeben, dann wer<strong>de</strong>n 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> <strong>de</strong>r 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 ero<strong>de</strong>rlich machen<br />
public Str<strong>in</strong>gWriter(<strong>in</strong>t <strong>in</strong>itialGroesse)<br />
Zugriffe: Die schreiben<strong>de</strong>n Zugriffe auf die Puffer erfolgen mit <strong>de</strong>n von Writer<br />
bekannten „write“-Metho<strong>de</strong>n. Für <strong>de</strong>n Zugriff auf <strong>de</strong>n Inhalt <strong>de</strong>s Puffers gibt es die<br />
Metho<strong>de</strong>n 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: Schreiben<strong>de</strong> Zugriffe erfolgen mit <strong>de</strong>n von „Writer“ bekannten „write“-<br />
Metho<strong>de</strong>n. Für <strong>de</strong>n Zugriff auf das Array gibt es die Metho<strong>de</strong>n public Str<strong>in</strong>g<br />
toStr<strong>in</strong>g() und public char[] toCharArray(). Mit <strong>de</strong>r Metho<strong>de</strong> public<br />
void reset() wird <strong>de</strong>r <strong>in</strong>terne Puffer geleert. Die Größe <strong>de</strong>s Zeichen-Array wird<br />
über public <strong>in</strong>t size() ermittelt. Durch Aufruf von public void<br />
writeTo(Writer aus) throws IOException kann <strong>de</strong>r Inhalt <strong>de</strong>s Array an<br />
e<strong>in</strong>en an<strong>de</strong>ren Writer übergeben wer<strong>de</strong>n 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 wer<strong>de</strong>n.<br />
BufferedWriter<br />
Die Klasse puffert „Stream“-Ausgaben über e<strong>in</strong>en <strong>in</strong>ternen Puffer, <strong>in</strong> <strong>de</strong>m die<br />
Ausgaben von write zwischengespeichert wer<strong>de</strong>n. Falls <strong>de</strong>r Puffer gefüllt ist o<strong>de</strong>r die<br />
Metho<strong>de</strong> flush aufgerufen wird, wer<strong>de</strong>n alle gepufferten Ausgaben <strong>in</strong> <strong>de</strong>n „Stream“<br />
geschrieben. Das Puffern <strong>de</strong>r Ausgabe ist immer dann nützlich, wenn die Ausgabe <strong>in</strong><br />
e<strong>in</strong>e Datei geschreiben wer<strong>de</strong>n soll. BufferedWriter besitzt zwei Konstruktoren:<br />
public BufferedWriter(Writer aus)<br />
public BufferedWriter(Writer aus, <strong>in</strong>t groesse)<br />
487
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
In bei<strong>de</strong>n Fällen wird e<strong>in</strong> existieren<strong>de</strong>r Writer übergeben, an <strong>de</strong>n alle gepufferten<br />
Ausgaben weitergereicht wer<strong>de</strong>n. Ist die Größe <strong>de</strong>s Puffers nicht explizit angegeben,<br />
legt BufferedWriter e<strong>in</strong>en Standardpuffer an.<br />
Die „write“-Metho<strong>de</strong>n von BufferedWriter entsprechen <strong>de</strong>nen <strong>de</strong>r Klasse<br />
Writer. Zusätzlich gibt es e<strong>in</strong>e Metho<strong>de</strong> newL<strong>in</strong>e mit <strong>de</strong>r e<strong>in</strong>e Zeileumschaltung <strong>in</strong><br />
<strong>de</strong>n Stream geschrieben wer<strong>de</strong>n kann.<br />
Pr<strong>in</strong>tWriter<br />
Diese Klasse stellt Ausgabemetho<strong>de</strong>n 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 wer<strong>de</strong>n soll.<br />
public Pr<strong>in</strong>tWriter(Writer aus, boolean autoflush)<br />
Mit <strong>de</strong>m Parameter autoflush wird angegeben, ob nach <strong>de</strong>r Ausgabe „e<strong>in</strong>er Zeilenschaltung“<br />
automatisch die Metho<strong>de</strong> flush() aufgerufen wer<strong>de</strong>n soll.<br />
Ausgabe primitiver Typen (und Objekttypen): Sie wird realisiert über e<strong>in</strong>e Reihe<br />
überla<strong>de</strong>ner Metho<strong>de</strong>n mit <strong>de</strong>m Namen „pr<strong>in</strong>t“. Zusätzlich gibt es alle Metho<strong>de</strong>n <strong>in</strong><br />
<strong>de</strong>r Variante pr<strong>in</strong>tln, bei <strong>de</strong>r automatisch an das En<strong>de</strong> <strong>de</strong>r 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 />
488
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
7.7.4 Demonstrationsprogramm zur E<strong>in</strong>-/ Ausgabe ab <strong>Java</strong> Version 1.1<br />
Das Demonstrationsprogramm soll folgen<strong>de</strong> 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 Wie<strong>de</strong>rgew<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 />
BufferedRea<strong>de</strong>r e<strong>in</strong>1 = new BufferedRea<strong>de</strong>r(<br />
new FileRea<strong>de</strong>r(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 Standar<strong>de</strong><strong>in</strong>gabe<br />
BufferedRea<strong>de</strong>r std<strong>in</strong> = new BufferedRea<strong>de</strong>r(<br />
new InputStreamRea<strong>de</strong>r(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>gRea<strong>de</strong>r e<strong>in</strong>2 = new Str<strong>in</strong>gRea<strong>de</strong>r(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("En<strong>de</strong> <strong>de</strong>s Stroms");<br />
}<br />
// 4. Zeilennummerierung und Datei-Ausgabe<br />
try<br />
{<br />
L<strong>in</strong>eNumberRea<strong>de</strong>r zn = new L<strong>in</strong>eNumberRea<strong>de</strong>r(<br />
new Str<strong>in</strong>gRea<strong>de</strong>r(s2));<br />
// BufferedRea<strong>de</strong>r e<strong>in</strong>4 = new BufferedRea<strong>de</strong>r(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("En<strong>de</strong> <strong>de</strong>s Stroms");<br />
489
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
}<br />
// 5. Speichern und Wie<strong>de</strong>rgew<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 />
BufferedRea<strong>de</strong>r e<strong>in</strong>5br = new BufferedRea<strong>de</strong>r(<br />
new InputStreamRea<strong>de</strong>r(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("En<strong>de</strong> <strong>de</strong>s Stroms");<br />
}<br />
}<br />
catch(FileNotFoundException e)<br />
{<br />
System.out.pr<strong>in</strong>tln("Datei nicht gefun<strong>de</strong>n: " + args[1]);<br />
}<br />
catch(IOException e)<br />
{<br />
System.out.pr<strong>in</strong>tln("IO Exception");<br />
}<br />
}<br />
}<br />
490
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
8. Serialisierung<br />
8.1 Grundlagen<br />
Serialisierung 342 ist die Fähigkeit e<strong>in</strong> Objekt, das im Hauptspeicher <strong>de</strong>r 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 o<strong>de</strong>r über e<strong>in</strong>e Netzwerkverb<strong>in</strong>dung zu transportieren. Auch <strong>de</strong>r<br />
umgekehrte Weg gehört dazu: Rekonstruktion e<strong>in</strong>es <strong>in</strong> serialisierter Form<br />
vorliegen<strong>de</strong>n Objekts <strong>in</strong> das <strong>in</strong>terne Format <strong>de</strong>r laufen<strong>de</strong>n <strong>Java</strong>-Masch<strong>in</strong>e.<br />
8.1.1 Das Interface Serializable<br />
Serialisierbare Objekte können <strong>in</strong> Dateien gespeichert o<strong>de</strong>r über Netzwerke<br />
übertragen wer<strong>de</strong>n. Dazu müssen sie <strong>in</strong> e<strong>in</strong> Byteformat umgewan<strong>de</strong>lt wer<strong>de</strong>n<br />
können. Das Markierungs<strong>in</strong>terface Serializable kennzeichnet e<strong>in</strong>e Klasse als<br />
serialisierbar. Ähnlich wie bei Cloneable s<strong>in</strong>d dazu ke<strong>in</strong>e Metho<strong>de</strong>n zu<br />
implementieren, es müssen aber auch alle referenzieren<strong>de</strong>n Klassen serialisierbar<br />
se<strong>in</strong>. Falls dies nicht <strong>de</strong>r Fall ist, wird e<strong>in</strong>e NotSerializableException erzeugt.<br />
Voraussetzung für das Serialisieren ist die Implementierung <strong>de</strong>r Schnittstelle<br />
Serializable. Das Interface enthält ke<strong>in</strong>e Implementierung, son<strong>de</strong>rn dient nur<br />
dazu, durch die Implementierungs-Hierarchie die Fähigkeit zum Schreiben<br />
anzuzeigen.<br />
342 häufig auch mit <strong>de</strong>m 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 <strong>de</strong>m Been<strong>de</strong>n <strong>de</strong>s Programms erhalten bleiben.<br />
491
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
8.1.2 Die Klasse ObjectOutputStream<br />
Zur Serialisierung e<strong>in</strong>es Objekts ( - o<strong>de</strong>r allgeme<strong>in</strong>er Daten bzw. Primitive - ) benötigt<br />
man e<strong>in</strong>en OutputStream. Am besten eignet sich e<strong>in</strong> FileOutputStream dafür,<br />
da meistens die Daten <strong>in</strong> e<strong>in</strong>er Datei 343 gesichert wer<strong>de</strong>n sollen. FileOutputStream<br />
erweitert die Klasse OutputStream. E<strong>in</strong>e Verb<strong>in</strong>dung zwischen Datei und Objekt-<br />
Strom wird durch die Klasse ObjectOutputStream (class<br />
java.io.ObjectOutputStream extends OutputStream implements<br />
DataOutput, ObjectOutput, ObjectStreamConstants) geschaffen.<br />
ObjectOutputStream implementiert das Interface ObjectOutput, z.B. die<br />
Funktion writeObject() zum Schreiben von Objekten.<br />
OutputStream<br />
{ abstract }<br />
ObjectOutputStream<br />
<br />
public ObjectOutputStream(OutputStream out) throws IOException<br />
// erzeugt e<strong>in</strong>en ObjectOutputStream, <strong>de</strong>r <strong>in</strong> <strong>de</strong>n angegebenen OutputStream<br />
// schreibt<br />
><br />
public f<strong>in</strong>al void writeObject(Object obj) throws IOException<br />
// schreibt das Objekt. Die implementieren<strong>de</strong> Klasse weiß, wie<br />
// das Objekt zu schreiben ist<br />
public void write(<strong>in</strong>t b) throws IOException<br />
// E<strong>in</strong> Bayte wird geschrieben<br />
public void write(byte b[]) throws IOException<br />
// schreibt e<strong>in</strong> Array von Bytes<br />
...<br />
public void writeBytes(Str<strong>in</strong>g daten) throws IOException;<br />
public void writeChars(Str<strong>in</strong>g daten) throws IOException;<br />
public void writeByte(<strong>in</strong>t daten) throws IOException;<br />
public void writeShort(<strong>in</strong>t daten) throws IOException;<br />
public void writeChar(<strong>in</strong>t daten) throws IOException;<br />
public void writeInt(<strong>in</strong>t daten) throws IOException;<br />
public void writeLong(long daten) throws IOException;<br />
public void writeFloat(float daten) throws IOException;<br />
public void writeDouble(double daten) throws IOException;<br />
...<br />
public void flush() throws IOException<br />
// Noch gepufferte Daten wer<strong>de</strong>n geschrieben<br />
public void close() throws IOException<br />
// Stream wird geschlossen.<br />
...<br />
Abb.: Die Klasse OblectOutputStream e<strong>in</strong>schl. e<strong>in</strong>iger Metho<strong>de</strong>n <strong>de</strong>s Interface ObjectOutput<br />
343 Der Date<strong>in</strong>ame wird häufig so gewählt, daß er mit <strong>de</strong>m Präfix „ser“ en<strong>de</strong>t.<br />
492
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Die Metho<strong>de</strong> public f<strong>in</strong>al void writeObject(Object obj) throws<br />
IOException schreibt folgen<strong>de</strong> Daten <strong>in</strong> <strong>de</strong>n OutputStream:<br />
- Die Klasse <strong>de</strong>s als Argument übergebenen Objekts<br />
- Die Signatur <strong>de</strong>r Klasse<br />
- Alle nicht statischen, nicht transienten Membervariablen <strong>de</strong>s übergebenen Objekts e<strong>in</strong>schl. <strong>de</strong>r aus<br />
Elternklassen geerbten Membervariablen.<br />
Bsp.: Serialisierung e<strong>in</strong>es „Zeit-“ Objekts. Das Zeit-Objekt ist e<strong>in</strong>e Instanz <strong>de</strong>r<br />
Klasse „Zeit“, die e<strong>in</strong>e Uhrzeit (Stun<strong>de</strong>, M<strong>in</strong>ute) kapselt.<br />
import java.io.*;<br />
public class Zeit implements Serializable<br />
{<br />
private <strong>in</strong>t stun<strong>de</strong>;<br />
private <strong>in</strong>t m<strong>in</strong>ute;<br />
public Zeit(<strong>in</strong>t stun<strong>de</strong>, <strong>in</strong>t m<strong>in</strong>ute)<br />
{<br />
this.stun<strong>de</strong> = stun<strong>de</strong>;<br />
this.m<strong>in</strong>ute = m<strong>in</strong>ute;<br />
}<br />
public Str<strong>in</strong>g toStr<strong>in</strong>g()<br />
{<br />
return stun<strong>de</strong> + ":" + m<strong>in</strong>ute;<br />
}<br />
}<br />
Mit Hilfe e<strong>in</strong>es Objekts vom Typ ObjectOutputStream kann e<strong>in</strong> Time-Objekt<br />
serialisiert wer<strong>de</strong>n.<br />
import java.io.*;<br />
import java.util.*;<br />
public class Pr81100<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
try {<br />
FileOutputStream fs = new FileOutputStream("test1.ser");<br />
ObjectOutputStream os = new ObjectOutputStream(fs);<br />
Zeit z = new Zeit(10,20);<br />
os.writeObject(z);<br />
os.close();<br />
}<br />
catch(IOException e)<br />
{ System.err.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
}<br />
}<br />
Nach <strong>de</strong>m Schließen <strong>de</strong>s Streams steht das serialisierte Objekt <strong>in</strong> „test1.ser“.<br />
493
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
8.1.3 Die Klasse ObjectInputStream<br />
An e<strong>in</strong>en E<strong>in</strong>gebestrom kommt man über e<strong>in</strong>en InputStream. Da die Daten häufig<br />
aus e<strong>in</strong>er Datei kommen ist dies häufig e<strong>in</strong> FileInputStream, <strong>de</strong>r mit e<strong>in</strong>em<br />
ObjectInputStream verknüpft wird. Die Metho<strong>de</strong> readObject() liest das<br />
Objekt, f<strong>in</strong><strong>de</strong>t heraus, was für e<strong>in</strong> Typ es ist und holt, falls nötig, auch noch Objekte,<br />
auf die verwiesen wird.<br />
InputStream<br />
{ abstract }<br />
ObjectInputStream<br />
<br />
public ObjectInputStream(InputStream <strong>in</strong>) throws IOException,<br />
StreamCorruptedException<br />
><br />
public f<strong>in</strong>al Object readObject() throws OptionalDataException<br />
ClassNotFoundException, IOException<br />
// Liest e<strong>in</strong> Objekt und gibt es zurück<br />
public boolean readBoolean() throws IOException<br />
public byte readByte(i) throws IOException<br />
public short readShort() throws IOException<br />
public char readChar() 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 />
. ...<br />
Abb.: Die Klasse ObjectInputStream<br />
Analog zum Interface ObjectOutput gibt es hier das Interface ObjectInput<br />
(<strong>in</strong>terface java.io.ObjectInput extends DataInput)<br />
494
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
><br />
ObjectInput<br />
><br />
public Object readObject() throws ClassNotFoundException, IOException<br />
public <strong>in</strong>t read() throws IOException<br />
// liest e<strong>in</strong> byte aus <strong>de</strong>m datenstrom. Dieses ist –1, wenn das En<strong>de</strong> erreicht ist<br />
public <strong>in</strong>t read(byte b[]) throws IOException<br />
// liest e<strong>in</strong> Array <strong>in</strong> <strong>de</strong>n Puffer. Das En<strong>de</strong> wird durch –1 angezeigt<br />
public <strong>in</strong>t read(byte b[], <strong>in</strong>t off, <strong>in</strong>t laenge) throws IOException<br />
// liest e<strong>in</strong> Array von Bytes <strong>in</strong> <strong>de</strong>n Puffer b an die Stelle off genau len Bytes<br />
public long skip (long n) throws IOException<br />
// überspr<strong>in</strong>gt n Bytes im E<strong>in</strong>gabestrom.<br />
public <strong>in</strong>t available() throws IOException<br />
// Gibt die Anzahl <strong>de</strong>r Zeichen zurück, die ohne Blocka<strong>de</strong> gelesen wer<strong>de</strong>n<br />
public void close() throws IOException<br />
// schließt <strong>de</strong>n E<strong>in</strong>gabestrom<br />
...<br />
Abb.: Das Interface ObjectInput<br />
Das Deserialisieren kann mann sich etwa so vorstellen:<br />
1. Anlegen e<strong>in</strong>en neuen Objekts <strong>de</strong>s zu serialisieren<strong>de</strong>n Typs, Vorbelegen <strong>de</strong>r Membervariablen mit<br />
Defaultwerten, Aufruf <strong>de</strong>s Defaultkonstruktor <strong>de</strong>r ersten nicht serialisierbaren Superklasse.<br />
2. Lesen <strong>de</strong>r serialsierten Daten und Zuweisen <strong>de</strong>r Daten zu <strong>de</strong>n entsprechen<strong>de</strong>n Membervariablen<br />
<strong>de</strong>s angelegten Objekts.<br />
Das durch Deserialisieren erzeugte Objekt hat anschließend dieselbe Struktur und<br />
<strong>de</strong>nselben Zustand, <strong>de</strong>n das serialsierte Objekt hatte 344 . Da <strong>de</strong>r Rückgabewert von<br />
readObject() vom Typ Object ist, muß das erzeugte Objekt <strong>in</strong> <strong>de</strong>n tatsächlichen<br />
Typ (o<strong>de</strong>r e<strong>in</strong>e se<strong>in</strong>er Oberklassen) umgewan<strong>de</strong>lt wer<strong>de</strong>n.<br />
Bsp.: Deserialisieren <strong>de</strong>s im vorherigen Beispiel serialisierten und <strong>in</strong> die Datei<br />
„test1.ser“ geschriebenen Zeit-Objekts.<br />
import java.io.*;<br />
import java.util.*;<br />
public class Pr81101<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
try {<br />
FileInputStream fs = new FileInputStream("test1.ser");<br />
ObjectInputStream is = new ObjectInputStream(fs);<br />
Zeit z = (Zeit) is.readObject();<br />
System.out.pr<strong>in</strong>tln(z.toStr<strong>in</strong>g());<br />
is.close();<br />
}<br />
catch(ClassNotFoundException e)<br />
{ System.err.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
catch(IOException e)<br />
{ System.err.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g()); }<br />
}<br />
}<br />
344 Abgesehen von <strong>de</strong>n nicht serialsierten Membervariablen <strong>de</strong>s Typs static o<strong>de</strong>r transient.<br />
495
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Beim Deserialisieren von Objekten können e<strong>in</strong>ige Fehler passieren. Damit e<strong>in</strong> Aufruf<br />
von readObject() erfolgreich ist, müssen mehrere Kriterien erfüllt se<strong>in</strong>:<br />
- das nächste Element <strong>de</strong>s E<strong>in</strong>gabestroms ist tatsächlich e<strong>in</strong> Objekt (ke<strong>in</strong> primitiver Typ).<br />
- Das Objekt muß vollständig und fehlerfrei aus <strong>de</strong>r E<strong>in</strong>gabedatei lesen lasse.<br />
- Es muß e<strong>in</strong>e Konvertierung auf <strong>de</strong>n gewünschten Typ erlauben, also entwe<strong>de</strong>r zu <strong>de</strong>rselben o<strong>de</strong>r<br />
e<strong>in</strong>er daraus abgeleiteten Klasse gehören.<br />
- Der Byteco<strong>de</strong> für die Klasse <strong>de</strong>s zu serialsieren<strong>de</strong>n Objekts muß vorhan<strong>de</strong>n se<strong>in</strong>. Er wird beim<br />
Serialisieren nicht mitgespeichert, son<strong>de</strong>rn muß <strong>de</strong>m Empfängerstrom wie üblich als kompilierter<br />
Byteco<strong>de</strong> zur Verfügung stehen.<br />
- Die Klassen<strong>in</strong>formation <strong>de</strong>s serialisierten Objekts und die im <strong>de</strong>serialisieren<strong>de</strong>n Programm als<br />
Byteco<strong>de</strong> vorhan<strong>de</strong>ne Klasse müssen zue<strong>in</strong>an<strong>de</strong>r kompatibel se<strong>in</strong>.<br />
8.2 Tiefe Objektkopien<br />
Klassen könen die Metho<strong>de</strong> clone() überschreiben und so e<strong>in</strong>e Kopie <strong>de</strong>r Werte<br />
liefern. Die Standarimplementierung ist jedoch so festgelegt, daß die Kopie flach ist.<br />
Das be<strong>de</strong>utet: Referenzen auf Objekte, die vom klonen<strong>de</strong>n Objekt ausgehen, wer<strong>de</strong>n<br />
beibehalten und diese Objekte nicht extra kopiert.<br />
E<strong>in</strong>e tiefe Kopie kann folgen<strong>de</strong>rmaßen erzeugt wer<strong>de</strong>n: Das zu klonen<strong>de</strong> Objekt ist<br />
zu serialisieren und dann wie<strong>de</strong>r auszupacken. Die zu klonen<strong>de</strong>n Objekte müssen<br />
nur das Serializable-Interface implementieren.<br />
496
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
9. Netzwerkprogrammierung<br />
Das Paket java.net enthält Klassen zur Programmierung von TCP/IP 345 -<br />
Netzwerkzugriffen. Dieses (Internet-) Protokoll stellt die Basis aller <strong>Java</strong>-Netzzugriffe<br />
dar. Darauf aufbauend gibt es weiter entwickelte Netzwerkprotokolle wie RMI für<br />
entfernte Metho<strong>de</strong>naufrufe und verteilte Anwendungen und Enterprise<br />
<strong>Java</strong>Beans für verteilte Objekte.<br />
9.1 Adressen, Ressourcen und URLs<br />
9.1.1 Die Klasse InetAddress<br />
Zur Adressierung von Rechnern im Netz wird die Klasse InetAddress <strong>de</strong>s Pakets<br />
java.net verwen<strong>de</strong>t. E<strong>in</strong>e InetAddress enthält sowohl e<strong>in</strong>e IP-Adresse 346 als<br />
auch <strong>de</strong>n symbolischen Namen <strong>de</strong>s jeweiligen Rechners 347 . Die bei<strong>de</strong>n Bestandteile<br />
können mit <strong>de</strong>n Metho<strong>de</strong>n getHostName() und getHostAddress() abgefragt<br />
wer<strong>de</strong>n. Mit Hilfe von getAddress() kann die IP-Adresse auch direkt als „byte“-<br />
Array (mit 4 Elementen) beschafft wer<strong>de</strong>n.<br />
Zur Generierung e<strong>in</strong>es InetAddress-Objekts stehen zur Verfügung:<br />
public static InetAddress getByName(Str<strong>in</strong>g host) throws<br />
UnknownHostException<br />
// erwartet e<strong>in</strong>en Str<strong>in</strong>g mit <strong>de</strong>r IP-Adtesse o<strong>de</strong>r <strong>de</strong>m Namen als Argument<br />
public static InetAddress getLocalHost() throws UnknownHostException<br />
// liefert e<strong>in</strong> InetAdress-Objekt für <strong>de</strong>n eigenen Rechner<br />
Das folgen<strong>de</strong> Programm 348 ermittelt zu e<strong>in</strong>er IP-Adresse <strong>de</strong>n symbolischen Namen<br />
<strong>de</strong>s zufehörigen Rechners bzw. zum symbolischen Namen e<strong>in</strong>e IP-Adresse,<br />
import java.net.*;<br />
public class WerB<strong>in</strong>Ich<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
if (args.length != 1)<br />
{<br />
System.err.pr<strong>in</strong>tln("Verwendung: java WerB<strong>in</strong>Ich ");<br />
System.exit(1);<br />
}<br />
try {<br />
345 Als Protokoll bezeichnet man die Menge aller Regeln, die nötig s<strong>in</strong>d, um e<strong>in</strong>en kontrollierten und<br />
e<strong>in</strong><strong>de</strong>utigen Verb<strong>in</strong>dungsaufbau, Datenaustausch und Verb<strong>in</strong>dungsabbau gewährleisten zu können. Die <strong>de</strong>rzeit<br />
<strong>in</strong> <strong>Java</strong> verfügbareb Netzwerkfähigkeiten basieren auf <strong>de</strong>n Internet-Protokollen TCP/IP (bzw. TCP/UDP)<br />
346 IP steht für Internet Protocol. Die 32-Bit-lange IP-Adresse besteht aus e<strong>in</strong>er Netzwerk-ID und e<strong>in</strong>er Host-ID.<br />
Die Host-ID gibt die Bezeichnung <strong>de</strong>s Rechners <strong>in</strong>nerhalb se<strong>in</strong>es eigenen Netzwerks an, die Netwerk-ID liefert<br />
die Bezeichnung <strong>de</strong>s Rechners.<br />
347 Anstelle <strong>de</strong>r IP-Adresse können bei Anwendungsprotokollen symbolische Namen verwen<strong>de</strong>t wer<strong>de</strong>n. Sie<br />
wer<strong>de</strong>n mit Hilfe von Namen-Servern <strong>in</strong> die zugehörige IP-Adresse übersetzt , bevor die Verb<strong>in</strong>dung aufgebaut<br />
wird. Das Doma<strong>in</strong> Name System (DNS) ordnet numerischen IP-Adressen sprechen<strong>de</strong> Namen zu.<br />
348 vgl. pr91100<br />
497
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
// Hole die angefor<strong>de</strong>rte Adresse<br />
InetAddress addr = InetAddress.getByName(args[0]);<br />
System.out.pr<strong>in</strong>tln(addr.getHostName());<br />
System.out.pr<strong>in</strong>tln(addr.getHostAddress());<br />
}<br />
catch(Exception e)<br />
{<br />
System.err.pr<strong>in</strong>tln(e.toStr<strong>in</strong>g());<br />
System.exit(1);<br />
}<br />
}<br />
}<br />
9.1.2 Die Klasse URL<br />
Im WWW wer<strong>de</strong>n Ressourcen über URLs (Universal Ressource Locator) i<strong>de</strong>ntifiziert.<br />
E<strong>in</strong>e URL besteht aus:<br />
e<strong>in</strong>em Protokollnamen, z.B. http 349 (HTML), file (lokale Dteien), ftp (Dateitransfer), rmi (Remote<br />
Method Invocation), <strong>in</strong>op(Inter ORB Protocol) o<strong>de</strong>r jdbc (<strong>Java</strong> Database Connectivity), <strong>de</strong>m e<strong>in</strong><br />
Doppelpunkt und zwei Schrägstriche folgen. Nach <strong>de</strong>m Doppel-Slash kommt die Angabe:<br />
//user 350 :password 351 @host 352 :port 353 /url-path 354 . E<strong>in</strong>ige Teile können bei e<strong>in</strong>er URL<br />
ausgelassen wer<strong>de</strong>n. So s<strong>in</strong>d „user:password@“, „password“, „port“ und „/url-path“ optional.<br />
S<strong>in</strong>d Benutzername und Paßwort gegeben, so folgt e<strong>in</strong> „At“-Zeichen @. Paßwort und Benutzername<br />
durfen nicht Doppelpunkt, At-Zeichen o<strong>de</strong>r Slash enthalten. Fehlt die Angabe <strong>de</strong>s Rechners, wird <strong>de</strong>r<br />
aktuelle Rechner (localhost) benutzt, bei Ports bekannte Standardnummern. Schließlich folgt e<strong>in</strong>e<br />
Bezeichnung <strong>de</strong>r Ressource, typischerweise unter Angabe e<strong>in</strong>es Pfads.<br />
<strong>Java</strong> implementiert das Konzept e<strong>in</strong>es Uniform Resource Locator durch e<strong>in</strong>e eigene<br />
Klasse URL, die sich im Paket java.net bef<strong>in</strong><strong>de</strong>t. Aus e<strong>in</strong>er gegebenen<br />
Zeichenreihe erstellt <strong>Java</strong> e<strong>in</strong>en geeigneten URL, <strong>de</strong>n Man zum E<strong>in</strong>richten e<strong>in</strong>er<br />
URLConnection nutzen kann. Die Verb<strong>in</strong>dung ermöglicht e<strong>in</strong>e Interaktion, die vom<br />
Protokoll <strong>de</strong>r betreffen<strong>de</strong>n Ressource <strong>de</strong>f<strong>in</strong>iert wird.<br />
Erzeugen von URL-Objekten. Am e<strong>in</strong>fachsten ist es, über e<strong>in</strong>e Str<strong>in</strong>g-Repräsentation<br />
<strong>de</strong>r URL-Adresse zu gehen, z.B.: URL fhURL = new URL("http://www.fhregensburg.<strong>de</strong>/");<br />
Diese URL wur<strong>de</strong> mit <strong>de</strong>m Konstruktor<br />
public URL(Str<strong>in</strong>g urlAddr) throws MalformedURLException<br />
erzeugt. E<strong>in</strong> an<strong>de</strong>rer Konstruktor ist<br />
349 Mit <strong>de</strong>m Hypertext Tranfer Protocol wird auf Inhalte <strong>de</strong>s Web zugegriffen. Die URL für Dienste im Web<br />
beg<strong>in</strong>nt mit http.<br />
350 Optionaler Benutzername<br />
351 optionales Paßwort, e<strong>in</strong> Paßwort ohne Benutzername kann nicht angegeben wer<strong>de</strong>n<br />
352 Auf die Angabe <strong>de</strong>s Protokolls folgt <strong>in</strong> <strong>de</strong>r Regel <strong>de</strong>r Name <strong>de</strong>r Domäne o<strong>de</strong>r die IP-Adresse <strong>de</strong>s Servers.<br />
Name und IP-Adresse s<strong>in</strong>d <strong>in</strong> <strong>de</strong>r Regel gleichwertig, da von e<strong>in</strong>em beson<strong>de</strong>ren Dienst <strong>de</strong>r Name <strong>in</strong> e<strong>in</strong>e IP-<br />
Adresse umgesetzt wird.<br />
353 E<strong>in</strong>e Verb<strong>in</strong>dung zu e<strong>in</strong>em Rechner geschieht immer durch e<strong>in</strong>e Art Tür, die Port genannt wird. Die Port-<br />
Nummer läßt <strong>de</strong>n Server die Dienste kategorisieren. Je<strong>de</strong>r Dienst bekommt e<strong>in</strong>e an<strong>de</strong>re Portnummer, damit sie<br />
sich unterschei<strong>de</strong>n lassen. Normalerweise horcht <strong>de</strong>r HTTP-Server auf Port 80.<br />
354 Auf <strong>de</strong>n Servernamen folgt die Angabe <strong>de</strong>r Datei, auf die über HTTP o<strong>de</strong>r FTP zugegriffen wer<strong>de</strong>n soll. Da<br />
sie <strong>in</strong> e<strong>in</strong>em Verzeichnis liegt, beschreibt url-path <strong>de</strong>n Weg zur Datei. Ist ke<strong>in</strong>e Datei vorhan<strong>de</strong>n und en<strong>de</strong>t die<br />
Angabe <strong>de</strong>r URL mit e<strong>in</strong>em Slash „/“, dann versucht <strong>de</strong>r Web-Server auf e<strong>in</strong>e <strong>de</strong>r Dateien <strong>in</strong><strong>de</strong>x.html bzw.<br />
<strong>in</strong><strong>de</strong>x.htm zuzugreifen.<br />
498
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
public URL(URL urlObj, Str<strong>in</strong>g … ) throws MalformedURLException<br />
// erzeugt relativ zur URL e<strong>in</strong> neues URL-Objekt.<br />
Bsp.: Zugiff auf die Homepage <strong>de</strong>r FH Regensburg<br />
import java.net.*;<br />
import java.io.*;<br />
public class OeffneURLStrom<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[])<br />
{<br />
try {<br />
Str<strong>in</strong>g s;<br />
URL fhURL = new URL("http://www.fh-regensburg.<strong>de</strong>/");<br />
BufferedRea<strong>de</strong>r e<strong>in</strong> = new BufferedRea<strong>de</strong>r(<br />
new InputStreamRea<strong>de</strong>r(fhURL.openStream()));<br />
while ((s = e<strong>in</strong>.readL<strong>in</strong>e()) != null)<br />
System.out.pr<strong>in</strong>tln(s);<br />
e<strong>in</strong>.close();<br />
}<br />
catch(MalformedURLException e)<br />
{ System.out.pr<strong>in</strong>tln("MalformedURLException: " + e); }<br />
catch(IOException e)<br />
{ System.out.pr<strong>in</strong>tln("IOException: " + e); }<br />
}<br />
}<br />
Die Klasse URL besitzt auch Konstruktoren, die die Angabe <strong>de</strong>r Komponenten von<br />
<strong>de</strong>r Adresse (also Zugriffsart, Hostname und Dateiadresse getrennt) akzeptieren:<br />
public URL(Str<strong>in</strong>g protocol, Str<strong>in</strong>g host, <strong>in</strong>t port, Str<strong>in</strong>g file) throws<br />
MalformedURLException<br />
public URL(Str<strong>in</strong>g protocol, Str<strong>in</strong>g host, Str<strong>in</strong>g file) throws<br />
MalformedURLException<br />
Je<strong>de</strong>r <strong>de</strong>r Konstruktoren wirft e<strong>in</strong>e MalformedURLException, wenn <strong>de</strong>r Parameter<br />
im Konstruktor entwe<strong>de</strong>r null ist o<strong>de</strong>r er e<strong>in</strong> unbekanntes Protokoll beschreibt.<br />
Zugriff auf Daten über e<strong>in</strong>e URL. Es gibt zwei Möglichkeiten über e<strong>in</strong>e URL bzw. über<br />
e<strong>in</strong>e URLConnection. Bei<strong>de</strong> Wege benutzen Streams. Je<strong>de</strong>s URL-Objekt besitzt die<br />
Metho<strong>de</strong> openStream(), die e<strong>in</strong>en InputStream zum Weiterverarbeiten liefert.<br />
f<strong>in</strong>al InputStream openStream() throws IOException<br />
// öffnet e<strong>in</strong>e Verb<strong>in</strong>dung zum Server und liefert e<strong>in</strong>en InputStream zurück<br />
URLConnection openConnection() throws IOException<br />
// liefert e<strong>in</strong> URLConnection-Objekt, das die Verb<strong>in</strong>dung zum entfernten<br />
// Server vertritt. openConnection() wird vom Protokoll-Handler immer<br />
// dann aufgerufen, wenn e<strong>in</strong>e neue Verb<strong>in</strong>dung geöffnet wird.<br />
Verweist die URL auf e<strong>in</strong>e Textdatei, dann erweitert man <strong>de</strong>n InputStream zu<br />
e<strong>in</strong>em BufferedRea<strong>de</strong>r, da dieser die readL<strong>in</strong>e()-Metho<strong>de</strong> besitzt.<br />
Bsp.: E<strong>in</strong>e Antwort (HTML-Seite) auf e<strong>in</strong>e Suchfrage<br />
import java.io.*;<br />
import java.net.*;<br />
public class GoogleSucher<br />
{<br />
public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]) throws IOException,<br />
MalformedURLException<br />
{<br />
499
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
Str<strong>in</strong>g s = "";<br />
if (args.length == 0) s = "Stephan Meier <strong>in</strong> Regensburg";<br />
else<br />
for (<strong>in</strong>t i = 0; i < args.length; i++) s += args[i] + " ";<br />
s.trim();<br />
s = "p=" + URLEnco<strong>de</strong>r.enco<strong>de</strong>(s);<br />
// Metho<strong>de</strong>n <strong>de</strong>r Klasse URLEnco<strong>de</strong>r machen aus e<strong>in</strong>em Str<strong>in</strong>g e<strong>in</strong>e URL<br />
System.out.pr<strong>in</strong>tln(s);<br />
URL u = new URL("http://<strong>de</strong>.google.yahoo.com/b<strong>in</strong>/query_<strong>de</strong>?" + s);<br />
BufferedRea<strong>de</strong>r e<strong>in</strong> = new BufferedRea<strong>de</strong>r(<br />
new InputStreamRea<strong>de</strong>r(u.openStream()));<br />
Str<strong>in</strong>g zeile, antwort = null;<br />
while ((zeile = e<strong>in</strong>.readL<strong>in</strong>e()) != null) antwort += zeile + "\n";<br />
System.out.pr<strong>in</strong>t(antwort);<br />
}<br />
}<br />
URLs <strong>in</strong> Applets. Die Klasse Applet hat zwei Metho<strong>de</strong>n mit <strong>de</strong>nen man e<strong>in</strong>e Basis-<br />
URL erzeugen kann, ohne e<strong>in</strong>e feste Adresse im Programm anzugeben:<br />
- Die Metho<strong>de</strong> getDocumentBase() gibt e<strong>in</strong> URL-Objekt zurück, welches das Verzeichnis<br />
repräsentiert, das die Webseite mit <strong>de</strong>m Applet enthält.<br />
- Die Metho<strong>de</strong> getCo<strong>de</strong>Base() gibt e<strong>in</strong> URL-Objekt zurück, das <strong>de</strong>n Ordner repräsentiert, <strong>in</strong> <strong>de</strong>m<br />
sich die .class-Datei <strong>de</strong>r Hauptklasse <strong>de</strong>s Applet bef<strong>in</strong><strong>de</strong>t.<br />
Die Applet-Klasse bietet e<strong>in</strong>e Metho<strong>de</strong> mit <strong>de</strong>m Namen getImage() an, mit <strong>de</strong>r e<strong>in</strong><br />
Bild <strong>in</strong> e<strong>in</strong> Image-Objekt gela<strong>de</strong>n wer<strong>de</strong>n kann. Es gibt zwei Möglichkeiten, diese<br />
Metho<strong>de</strong> zu verwen<strong>de</strong>n:<br />
- Die Metho<strong>de</strong> getImage(), aufgerufen mit e<strong>in</strong>em Argument (e<strong>in</strong> Objekt vom Typ URL), lädt das Bild<br />
mit dieser URL<br />
- Die Metho<strong>de</strong> getImage(), aufgerufen mit zwei Argumenten (<strong>de</strong>r Basis-URL und e<strong>in</strong>em Str<strong>in</strong>g, <strong>de</strong>r<br />
<strong>de</strong>n relativen Pfad o<strong>de</strong>r Date<strong>in</strong>amen <strong>de</strong>s aktuellen Bilds ausgibt).<br />
Bsp.:<br />
import java.applet.Applet;<br />
import java.awt.*;<br />
import java.net.*;<br />
public class AppletURL extends Applet<br />
{<br />
Image bild;<br />
public void <strong>in</strong>it()<br />
{<br />
URL u1 = getDocumentBase(); System.out.pr<strong>in</strong>tln(u1);<br />
try { URL u2 = new URL(u1,"images/scratch1.gif");<br />
System.out.pr<strong>in</strong>tln(u2);<br />
bild = getImage(getCo<strong>de</strong>Base(),"images/B04240900.jpg");<br />
}<br />
catch (MalformedURLException e) { System.out.pr<strong>in</strong>tln(e); }<br />
}<br />
public void pa<strong>in</strong>t(Graphics schirm)<br />
{<br />
<strong>in</strong>t iBreite = bild.getWidth(this); <strong>in</strong>t iHoehe = bild.getHeight(this);<br />
schirm.drawImage(bild,10,10,iBreite/4,iHoehe/4,this);<br />
}<br />
}<br />
500
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
URL<br />
><br />
public URL(Str<strong>in</strong>g url) throws MalformedURLException<br />
public URL(Str<strong>in</strong>g protokoll, Str<strong>in</strong>g host, Str<strong>in</strong>g pfad) throws MalformedURLException<br />
public URL(Str<strong>in</strong>g protololl, Str<strong>in</strong>g host, <strong>in</strong>t portnummer, Str<strong>in</strong>g pfad)<br />
throws MalformedURLException<br />
// erzeugt e<strong>in</strong> URL-Objekt mit gegebenen Protokoll, Hostnamen, Portnummer und Datei<br />
// Ist die Portnummer –1, so wird <strong>de</strong>r Standard-Port verwen<strong>de</strong>t, z:B für WWW Port 80<br />
><br />
public f<strong>in</strong>al Object getContent() throws IOException<br />
//<br />
public f<strong>in</strong>al InputStream openStream() throws IOException<br />
// öffnet e<strong>in</strong>e Verb<strong>in</strong>dung zum Server und liefert e<strong>in</strong>en Inputstream zurück. Die Me-<br />
// tho<strong>de</strong> ist e<strong>in</strong>e Ankürzung für openConnection.getInputStream()<br />
public URLConnection openConnection() throws IOException<br />
// liefert e<strong>in</strong> URLConnection-Objekt, das die Verb<strong>in</strong>dung zum entfernten Objekt<br />
// vertritt.. openConnection() wird vom Protokoll-Handler immer dann aufgerufen,<br />
// wenn e<strong>in</strong>e neue Verb<strong>in</strong>dung geöffnet wird.<br />
public Str<strong>in</strong>g getProtocol()<br />
// liefert das Protokoll <strong>de</strong>r URL<br />
public Str<strong>in</strong>g getHost()<br />
// liefert <strong>de</strong>n Hostnamen <strong>de</strong>r URL, falls das möglich ist.<br />
// Für das Protokoll „file“ ist das e<strong>in</strong> leerer Str<strong>in</strong>g<br />
public <strong>in</strong>t getPort()<br />
// liefert die Portnummer. Ist sie nicht gesetzt, liefert die Metho<strong>de</strong> e<strong>in</strong>e –1.<br />
public Str<strong>in</strong>g getFile()<br />
// gibt <strong>de</strong>n Date<strong>in</strong>amen <strong>de</strong>r URL zurück<br />
Abb.: Die Klasse java.net.URL<br />
URL toURL() throws MalformedURLException<br />
liefert e<strong>in</strong> URL-Objekt zu e<strong>in</strong>em File-Objekt. Es muß e<strong>in</strong> File-Objekt erzeugt se<strong>in</strong>,<br />
anschließend erzeugt toURL() e<strong>in</strong> URL-Objekt (mit <strong>de</strong>m Protokoll "file" und <strong>de</strong>n<br />
absoluten Pfadangaben zur Datei bzw. zum Verzeichnis).<br />
501
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
9.1.3 Die Klasse URLConnection und abgeleitete Klassen<br />
E<strong>in</strong>e URL-Connection erhält man durch Aufruf <strong>de</strong>r Metho<strong>de</strong> openConnection()<br />
e<strong>in</strong>es URL-Objekts. Mit diesem Objekt lassen sich Inhalte <strong>de</strong>r Ressource lesen sowie<br />
Informationen über die Art <strong>de</strong>s Objekts ermitteln. Je nach Art <strong>de</strong>s Protokolls wird die<br />
abstrakte Klasse URLConnection durch verschie<strong>de</strong>n konkrete Klassen<br />
implementiert, z.B. HttpURLConnection, AppletResourceConnection,<br />
FileURLConnection o<strong>de</strong>r FtpURLConnection. Die Subklassen implementieren<br />
die Protokolle, mit <strong>de</strong>nen die Verb<strong>in</strong>dung zum Inhalt aufgebaut wird. Subklassen<br />
bedienen sich dabei <strong>de</strong>r Klasse URLStreamHandler mit <strong>de</strong>n <strong>de</strong>r eigentliche Inhalt<br />
ausgelesen wird.<br />
URLConnection<br />
{ abstract }<br />
><br />
protected URLConnection(URL url)<br />
><br />
public Object getContent() throws IOException, UnkownServiceException<br />
// liefert <strong>de</strong>n Inhalt, auf <strong>de</strong>n die URL verweist.<br />
Der Inhalt e<strong>in</strong>es URL-Objekts lässt sich mit getContent() vom Server beschaffen.<br />
Für HTML-Dateien liefert getContent() e<strong>in</strong> Objekt vom Typ<br />
sun.net.www.MeteredStream, für normale Textdateien e<strong>in</strong><br />
sun.www.content.txt.Pla<strong>in</strong>TextInputStream-Objekt. Für Texte und HTML-<br />
Seiten kann man mit Hilfe e<strong>in</strong>es InputStream-Objekts die Datei (zeilenweise) lesen.<br />
Mit<br />
Object o = u.getContent();<br />
System.out.pr<strong>in</strong>tln("Ich erhielt " + o.getClass().getName());<br />
kann festgestellt wer<strong>de</strong>n, was für e<strong>in</strong> Handler-Objekt e<strong>in</strong>e URL-Klasse für <strong>de</strong>n<br />
Datenstrom e<strong>in</strong>setzt. getContent() erkennt anhand <strong>de</strong>r Endung bzw. <strong>de</strong>n ersten<br />
Bytes <strong>de</strong>n Typ <strong>de</strong>r Datei. Dann konvertiert <strong>de</strong>r Content Handler die Bytes se<strong>in</strong>es<br />
Datenstroms <strong>in</strong> e<strong>in</strong> <strong>Java</strong> Objekt.<br />
502
<strong>Programmieren</strong> <strong>in</strong> <strong>Java</strong><br />
9.2 Kommunikation <strong>in</strong> Netzwerken<br />
Das Common GatewayInterface (CGI)<br />
CGI ist die Beschreibung e<strong>in</strong>er Schnittstelle über die externe Programme mit<br />
Informations-Servern, meistens Web-Servern, Daten austauschen. CGI-Programme<br />
können <strong>in</strong> allen möglichen Programmiersprachen verfaßt se<strong>in</strong>. Häufig s<strong>in</strong>d es Shello<strong>de</strong>r<br />
Perl-Skripte.<br />
Die CGI-Programme wer<strong>de</strong>n von e<strong>in</strong>em Browser durch e<strong>in</strong>e URL angesprochen. Der<br />
Browser baut e<strong>in</strong>e Verb<strong>in</strong>dung zum Server auf. Dieser erkennt an Hand <strong>de</strong>s Pfads<br />
<strong>de</strong>r URL, ob es sich um e<strong>in</strong>e normale Web-Seite o<strong>de</strong>r um e<strong>in</strong> Skript han<strong>de</strong>lt. Falls es<br />
e<strong>in</strong> Skript ist, dann führt <strong>de</strong>r Server das Skript aus, das e<strong>in</strong>e HTML-Datei erzeugt.<br />
Diese wird übertragen und im Browser dargestellt.<br />
Sockets 357<br />
Als Socket bezeichnet man e<strong>in</strong> streambasierte Programmierschnittstelle zur<br />
Kommunikation zweier Rechner <strong>in</strong> e<strong>in</strong>em TCP/IP-Netz. Das Übertragen von Daten<br />
über e<strong>in</strong>e Socket-Verb<strong>in</strong>dung besteht aus:<br />
1. Verb<strong>in</strong>dungsaufbau<br />
2. Lesen bzw. Schreiben <strong>de</strong>r Daten<br />
3. Verb<strong>in</strong>dungsabbau<br />
Wer<strong>de</strong>n Rechner verbun<strong>de</strong>n, so implementiert je<strong>de</strong>r Rechner e<strong>in</strong>en Socket.<br />
Derjenige, <strong>de</strong>r Daten empfängt (Client), öffnet e<strong>in</strong>e Socket-Verb<strong>in</strong>dung zum Horchen<br />
und <strong>de</strong>rjenige, <strong>de</strong>r sen<strong>de</strong>t, öffnet e<strong>in</strong>e Verb<strong>in</strong>dung zum Sen<strong>de</strong>n (Server). Damit <strong>de</strong>r<br />
Empfänger <strong>de</strong>n Sen<strong>de</strong>r auch hören kann, muß dieser durch e<strong>in</strong>e e<strong>in</strong><strong>de</strong>utige Adresse<br />
als Server ausgemacht wer<strong>de</strong>n. Er bekommt also e<strong>in</strong>e IP-Adresse im Netz und e<strong>in</strong>e<br />
ebenso e<strong>in</strong><strong>de</strong>utige Port-Adresse. Der Port ist so etwas wie e<strong>in</strong>e Zimmernummer: Die<br />
Adresse bleibt dieselbe, aber <strong>in</strong> je<strong>de</strong>m Zimmer sitzt e<strong>in</strong>er und macht se<strong>in</strong>e Aufgaben.<br />
Für je<strong>de</strong>n Dienst (Service), <strong>de</strong>n e<strong>in</strong> Server bereitstellt, gibt es e<strong>in</strong>en Port 358 . E<strong>in</strong>e<br />
Port-Nummer ist e<strong>in</strong>e 16-Bit-Zahl und <strong>in</strong> die Gruppen System und Benutzer e<strong>in</strong>geteilt.<br />
Sockets aus <strong>de</strong>r Sicht e<strong>in</strong>er Client- bzw. Server-Anwendung wer<strong>de</strong>n durch die bei<strong>de</strong>n<br />
Klassen Socket und ServerSocket repräsentiert.<br />
Bsp 359 .:<br />
1. E<strong>in</strong> e<strong>in</strong>facher Server, <strong>de</strong>r alles „nachplappert“, was <strong>de</strong>r Client sen<strong>de</strong>t.<br />
2. E<strong>in</strong> e<strong>in</strong>facher Client, <strong>de</strong>r Zeilen zum Server sen<strong>de</strong>t und e<strong>in</strong>liest<br />
357 Sockets wur<strong>de</strong>n zu Beg<strong>in</strong>n <strong>de</strong>r achtziger Jahre für die Programmiersprache C entwickelt.<br />
358 Diese Adressen wer<strong>de</strong>n von <strong>de</strong>r IANA (Internet Assigned Number Authority) vergeben. Die IANA ist <strong>de</strong>r<br />
zentrale Koord<strong>in</strong>ator für die IP-Adressen, Doma<strong>in</strong> Namen, MIME Typen und viele an<strong>de</strong>re Parameter, u.a.a.<br />
Portnummern.<br />
359 pr92100<br />
503