This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
oder
), oder es muss ein Tag verwendet werden, dessen Ausgabe in einer eigenen Zeile steht (z.B.
A2:
A3:
Teil VII
Die HTML-Seite kann nun im Browser aufgerufen werden. Nach einigen Mausklicks kçnnte die Darstellung so aussehen:
951
Kapitel 40
Applets II
Abbildung 40.2: Die drei kommunizierenden Applets
40.3 Umwandlung einer Applikation in ein Applet In der Praxis steht man manchmal vor der Aufgabe, eine bestehende Applikation in ein Applet umzuwandeln, etwa wenn ein vorhandendes Programm in eine HTML-Prsentation eingebunden werden soll. Da die Unterschiede zwischen Applets und Applikationen nicht so groß sind, kann diese Konvertierung – etwas Glck vorausgesetzt – mit berschaubarem Aufwand erledigt werden. Wir wollen in diesem Abschnitt die prinzipielle Vorgehensweise erlutern und auf einige der dabei mçglicherweise auftretenden Besonderheiten eingehen.
40.3.1 Die Beispielapplikation Als Beispiel soll ein sehr einfaches Programm verwendet werden. Es enthlt ein Textfeld mit einem Zahlenwert und vier Buttons, mit denen die Zahl um 1, 10, 100 oder 1000 erhçht werden kann. Die Dialogelemente werden in einem Frame angeordnet, der von der main-Methode erzeugt wird. Seine Grçße und Position werden ebenfalls explizit vorgegeben: Listing 40.5: Die CalculatorApplikation
952
001 002 003 004 005 006 007 008 009 010 011
/* Calculator.java */ import java.awt.*; import java.awt.event.*; public class Calculator extends Frame implements ActionListener { private TextField tf;
Umwandlung einer Applikation in ein Applet 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 }
public Calculator() { super("Calculator"); addWindowListener(new WindowClosingAdapter(true)); setBackground(Color.lightGray); setLayout(new GridLayout(2, 1)); tf = new TextField("777"); add(tf); Panel p = new Panel(); for (int i = 1; i <= 1000; i *= 10) { Button b = new Button("+" + i); b.addActionListener(this); p.add(b); } add(p); }
Kapitel 40 Listing 40.5: Die CalculatorApplikation (Forts.)
public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); int n1 = Integer.parseInt(tf.getText()); int n2 = Integer.parseInt(cmd.substring(1)); tf.setText("" + (n1 + n2)); } public static void main(String[] args) { Calculator calc = new Calculator(); calc.setLocation(100, 100); calc.setSize(200, 85); calc.setVisible(true); }
Die Ausgabe des Programms nach dem Starten sieht so aus:
INFO
i
i
Teil VII
Abbildung 40.3: Die CalculatorApplikation
i
In vielen Beispielen in diesem Buch wird der Einfachheit halber die in Abschnitt 23.2.4, Seite 535 vorgestellte Klasse WindowClosingAdapter verwendet, um einen Listener zum Schließen des Fensters zu registrieren. Damit ein solches Beispiel sich kompilieren lsst, muss die Datei WindowClosingAdapter.java im aktuellen Verzeichnis vorhanden sein. Sie befindet sich auf der DVD zum Buch oder in Listing 23.2, Seite 535.
953
Kapitel 40
Applets II
40.3.2 Variante 1: Das Programm als Popup-Fenster Die einfachste Mçglichkeit, die Applikation als Applet laufen zu lassen, besteht darin, die aus Frame abgeleitete Fensterklasse zu erhalten und aus dem Applet heraus als eigenstndiges Hauptfenster aufzurufen. Dazu schreiben wir ein Hilfsapplet CalculatorApplet1, das den ehemals in main enthaltenen Code in der init-Methode ausfhrt. Um das Fenster sichtbar zu machen, wird der Aufruf von setVisible(true) in die Methode start verlegt und in stop wird setVisible(false) aufgerufen. Das Fenster wird dadurch immer dann angezeigt, wenn die Seite mit dem Applet im Browser sichtbar ist: Listing 40.6: Ein ApplikationsApplet im Popup-Fenster
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027
/* CalculatorApplet1.java */ import java.awt.*; import java.applet.*; public class CalculatorApplet1 extends Applet { Calculator calc; public void init() { calc = new Calculator(); calc.setLocation(100, 100); calc.setSize(200, 130); } public void start() { calc.setVisible(true); } public void stop() { calc.setVisible(false); } }
Das Applet kann mit folgender HTML-Datei im Browser angezeigt werden: Listing 40.7: HTML-Datei zum Aufruf des Beispiel-Applets
954
001 002 003 004 005 006 007 008 009
... * Die Dateitypen .htm, .html, .gif, .jpg und .jpeg werden * erkannt und mit korrekten MIME-Headern bertragen, alle * anderen Dateien werden als "application/octet-stream" * bertragen. Jeder Request wird durch einen eigenen * Client-Thread bearbeitet, nach bertragung der Antwort * schließt der Server den Socket. Antworten werden mit * HTTP/1.0-Header gesendet. */ public class ExperimentalWebServer { public static void main(String[] args) { if (args.length != 1) { System.err.println( "Usage: java ExperimentalWebServer <port>" ); System.exit(1); } try { int port = Integer.parseInt(args[0]); System.out.println("Listening to port " + port); int calls = 0; ServerSocket httpd = new ServerSocket(port); while (true) { Socket socket = httpd.accept(); (new BrowserClientThread(++calls, socket)).start(); } } catch (IOException e) { System.err.println(e.toString()); System.exit(1); } } } /** * Die Thread-Klasse fr die Client-Verbindung. */ class BrowserClientThread extends Thread { static final String[][] mimetypes = {
Anpassungen fr das HTTP 1.1-Protokoll Das am CERN in Genf entwickelte Protokoll HTTP 1.0 standardisierte den netzwerkbasierenden Zugriff auf entfernte Dokumente. Filehoster und multiple URLs auf ein und dieselbe IP-Adresse wurden whrend der Entwurfsphase des Protokolls allerdings noch nicht vorgesehen und erst in der nachfolgenden Version HTTP 1.1 bercksichtigt. Dieser
1160
Client-Sockets
Kapitel 46
Abschnitt beschreibt die Anpassungen, die vorgenommen werden mssen, um Dokumente ber einen Socket von einem HTTP 1.1-Server herunterzuladen, doch zunchst ein wenig Motivation. Eventuell sind Sie ja bereits stolzer Besitzer einer eigenen Domain und hosten diese bei einem Anbieter wie Strato, 1und1 etc. Dies bedeutet, dass Sie zwar rechtlicher Inhaber Ihrer Domain sind, alle Aufrufe ber das Internet jedoch auf die Server Ihres Webhosters umgeleitet und die Dokumente von dort heruntergeladen werden. Abhngig von Ihrem Vertrag stellt Ihnen Ihr Webhoster dabei einen dedizerten (virtuellen) Server zur Verfgung oder lsst die Anfrage von einem Rechner beantworten, der neben Ihrer Domain auch fr eine Reihe weiterer Domains verantwortlich ist. Dieses Konzept wird auch als Virtueller Host bezeichnet. Daraus kann sich aber nun folgendes Problem ergeben: Angenommen Sie sind der Besitzer der Domain abc.de und hosten diese auf dem gleichen Server wie der Inhaber der Domain xyz.de. Außerdem beinhalten beide Internetauftritte das Dokument index.html. In dieser Konstellation wird der Server nun ber seine IP-Netzwerkadresse angesprochen und aufgefordert, die Ressource index.html zu bermitteln. Da diese jedoch doppelt vorhanden ist, bençtigt der Server zustzlich die Information, unter welcher URL die betreffende Ressource zu finden sein soll. Um das oben geschilderte Problem zu lçsen, wurde mit HTTP 1.1 der zustzliche Request-Header Host eingefhrt, dessen Wert die angeforderte Domain enthlt. Auf diese Weise kann das Konzept der virtuellen Hosts realisiert werden, da der Server die angeforderten Ressourcen nun eindeutig auflçsen kann. Das folgende Listing zeigt, wie unter Verwendung des Host-Headers ber das HTTP 1.1-Protokoll auf ein Dokument der Domain www.abc.de zugegriffen werden kann. /* Listing4605.java */ import java.net.*; import java.io.*;
Listing 46.5: Laden einer Seite von einem WebServer (HTTP 1.1)
public class Listing4605 { public static void main(String[] args) { if (args.length != 2) { System.err.println( "Usage: java Listing4605
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020
1161
Kapitel 46 Listing 46.5: Laden einer Seite von einem WebServer (HTTP 1.1) (Forts.)
Netzwerkprogrammierung 021 String s = "GET " + args[1] + " HTTP/1.1" + "\r\n"; 022 s += "Host: www.abc.de\r\n\r\n" 023 out.write(s.getBytes()); 024 //Ausgabe lesen und anzeigen 025 int len; 026 byte[] b = new byte[4096]; 027 while ((len = in.read(b)) != -1) { 028 System.out.write(b, 0, len); 029 } 030 //Programm beenden 031 in.close(); 032 out.close(); 033 sock.close(); 034 } catch (IOException e) { 035 System.err.println(e.toString()); 036 System.exit(1); 037 } 038 } 039 }
Zugriff auf einen Webserver unter Verwendung der Klasse URL Die beiden vorangegangenen Beispiele demonstrieren die Arbeitsweise von Sockets am Beispiel des Zugriffs auf eine Internetressource. Dabei wurde, insbesondere beim Zugriff auf einen virtuellen Host, zustzliches Wissen ber das Protokoll HTTP bençtigt. Um den Zugriff auf eine HTTP-Ressource zu vereinfachen stellt Java die Klasse URL aus dem Paket java.net zur Verfgung. Diese bernimmt per Konstruktor die Informationen ber Host, Port, Protokoll und die angeforderte Ressource und çffnet ber die Methode openStream() einen InputStream ber den die Daten abgerufen werden kçnnen. Das folgende Listing demonstriert den Zugriff auf eine Internet-Resssource mit der Klasse java.net.URL Listing 46.6: Laden einer Seite von einem WebServer ber java.net.URL
1162
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
/* Listing4606.java */ import java.net.*; import java.io.*; public class Listing4606 { public static void main(String[] args) { if (args.length != 2) { System.err.println( "Usage: java Listing4606
Server-Sockets 016 017 try { 018 // Aufbau der Connection 019 URL url = new URL("http", args[0], 80, args[1]); 020 021 InputStream in = url.openStream(); 022 int len; 023 byte[] b = new byte[4096]; 024 while ((len = in.read(b)) != -1) { 025 System.out.write(b, 0, len); 026 } 027 028 //Programm beenden 029 in.close(); 030 } catch (IOException e) { 031 System.err.println(e.toString()); 032 System.exit(1); 033 } 034 } 035 }
Kapitel 46 Listing 46.6: Laden einer Seite von einem WebServer ber java.net.URL (Forts.)
Die vorgegangen 3 Abschnitte haben Ihnen gezeigt, wie Sie mit Hilfe eines Sockets und unter stckweiser Implementierung des HTTP Protokolls, sowie unter Verwendung der Klasse java.net.URL auf die Dateien eines Webservers zugreifen. Der nchste Abschnitt demonstriert Ihnen nun, wie Sie das Gegenstck, also einen rudimentren Webserver, in Java implementieren kçnnen.
46.3 Server-Sockets 46.3.1 Die Klasse ServerSocket In den bisherigen Abschnitten hatten wir uns mit dem Entwurf von Netzwerk-Clients beschftigt. Nun wollen wir uns das passende Gegenstck ansehen, uns also mit der Entwicklung von Servern beschftigen. Glcklicherweise ist auch das in Java recht einfach. Der wesentliche Unterschied liegt in der Art des Verbindungsaufbaus, fr den es eine spezielle Klasse ServerSocket gibt. Diese Klasse stellt Methoden zur Verfgung, um auf einen eingehenden Verbindungswunsch zu warten und nach erfolgtem Verbindungsaufbau einen Socket zur Kommunikation mit dem Client zurckzugeben. Bei der Klasse ServerSocket sind im Wesentlichen der Konstruktor und die Methode accept von Interesse: java.net. ServerSocket
Teil VIII
public ServerSocket(int port) throws IOException public Socket accept() throws IOException
1163
Kapitel 46
Netzwerkprogrammierung
Der Konstruktor erzeugt einen ServerSocket fr einen bestimmten Port, also einen bestimmten Typ von Server-Anwendung (siehe Abschnitt 46.1.4, Seite 1147). Anschließend wird die Methode accept aufgerufen, um auf einen eingehenden Verbindungswunsch zu warten. accept blockiert so lange, bis sich ein Client bei der Server-Anwendung anmeldet (also einen Verbindungsaufbau zu unserem Host unter der Portnummer, die im Konstruktor angegeben wurde, initiiert). Ist der Verbindungsaufbau erfolgreich, liefert accept ein Socket-Objekt, das wie bei einer Client-Anwendung zur Kommunikation mit der Gegenseite verwendet werden kann. Anschließend steht der ServerSocket fr einen weiteren Verbindungsaufbau zur Verfgung oder kann mit close geschlossen werden. Wir wollen uns die Konstruktion von Servern an einem Beispiel ansehen. Dazu soll ein einfacher ECHO-Server geschrieben werden, der auf Port 7 auf Verbindungswnsche wartet. Alle eingehenden Daten sollen unverndert an den Client zurckgeschickt werden. Zur Kontrolle sollen sie ebenfalls auf die Konsole ausgegeben werden: Listing 46.7: Ein ECHO-Server fr Port 7
1164
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030
/* SimpleEchoServer.java */ import java.net.*; import java.io.*; public class SimpleEchoServer { public static void main(String[] args) { try { System.out.println("Warte auf Verbindung auf Port 7..."); ServerSocket echod = new ServerSocket(7); Socket socket = echod.accept(); System.out.println("Verbindung hergestellt"); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); int c; while ((c = in.read()) != -1) { out.write((char)c); System.out.print((char)c); } System.out.println("Verbindung beenden"); socket.close(); echod.close(); } catch (IOException e) { System.err.println(e.toString()); System.exit(1); } } }
Server-Sockets
Kapitel 46
Wird der Server gestartet, kann via Telnet oder mit dem EchoClient aus Listing 46.3, Seite 1155 auf den Server zugegriffen werden: telnet localhost 7 Wenn der Server luft, werden alle eingegebenen Zeichen direkt vom Server zurckgesendet und als Echo in Telnet angezeigt. Luft er nicht, gibt es beim Verbindungsaufbau eine Fehlermeldung. INFO
i
i
i
Wird das Programm unter UNIX gestartet, kann es mçglicherweise Probleme geben. Einerseits kann es sein, dass bereits ein ECHO-Server auf Port 7 luft. Er kçnnte nçtigenfalls per Eintrag in inetd.conf oder hnlichen Konfigurationsdateien vorbergehend deaktiviert werden. Andererseits drfen Server auf Ports kleiner 1024 nur mit Root-Berechtigung gestartet werden. Ein normaler Anwender darf dagegen nur Server-Ports grçßer 1023 verwenden.
46.3.2 Verbindungen zu mehreren Clients Wir wollen das im vorigen Abschnitt vorgestellte Programm nun in mehrfacher Hinsicht erweitern: " Der Server soll mehr als einen Client gleichzeitig bedienen kçnnen. Die Clients sollen zur besseren Unterscheidung durchnummeriert werden. " Beim Verbindungsaufbau soll der Client eine Begrßungsmeldung erhalten. " Fr jeden Client soll ein eigener Thread angelegt werden. Um diese Anforderungen zu erfllen, verndern wir das obige Programm ein wenig. Im Hauptprogramm wird nun nur noch der ServerSocket erzeugt und in einer Schleife jeweils mit accept auf einen Verbindungswunsch gewartet. Nach dem Verbindungsaufbau erfolgt die weitere Bearbeitung nicht mehr im Hauptprogramm, sondern es wird ein neuer Thread mit dem Verbindungs-Socket als Argument erzeugt. Dann wird der Thread gestartet und erledigt die gesamte Kommunikation mit dem Client. Beendet der Client die Verbindung, wird auch der zugehçrige Thread beendet. Das Hauptprogramm braucht sich nur noch um den Verbindungsaufbau zu kmmern und ist von der eigentlichen Client-Kommunikation vollstndig befreit. /* EchoServer.java */ import java.net.*; import java.io.*;
Listing 46.8: Eine verbesserte Version des EchoServers
Teil VIII
001 002 003 004 005 006 007 008
public class EchoServer { public static void main(String[] args)
1165
Kapitel 46 Listing 46.8: Eine verbesserte Version des EchoServers (Forts.)
1166
Netzwerkprogrammierung 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056
{ int cnt = 0; try { System.out.println("Warte auf Verbindungen auf Port 7..."); ServerSocket echod = new ServerSocket(7); while (true) { Socket socket = echod.accept(); (new EchoClientThread(++cnt, socket)).start(); } } catch (IOException e) { System.err.println(e.toString()); System.exit(1); } } } class EchoClientThread extends Thread { private int name; private Socket socket; public EchoClientThread(int name, Socket socket) { this.name = name; this.socket = socket; } public void run() { String msg = "EchoServer: Verbindung " + name; System.out.println(msg + " hergestellt"); try { InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); out.write((msg + "\r\n").getBytes()); int c; while ((c = in.read()) != -1) { out.write((char)c); System.out.print((char)c); } System.out.println("Verbindung " + name + " wird beendet"); socket.close(); } catch (IOException e) { System.err.println(e.toString()); } } }
Server-Sockets
Kapitel 46
Zur besseren bersicht werden alle Client-Verbindungen durchnummeriert und als erstes Argument an den Thread bergeben. Unmittelbar nach dem Verbindungsaufbau wird diese Meldung auf der Server-Konsole ausgegeben und an den Client geschickt. Anschließend wird in einer Schleife jedes vom Client empfangene Zeichen an diesen zurckgeschickt, bis er von sich aus die Verbindung unterbricht. Man kann den Server leicht testen, indem man mehrere Telnet-Sessions zu ihm aufbaut. Jeder einzelne Client sollte eine Begrßungsmeldung mit einer eindeutigen Nummer erhalten und autonom mit dem Server kommunizieren kçnnen. Der Server sendet alle Daten zustzlich an die Konsole und gibt sowohl beim Starten als auch beim Beenden eine entsprechende Meldung auf der Konsole aus.
46.3.3 Entwicklung eines einfachen Web-Servers In Abschnitt 46.2.4, Seite 1158 war schon angeklungen, dass ein Web-Server in seinen Grundfunktionen so einfach aufgebaut ist, dass wir uns hier eine experimentelle Implementierung ansehen kçnnen. Diese ist nicht nur zu bungszwecken ntzlich, sondern wird uns in Kapitel 47, Seite 1179 bei der RMI-Programmierung behilflich sein, Bytecode »on demand« zwischen Client und Server zu bertragen. Die Kommunikation zwischen einem Browser und einem Web-Server entspricht etwa folgendem Schema: " Der Web-Browser baut eine Verbindung zum Server auf. " Er schickt eine Seitenanforderung und ein paar zustzliche Informationen in Form eines Request gemß HTTP-Spezifikation. " Der Server analysiert den Request und schickt die gewnschte Datei (bzw. eine Fehlermeldung) an den Browser. " Der Server beendet die Verbindung. Hat der Browser auf diese Weise eine HTML-Seite erhalten, interpretiert er den HTMLCode und zeigt die Seite formatiert auf dem Bildschirm an. Enthlt die Datei IMG-, APPLET- oder hnliche Elemente, werden diese in derselben Weise vom Server angefordert und in die Seite eingebaut. Die wichtigste Aufgabe des Servers besteht also darin, eine Datei an den Client zu bertragen. Wir wollen uns zunchst das Listing ansehen und dann auf Details der Implementierung eingehen: /* ExperimentalWebServer.java */ import java.io.*; import java.util.*; import java.net.*;
Listing 46.9: Ein experimenteller Web-Server
Teil VIII
001 002 003 004 005 006 007 008 009
/** * Ein ganz einfacher Web-Server auf TCP und einem * beliebigen Port. Der Server ist in der Lage,
1167
Kapitel 46 Listing 46.9: Ein experimenteller Web-Server (Forts.)
1168
Netzwerkprogrammierung 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058
* Seitenanforderungen lokal zu dem Verzeichnis, * aus dem er gestartet wurde, zu bearbeiten. Wurde * der Server z.B. im Verzeichnis c:\tmp gestartet, so * wrde eine Seitenanforderung * http://localhost:80/test/index.html die Datei * c:\tmp\test\index.html laden. CGIs, SSIs, Servlets * oder hnliches wird nicht untersttzt. *
Server-Sockets {"html", {"htm", {"txt", {"gif", {"jpg", {"jpeg", {"jnlp",
"text/html"}, "text/html"}, "text/plain"}, "image/gif"}, "image/jpeg"}, "image/jpeg"}, "application/x-java-jnlp-file"}
Listing 46.9: Ein experimenteller Web-Server (Forts.)
}; private private private private private private private
Socket int PrintStream InputStream String String String
socket; id; out; in; cmd; url; httpversion;
/** * Erzeugt einen neuen Client-Thread mit der angegebenen * id und dem angegebenen Socket. */ public BrowserClientThread(int id, Socket socket) { this.id = id; this.socket = socket; } /** * Hauptschleife fr den Thread. */ public void run() { try { System.out.println(id + ": Incoming call..."); out = new PrintStream(socket.getOutputStream()); in = socket.getInputStream(); readRequest(); createResponse(); socket.close(); System.out.println(id + ": Closed."); } catch (IOException e) { System.out.println(id + ": " + e.toString()); System.out.println(id + ": Aborted."); } }
Teil VIII
059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107
Kapitel 46
/** * Liest den nchsten HTTP-Request vom Browser ein. */
1169
Kapitel 46 Listing 46.9: Ein experimenteller Web-Server (Forts.)
1170
Netzwerkprogrammierung 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
private void readRequest() throws IOException { //Request-Zeilen lesen Vector request = new Vector(10); StringBuffer sb = new StringBuffer(100); int c; while ((c = in.read()) != -1) { if (c == '\r') { //ignore } else if (c == '\n') { //line terminator if (sb.length() <= 0) { break; } else { request.addElement(sb); sb = new StringBuffer(100); } } else { sb.append((char)c); } } //Request-Zeilen auf der Konsole ausgeben Enumeration e = request.elements(); while (e.hasMoreElements()) { sb = (StringBuffer)e.nextElement(); System.out.println("< " + sb.toString()); } //Kommando, URL und HTTP-Version extrahieren String s = ((StringBuffer)request.elementAt(0)).toString(); cmd = ""; url = ""; httpversion = ""; int pos = s.indexOf(' '); if (pos != -1) { cmd = s.substring(0, pos).toUpperCase(); s = s.substring(pos + 1); //URL pos = s.indexOf(' '); if (pos != -1) { url = s.substring(0, pos); s = s.substring(pos + 1); //HTTP-Version pos = s.indexOf('\r'); if (pos != -1) { httpversion = s.substring(0, pos); } else { httpversion = s; } } else {
Server-Sockets url = s; } } }
Listing 46.9: Ein experimenteller Web-Server (Forts.)
/** * Request bearbeiten und Antwort erzeugen. */ private void createResponse() { if (cmd.equals("GET") || cmd.equals("HEAD")) { if (!url.startsWith("/")) { httpError(400, "Bad Request"); } else { //MIME-Typ aus Dateierweiterung bestimmen String mimestring = "application/octet-stream"; for (int i = 0; i < mimetypes.length; ++i) { if (url.endsWith(mimetypes[i][0])) { mimestring = mimetypes[i][1]; break; } } //URL in lokalen Dateinamen konvertieren String fsep = System.getProperty("file.separator", "/"); StringBuffer sb = new StringBuffer(url.length()); for (int i = 1; i < url.length(); ++i) { char c = url.charAt(i); if (c == '/') { sb.append(fsep); } else { sb.append(c); } } try { FileInputStream is = new FileInputStream(sb.toString()); //HTTP-Header senden out.print("HTTP/1.0 200 OK\r\n"); System.out.println("> HTTP/1.0 200 OK"); out.print("Server: ExperimentalWebServer 0.5\r\n"); System.out.println( "> Server: ExperimentalWebServer 0.5" ); out.print("Content-type: " + mimestring + "\r\n\r\n"); System.out.println("> Content-type: " + mimestring); if (cmd.equals("GET")) { //Dateiinhalt senden byte[] buf = new byte[256]; int len; while ((len = is.read(buf)) != -1) {
Teil VIII
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
Kapitel 46
1171
Kapitel 46 Listing 46.9: Ein experimenteller Web-Server (Forts.)
Netzwerkprogrammierung 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 }
out.write(buf, 0, len); } } is.close(); } catch (FileNotFoundException e) { httpError(404, "Error Reading File"); } catch (IOException e) { httpError(404, "Not Found"); } catch (Exception e) { httpError(404, "Unknown exception"); } } } else { httpError(501, "Not implemented"); } } /** * Eine Fehlerseite an den Browser senden. */ private void httpError(int code, String description) { System.out.println("> ***" + code + ": " + description + "***"); out.print("HTTP/1.0 " + code + " " + description + "\r\n"); out.print("Content-type: text/html\r\n\r\n"); out.println(""); out.println("HTTP/1.0 " + code + "
"); out.println("" + description + "
"); out.println(""); out.println(""); }
Der Web-Server besteht aus den beiden Klassen ExperimentalWebServer und BrowserClientThread, die nach dem in Abschnitt 46.3.2, Seite 1165 vorgestellten Muster aufgebaut sind. Nachdem in ExperimentalWebServer eine Verbindung aufgebaut wurde, wird ein neuer Thread erzeugt und die weitere Bearbeitung des Request an ein Objekt der Klasse BrowserClientThread delegiert. Der in run liegende Code beschafft zunchst die Ein- und Ausgabestreams zur Kommunikation mit dem Socket und ruft dann die beiden Methoden readRequest und createResponse auf. Anschließend wird der Socket geschlossen und der Thread beendet. In readRequest wird der HTTP-Request des Browsers gelesen, der aus mehreren Zeilen besteht. In der ersten wird die eigentliche Dateianforderung angegeben, die brigen
1172
Server-Sockets
Kapitel 46
liefern Zusatzinformationen wie den Typ des Browsers, akzeptierte Dateiformate und hnliches. Alle Zeilen werden mit CRLF abgeschlossen, nach der letzten Zeile des Request wird eine Leerzeile gesendet. Entsprechend der Empfehlung in RFC1945 ignoriert unser Parser die '\r'-Zeichen und erkennt das Zeilenende anhand eines '\n'. So arbeitet er auch dann noch korrekt, wenn ein Client die Headerzeilen versehentlich mit einem einfachen LF abschließt. Ein typischer Request kçnnte etwa so aussehen (in diesem Beispiel wurde er von Netscape 4.04 unter Windows 95 generiert): GET /ansisys.html HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.04 [en] (Win95; I) Host: localhost:80 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* Accept-Language: en Accept-Charset: iso-8859-1,*,utf-8 HTTP/1.0 200 OK Server: ExperimentalWebServer 0.5 Content-type: text/html Unser Web-Server liest den Request zeilenweise in den Vector request ein und gibt alle Zeilen zur Kontrolle auf der Konsole aus. Anschließend wird das erste Element extrahiert und in die Bestandteile Kommando, URL (Dateiname) und HTTP-Version zerlegt. Diese Informationen werden zur weiteren Verarbeitung in den Membervariablen cmd, url und httpversion gespeichert. Nachdem der Request gelesen wurde, wird in createResponse die Antwort erzeugt. Zunchst prft die Methode, ob es sich um ein GET- oder HEAD-Kommando handelt (HTTP kennt noch mehr). Ist das nicht der Fall, wird durch Aufruf von httpError eine Fehlerseite an den Browser gesendet. Andernfalls fhrt die Methode mit der Bestimmung des Dateityps fort. Der Dateityp wird mit Hilfe der Arraykonstante mimetypes anhand der Dateierweiterung bestimmt und in einen passenden MIME-Typ konvertiert, der im Antwortheader an den Browser bertragen wird. Der Browser entscheidet anhand dieser Information, was mit der nachfolgend bertragenen Datei zu tun ist (Anzeige als Text, Anzeige als Grafik, Speichern in einer Datei usw.). Wird eine Datei angefordert, deren Erweiterung nicht bekannt ist, sendet der Server sie als application/octet-stream an den Browser, damit dieser dem Anwender die Mçglichkeit geben kann, die Datei auf der Festplatte zu speichern.
i
i
i
Teil VIII
INFO Der Mime-Typ application/x-java-jnlp-file wird fr den Betrieb von Java Web Start bençtigt. Dieses seit dem JDK 1.4 verfgbare Werkzeug zum Laden, Aktualisieren und
1173
Kapitel 46
Netzwerkprogrammierung
Starten von Java-Programmen ber Internetverbindungen wird ausfhrlich in Abschnitt 13.5, Seite 322 erlutert.
Nun wandelt der Server den angegebenen Dateinamen gemß den Konventionen seines eigenen Betriebssystems um. Dazu wird das erste »/« aus dem Dateinamen entfernt (alle Dateien werden lokal zu dem Verzeichnis geladen, aus dem der Server gestartet wurde) und alle »/« innerhalb des Pfadnamens werden in den lokalen Pfadseparator konvertiert (unter MS-DOS ist das beispielsweise der Backslash). Dann wird die Datei mit einem FileInputStream geçffnet und der HTTP-Header und der Dateiinhalt an den Client gesendet. Konnte die Datei nicht geçffnet werden, wird eine Ausnahme ausgelçst und der Server sendet eine Fehlerseite. Der vom Server gesendete Header ist hnlich aufgebaut wie der Request-Header des Clients. Er enthlt mehrere Zeilen, die durch CRLF-Sequenzen voneinander getrennt sind. Nach der letzten Headerzeile folgt eine Leerzeile, also zwei aufeinanderfolgende CRLFSequenzen. HTTP 1.0 und 1.1 spezifizieren eine ganze Reihe von (optionalen) Headerelementen, von denen wir lediglich die Versionskennung, unseren Server-Namen und den MIME-Bezeichner mit der Typkennung der gesendeten Datei an den Browser bertragen. Unmittelbar nach dem Ende des Headers wird der Dateiinhalt bertragen. Eine Umkodierung erfolgt dabei normalerweise nicht, alle Bytes werden unverndert bertragen. Unser Server kann sehr leicht getestet werden. Am einfachsten legt man ein neues Unterverzeichnis an und kopiert die bersetzten Klassendateien und einige HTML-Dateien in dieses Verzeichnis. Nun kann der Server wie jedes andere Java-Programm gestartet werden. Beim Aufruf ist zustzlich die Port-Nummer als Argument anzugeben: java ExperimentalWebServer 80 Nun kann ein normaler Web-Browser verwendet werden, um Dateien vom Server zu laden. Befindet sich beispielsweise eine Datei index.html im Server-Verzeichnis und luft der Server auf derselben Maschine wie der Browser, kann die Datei ber die Adresse http://localhost/index.html im Browser geladen werden. Auch ber das lokale Netz des Unternehmens oder das Internet kçnnen leicht Dateien geladen werden. Hat der Host, auf dem der Server luft, keinen Nameserver-Eintrag, kann stattdessen auch direkt seine IP-Adresse im Browser angegeben werden.
!
!
!
ACHTUNG Auf einem UNIX-System darf ein Server die Port-Nummer 80 nur verwenden, wenn er Root-Berechtigung hat. Ist das nicht der Fall, kann der Server alternativ auf einem Port grçßer 1023 gestartet werden:
java ExperimentalWebServer 7777 Im Browser muss die Adresse dann ebenfalls um die Port-Nummer ergnzt werden: http://localhost:7777/index.html.
1174
Daten mit Hilfe der Klasse URL lesen
Kapitel 46
46.4 Daten mit Hilfe der Klasse URL lesen Die Klasse URL wurde bereits in Abschnitt 40.1.1, Seite 943 behandelt. Neben den dort beschriebenen Mçglichkeiten besitzt sie Methoden, um Daten von der Quelle zu lesen, die durch den URL adressiert wird: public final InputStream openStream() throws IOException
java.net.URL
public final Object getContent() throws IOException public URLConnection openConnection() throws IOException Mit openStream wird ein InputStream geliefert, der wie die Methode getInputStream der Klasse Socket zum Lesen der Quelldaten verwendet werden kann. getContent versucht darber hinaus, die Daten zu interpretieren. Dazu kçnnen Content Handler Factories registriert werden, die beispielsweise Text-, Image- oder Archivdateien interpretieren und ein dazu passendes Java-Objekt liefern. Die Methode openConnection stellt eine Vorstufe von getContent dar. Sie liefert ein Objekt des Typs URLConnection, das eine Abstraktion einer protokollspezifischen Verbindung zwischen einem Java-Programm und einem URL darstellt. Als einfaches Beispiel wollen wir uns das folgende Programm SaveURL ansehen. Es wird mit einem URL und einer Datei als Argument aufgerufen. Mit Hilfe der Klasse URL stellt das Programm eine Verbindung zur angegebenen URL her und beschafft durch Aufruf von openStream einen InputStream. Mit seiner Hilfe wird die Quelle gelesen und das Ergebnis in die als zweites Argument angegebene Datei geschrieben: /* SaveURL.java */ import java.net.*; import java.io.*;
Listing 46.10: Daten von einem URL lesen
public class SaveURL { public static void main(String[] args) { if (args.length != 2) { System.err.println( "Usage: java SaveURL
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
1175
Kapitel 46 Listing 46.10: Daten von einem URL lesen (Forts.)
Netzwerkprogrammierung 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 } 035 }
try { URL url = new URL(args[0]); OutputStream out = new FileOutputStream(args[1]); InputStream in = url.openStream(); int len; byte[] b = new byte[100]; while ((len = in.read(b)) != -1) { out.write(b, 0, len); } out.close(); in.close(); } catch (MalformedURLException e) { System.err.println(e.toString()); System.exit(1); } catch (IOException e) { System.err.println(e.toString()); System.exit(1); }
Das Programm kann nun leicht verwendet werden, um den Inhalt beliebiger URLs auf der Festplatte abzuspeichern. Die folgenden beiden Aufrufe zeigen den Download der Hauptseite des Java-Servers von SUN und das Laden einer Testseite von unserem in Abschnitt 46.3.3, Seite 1167 vorgestellten Web-Server: java SaveURL http://java.sun.com x.html java SaveURL http://localhost/index.html y.html
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Grundlagen und Anwendungen der Netzwerkprogrammierung " Das ISO/OSI-7-Schichten-Modell und das vereinfachte Vier-Ebenen-Modell " Grundlagen der Protokolle TCP und IP " IP-Adressen, Netztypen und Domain-Namen " Port-Nummern und Applikationen " Request For Comments " Das Konzept der Sockets " Die Klasse InetAddress zur Adressierung von Socket-Verbindungen " Die besonderen Adressen localhost und 127.0.0.1
1176
Zusammenfassung
Kapitel 46
" Aufbau einer Client-Socket-Verbindung mit Hilfe der Klasse Socket und dem streambasierten Zugriff auf die Daten " Kommunikation mit dem DayTime- und Echo-Server " Lesender Zugriff auf einen Web-Server " Konstruktion von Serverdiensten mit der Klasse ServerSocket " Konstruktion mehrbenutzerfhiger Server mit Threads " Entwurf eines experimentellen Web-Servers
Teil VIII
" Daten mit Hilfe der Klasse URL lesen
1177
47
Remote Method Invocation
47.1
Einleitung
47.1.1 Prinzipielle Arbeitsweise Im vorigen Kapitel wurde die Netzwerkprogrammierung mit Hilfe von Sockets und URL-Objekten erlutert. Dabei wurden im Wesentlichen Dienste verwendet, deren Aufgabe es war, Daten zwischen zwei Netzwerkknoten zu bertragen. Hçhere Anwendungen, wie etwa das Kopieren von Dateien, die Manipulation von Verzeichnissen oder das Starten von Programmen auf dem Server, wurden mit zustzlichen Anwendungsprotokollen wie FTP oder HTTP realisiert. Neben der reinen bertragung von Daten besteht eine weitere wichtige Anwendung von Netzwerkstrukturen darin, Programmcode zu verteilen und von unterschiedlichen Arbeitspltzen im Netz aufzurufen. Auf diese Weise kçnnen spezielle Aufgaben einer Applikation (wie etwa der Datenbankzugriff oder die Kommunikation mit externen Systemen) an geeignete Server delegiert und so die Applikationslast gleichmßiger verteilt und die Skalierbarkeit des Systems erhçht werden.
" In einem Remote-Interface werden eine oder mehrere Methoden definiert, die als aufrufbare Dienste anderen Arbeitspltzen zur Verfgung gestellt werden sollen.
Teil VIII
Mit RMI (Remote Method Invocation) stellt das JDK seit der Version 1.1 einen Mechanismus zur Verfgung, der es ermçglicht, Objekte auf einfache Weise im Netz zu verteilen und ihre Dienste anderen Arbeitspltzen zur Verfgung zu stellen. Die prinzipielle Arbeitsweise von RMI lsst sich wie folgt skizzieren (siehe Abbildung 47.1, Seite 1180):
Kapitel 47
Remote Method Invocation
" Eine Serverklasse implementiert das Interface und erzeugt eine oder mehrere Instanzen, die als Remote-Objekte bezeichnet werden. " Die Remote-Objekte werden bei einem Namens-Service registriert, der von potenziellen Clients abgefragt werden kann. Mit der RMI-Registry ist ein einfacher Namens-Service bereits Bestandteil des RMI-Pakets. " Clients beschaffen mit Hilfe der RMI-Registry Referenzen auf die bençtigten Objekte und rufen die gewnschten Methoden auf. Die beim Aufruf bergebenen Parameter werden an das Remote-Objekt bertragen und die passende Methode wird dort ausgefhrt. Der Rckgabewert wird an den Client zurckbertragen. Die Referenzen auf die Remote-Objekte werden als Remote-Referenzen bezeichnet. Abbildung 47.1: Prinzipielle Arbeitsweise von RMI
RMI-Registry Suche
Client
Registrierung
Virtueller Aufruf
Server RemoteObjekte
RMI etabliert also eine Client-Server-Architektur zwischen lokalen Java-Objekten und den von ihnen aufgerufenen Remote-Objekten. Die eigentliche Kommunikation zwischen den Teilnehmern ist fast vollstndig unsichtbar. Die Rollen von Client und Server sind dabei keineswegs statisch festgelegt. So kann ein Client durchaus Server-Funktionalitten implementieren oder ein Server kann zur Ausfhrung eines Client-Call die Hilfe eines anderen Remote-Objekts in Anspruch nehmen. Eine interessante Eigenschaft von RMI besteht auch darin, fehlenden Code dynamisch nachzuladen. Bençtigt beispielsweise ein Server zur Ausfhrung eines Auftrags eine bis dato unbekannte Klasse vom Client (die natrlich ein ihm zur Compilezeit bekanntes Interface implementiert), so kann er diese dynamisch vom Client laden und – dank der Plattformunabhngigkeit von Java – auf dem Server ausfhren.
47.1.2 Einzelheiten der Kommunikation Bei der Kommunikation mit RMI hat der Client den Eindruck, Methoden von Objekten aufzurufen, die auf dem Server liegen. In Wirklichkeit liegen die Dinge natrlich etwas komplizierter, denn der Client hat von der RMI-Registry lediglich ein Stub-Objekt erhalten und das Remote-Objekt hat den Server nicht wirklich verlassen. Ein Stub ist eine Klasse, die – wie das implementierende Remote-Objekt – das Remote-Interface implementiert und daher fr den Client als Platzhalter fr den Zugriff auf das Remote-Objekt dient.
1180
Einleitung
Kapitel 47
Der Stub kommuniziert ber eine TCP-Verbindung mit dem als Skeleton bezeichneten Gegenstck auf der Server-Seite. Das Skeleton kennt das tatschliche Applikationsobjekt, leitet die Anfragen des Stubs an dieses weiter und gibt den Rckgabewert an ihn zurck. Stub und Skeleton werden whrend der Entwicklung mit Hilfe eines Tools generiert und verbergen die komplizierten Details der Kommunikation zwischen Server und Client. Client
Virtuelle Kommunikation
Server
Stub
Skeleton
Remote Reference Layer
Remote Reference Layer
Abbildung 47.2: Stubs und Skeletons
Netzwerkverbindung
INFO
i
i
i
RMI verfolgt mit der Verteilung von Objekten im Netz einen hnlichen Ansatz wie CORBA (die Common Object Request Broker Architecture, siehe beispielsweise http://www.omg.org). Da auch CORBA von Java sehr gut untersttzt wird, muss man sich als Entwickler natrlich die Frage stellen, welche der beiden Architekturen in einem entsprechenden Projekt die bessere Wahl ist. Fr CORBA spricht die Vielzahl der verfgbaren Implementierungen, die grçßere Verbreitung und die Tatsache, dass neben Java auch andere Programmiersprachen untersttzt werden (etwa C++). Es ist daher ideal fr heterogene Projekte, deren Grçße eine gewisse kritische Masse berschreiten. RMI ist dagegen einfacher zu erlernen, bietet dynamischen Code-Austausch, erfordert keine zustzlichen Lizenzen und kommt mit insgesamt weniger Aufwand aus. Fr reine Java-Projekte kçnnte es sich daher als geeignete Wahl erweisen. Seit der Version 1.3 untersttzt das JDK die RMI-Kommunikation auch auf der Basis des CORBA-Protokolls IIOP und erleichtert so die Integration von RMI- und CORBA-Anwendungen.
Bei der Kommunikation zwischen Client und Server (wenn also der Client eine Methode auf einem Remote-Objekt aufruft) sind drei Arten von Datentypen zu unterscheiden: " Werden beim Aufruf einer Methode primitive Datentypen bergeben oder zurckgegeben (int, char, boolean usw.), werden sie wie gewçhnlich per Wert bergeben (call by value). In diesem Fall besteht also berhaupt kein Unterschied zu lokalen Java-Programmen.
Teil VIII
" Lokale Objekte kçnnen dagegen nur dann als Parameter oder Rckgabewert verwendet werden, wenn sie serialisierbar sind. Sie werden bei der bertragung kopiert und somit ebenfalls per Wert bergeben (siehe Kapitel 41, Seite 963). Viele Klassen des JDK, wie etwa String, Calendar, die numerischen Wrapper-Klassen oder die Collection-Klassen sind bereits serialisierbar und kçnnen direkt verwendet werden. Eigene Klassen mssen das Interface Serializable implementieren.
1181
Kapitel 47
Remote Method Invocation
" Verweise auf Remote-Objekte, wie sie beispielsweise vom Namens-Service zurckgegeben werden, haben dagegen Referenzcharakter und werden wie gewçhnliche Objektreferenzen behandelt.
!
!
!
ACHTUNG Objekte, die weder Remote-Referenzen noch serialisierbar sind, kçnnen per RMI nicht ausgetauscht werden. Beispiele dafr sind die Klassen Thread, System oder RandomAccessFile. Derartige Objekte haben allerdings auch meist nur lokale Bedeutung und die bertragung an eine andere virtuelle Maschine macht wenig Sinn.
47.2
Aufbau eines einfachen Uhrzeit-Services
47.2.1 Vorgehensweise In diesem Abschnitt wollen wir eine einfache Client-Server-Anwendung entwickeln und dabei die wichtigsten Eigenschaften von RMI vorstellen. Dazu soll ein Remote-Interface TimeService geschrieben werden, das zwei Methoden getTime und storeTime definiert. Mit getTime kann ein Client die aktuelle Uhrzeit auf dem Server ermitteln und sie sich als String zurckgeben lassen. storeTime erledigt prinzipiell dieselbe Aufgabe, speichert die Uhrzeit aber in einem TimeStore-Objekt, an dem wir die Besonderheiten des Austauschs von Objekttypen zeigen wollen. Der Server, der auf einem Computer mit dem Namen »ph01« luft, wird ein einziges Remote-Objekt instanzieren und bei der ebenfalls auf »ph01« laufenden RMI-Registry unter dem Namen »TimeService« registrieren. Ein einfaches Client-Programm auf dem Rechner »ph02« wird bei der RMI-Registry eine Remote-Referenz auf das TimeServiceObjekt beschaffen, mit seiner Hilfe die Uhrzeit des Servers abfragen und die Ergebnisse auf seiner eigenen Console ausgeben. Da insbesondere das Setup der Systeme einigen Aufwand erfordert, wollen wir die einzelnen Schritte genau erlutern: " Zunchst wird das Remote-Interface erlutert. " Anschließend stellen wir seine Implementierung vor und zeigen, wie Stub und Skeleton erzeugt werden. " Danach erlutern wir, wie die RMI-Registry und der Server gestartet werden und welche Vorbereitungen dazu erforderlich sind. " Schließlich implementieren wir eine Client-Klasse und zeigen, wie sie gestartet und zum Zugriff auf den Server verwendet wird.
1182
Aufbau eines einfachen Uhrzeit-Services
Kapitel 47
47.2.2 Das Remote-Interface Das Remote-Interface definiert die Schnittstelle zwischen Client und Server. Bei seiner Entwicklung mssen einige Regeln beachtet werden: " Das Remote-Interface muss aus dem Interface Remote des Pakets java.rmi abgeleitet und als public deklariert werden. " Jede Methode muss die Exception RemoteException (ebenfalls aus dem Paket java.rmi) deklarieren. Hiermit werden alle Arten von Netzwerkproblemen oder Verbindungsstçrungen zwischen Client und Server angezeigt. Nur die im Remote-Interface definierten Methoden stehen spter den Clients zur Verfgung. Werden spter bei der Implementierung des Servers weitere Methoden hinzugefgt, so bleiben sie fr den Client unsichtbar. Das Remote-Interface fr unseren UhrzeitService sieht so aus: 001 002 003 004 005 006 007 008 009 010 011 012 013 014
/* TimeService.java */ import java.rmi.*; import java.util.*;
Listing 47.1: Das RemoteInterface fr den Uhrzeit-Service
public interface TimeService extends Remote { public String getTime() throws RemoteException; public TimeStore storeTime(TimeStore store) throws RemoteException; }
Die Methode getTime liefert einen String mit der aktuellen Server-Uhrzeit im Format »h[h]:m[m]:s[s]«. Die Methode storeTime erwartet ein Objekt vom Typ TimeStore, um den Uhrzeitstring dort hineinzuschreiben. Da Objekte (wegen der zur bertragung erforderlichen Serialisierung) per Wert bergeben werden, wrde jede nderung an ihnen auf Client-Seite unsichtbar bleiben. storeTime gibt daher das TimeStore-Objekt mit der eingefgten Uhrzeit als Rckgabewert an den Client zurck. TimeStore wird als Interface wie folgt definiert: import java.io.Serializable; public interface TimeStore extends Serializable { public void setTime(String time);
Listing 47.2: Das TimeStoreInterface
Teil VIII
001 002 003 004 005 006 007 008 009
public String getTime(); }
1183
Kapitel 47
Remote Method Invocation
Mit setTime wird ein als String bergebener Uhrzeitwert gespeichert, mit getTime kann er abgefragt werden.
i
i
i
INFO Der Grund dafr, TimeStore als Interface zu definieren, liegt darin, dass wir mit seiner Hilfe zeigen wollen, auf welche Weise Code dynamisch zwischen Client und Server bertragen werden kann. Auf der Client-Seite werden wir dazu spter eine Implementierung MyTimeStore verwenden, deren Bytecode server-seitig zunchst nicht bekannt ist, sondern zur Laufzeit nachgeladen wird.
47.2.3 Implementierung des Remote-Interface Die Implementierungsklasse Nach der Definition des Remote-Interface muss dessen Implementierung (also die Klasse fr die Remote-Objekte) realisiert werden. Dazu erstellen wir eine Klasse TimeServiceImpl, die aus UnicastRemoteObject abgeleitet ist und das Interface TimeService implementiert. UnicastRemoteObject stammt aus dem Paket java.rmi.server und ist fr die Details der Kommunikation zwischen Client und Server verantwortlich. Zustzlich berlagert sie die Methoden clone, equals, hashCode und toString der Klasse Object, um den Remote-Referenzen die Semantik von Referenzen zu verleihen.
i
i
i
INFO Der hier verwendete Suffix »Impl« ist lediglich eine Namenskonvention, die anzeigt, dass das Objekt eine Implementierung von »TimeService« ist. Wir htten auch jeden anderen Namen whlen kçnnen. Die Klasse TimeServiceImpl wird spter nur bei der Instanzierung der zu registrierenden Remote-Objekte bençtigt, auf Client-Seite kommt sie berhaupt nicht vor.
Das folgende Listing zeigt die Implementierung: Listing 47.3: Implementierung des UhrzeitServices
1184
001 002 003 004 005 006 007 008 009 010 011 012 013 014
/* TimeServiceImpl.java */ import java.rmi.*; import java.rmi.server.*; import java.util.*; public class TimeServiceImpl extends UnicastRemoteObject implements TimeService { public TimeServiceImpl() throws RemoteException { }
Aufbau eines einfachen Uhrzeit-Services 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 }
public String getTime() throws RemoteException { GregorianCalendar cal = new GregorianCalendar(); StringBuffer sb = new StringBuffer(); sb.append(cal.get(Calendar.HOUR_OF_DAY)); sb.append(":" + cal.get(Calendar.MINUTE)); sb.append(":" + cal.get(Calendar.SECOND)); return sb.toString(); }
Kapitel 47 Listing 47.3: Implementierung des UhrzeitServices (Forts.)
public TimeStore storeTime(TimeStore store) throws RemoteException { store.setTime(getTime()); return store; }
INFO
i
i
i
Der parameterlose Konstruktor ist erforderlich, weil beim (ansonsten automatisch ausgefhrten) Aufruf des Superklassenkonstruktors eine RemoteException ausgelçst werden kçnnte. Ebenso wie die zu implementierenden Methoden kann er also stets eine RemoteException auslçsen.
In getTime wird ein GregorianCalendar-Objekt instanziert und mit der aktuellen Uhrzeit belegt. Aus den Stunden-, Minuten- und Sekundenwerten wird ein StringBuffer erzeugt und nach Konvertierung in einen String an den Aufrufer zurckgegeben. storeTime ist noch einfacher aufgebaut. Es erzeugt zunchst einen Uhrzeitstring, speichert diesen in dem als Parameter bergebenen TimeStore-Objekt und gibt es an den Aufrufer zurck.
Erzeugen von Stub und Skeleton Nachdem die Implementierungsklasse angelegt wurde, mssen Stub und Skeleton erzeugt werden. Diese Arbeit braucht glcklicherweise nicht per Hand erledigt zu werden, sondern kann mit Hilfe des Programms rmic aus dem JDK ausgefhrt werden. rmic erwartet den Namen der Implementierungsklasse als Argument (falls erforderlich, mit der vollen Paketbezeichnung) und erzeugt daraus die beiden Klassendateien fr Stub und Skeleton. Aus der Klasse TimeServiceImpl werden die Klassen TimeServiceImpl_Stub und TimeServiceImpl_Skel erzeugt und als .class-Dateien zur Verfgung gestellt.
Teil VIII
rmic ist ein Kommandozeilenprogramm, das hnliche Optionen wie javac kennt. Im einfachsten Fall reicht es aus, den Namen der Implementierungsklasse anzugeben: rmic TimeServiceImpl
1185
Kapitel 47
*
Remote Method Invocation
*
*
TIPP rmic analysiert den Bytecode der bergebenen Klasse und erzeugt daraus die angegebenen Klassendateien. Falls die Implememtierungsklasse noch nicht bersetzt war, wird dies automatisch erledigt. Wer sich einmal den Quellcode von Stub und Skeleton ansehen mçchte, kann rmic mit der Option »-keep« anweisen, die temporren .java-Dateien nach dem Erzeugen der Klassendateien nicht zu lçschen.
47.2.4 Registrieren der Objekte Starten der RMI-Registry Um den TimeService verwenden zu kçnnen, muss wenigstens eine Instanz von TimeServiceImpl erzeugt und bei der RMI-Registry registriert werden. Diese wird im JDK durch das Kommandozeilenprogramm rmiregistry zur Verfgung gestellt. Es wird auf dem Server gestartet und muss so lange laufen, wie Remote-Objekte dieses Servers verwendet werden sollen. Der einzige Parameter von rmiregistry ist eine optionale TCP-Port-Nummer. Diese gibt an, auf welchem TCP-Port eingehende Anfragen empfangen werden sollen. Sie ist standardmßig auf 1099 eingestellt, kann aber auch auf einen anderen Wert gesetzt werden. Unter UNIX kann man die RMI-Registry im Hintergrund starten: rmiregistry & Unter Windows kann sie direkt von der Kommandozeile oder mit Hilfe des start-Kommandos in einer eigenen DOS-Box gestartet werden: start rmiregistry
Das Programm zur Registrierung des Remote-Objekts Nachdem rmiregistry luft, kçnnen die zur Verfgung stehenden Remote-Objekte registriert werden. Wir verwenden dazu eine eigene Klasse TimeServiceRegistration, in deren main-Methode die Registrierung vorgenommen wird: Listing 47.4: Registrierung von Remote-Objekten
1186
001 002 003 004 005 006 007 008 009 010 011 012
/* TimeServiceRegistration.java */ import java.rmi.*; import java.util.*; public class TimeServiceRegistration { public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { System.out.println("Registering TimeService");
Aufbau eines einfachen Uhrzeit-Services 013 TimeServiceImpl tsi = new TimeServiceImpl(); 014 Naming.rebind("TimeService", tsi); 015 System.out.println(" Done."); 016 } catch (Exception e) { 017 System.err.println(e.toString()); 018 System.exit(1); 019 } 020 } 021 }
Kapitel 47 Listing 47.4: Registrierung von Remote-Objekten (Forts.)
Das Programm erzeugt eine neue Instanz von TimeServiceImpl und bergibt diese unter dem Namen »TimeService« an die RMI-Registry. Dazu wird die statische Methode rebind der Klasse Naming aufgerufen. Naming ist die Programmierschnittstelle zur RMI-Registry, sie stellt folgende Methoden zur Verfgung: public static void bind(String name, Remote obj) throws AlreadyBoundException, MalformedURLException, RemoteException
java.rmi.Naming
public static void rebind(String name, Remote obj) throws RemoteException, MalformedURLException public static void unbind(String name) throws RemoteException, MalformedURLException, NotBoundException public static Remote lookup(String name) throws NotBoundException, MalformedURLException, RemoteException public static String[] list(String name) throws RemoteException, MalformedURLException
Teil VIII
Mit bind wird ein Remote-Objekt unter einem vorgegebenen Namen registriert. Gab es bereits ein Objekt dieses Namens, wird eine Ausnahme ausgelçst. rebind erledigt dieselbe Aufgabe, ersetzt jedoch ein eventuell vorhandenes gleichnamiges Objekt. Mit unbind kann ein registriertes Objekt aus der RMI-Registry entfernt werden. Die Methode lookup dient dazu, zu einem gegebenen Namen eine Remote-Referenz zu erhalten. Sie wird uns beim Client wiederbegegnen. Mit list kann eine Liste der Namen von allen registrierten Remote-Referenzen beschafft werden.
1187
Kapitel 47
Remote Method Invocation
Die an Naming bergebenen Namen haben das Format von URLs (siehe Abschnitt 40.1.1, Seite 943). Die Dienstebezeichnung ist »rmi«, der Rest entspricht einer HTTP-URL. Eine gltige rmi-URL wre also beispielsweise: rmi://ph01:1099/TimeService Der Server heißt hier »ph01« und wird auf Port 1099 angesprochen, der Name des Remote-Objekts ist »TimeService«. Server-Name und Port-Nummer sind optional. Fehlt der Server, wird »localhost« angenommen, fehlt die Port-Nummer, erfolgt die Kommunikation auf TCP-Port 1099. Aus diesem Grund haben wir bei der Registrierung des TimeServiceImpl-Objekts mit »TimeService« lediglich den Namen des Remote-Objekts angegeben.
i
i
i
INFO Der Name, unter dem ein Remote-Objekt bei der RMI-Registry registriert werden soll, ist frei whlbar. Tatschlich hat der in unserem Fall verwendete Begriff »TimeService« nichts mit dem Namen des Interface TimeService zu tun. Er stellt lediglich eine Vereinbarung zwischen Server und Client dar und htte ebenso gut »ts«, »TimeService1« oder »Blablabla« lauten kçnnen.
ndern der Policy-Datei Die in Zeile 010 stehende Installation der Klasse RMISecurityManager ist erforderlich, weil der Server den Code fr die auf dem Client erzeugte TimeStore-Implementierung dynamisch laden soll. Aus Sicherheitsgrnden ist das Laden von externem Bytecode aber nur dann erlaubt, wenn ein SecurityManager installiert ist. Um diesen mit den erforderlichen Rechten auszustatten, muss (ab dem JDK 1.2) die Policy-Datei auf dem Server um folgenden Eintrag ergnzt werden: grant { permission java.net.SocketPermission "ph01:1099", "connect,resolve"; permission java.net.SocketPermission "ph02:80", "connect"; }; Der erste Eintrag ermçglicht die TCP-Kommunikation mit der RMI-Registry auf Port 1099. Der zweite ermçglicht es dem Server, auf TCP-Port 80 eine Verbindung zu dem Rechner mit dem Namen »ph02« herzustellen. Dort wird spter der Web-Server laufen, mit dem der Client die Klassendatei mit der TimeStore-Implementierung zur Verfgung stellt. Am besten ist es, die entsprechenden Eintrge in der benutzerspezifischen Policy-Datei vorzunehmen. Sie liegt im Home-Verzeichnis des aktuellen Benutzers und heißt .java.policy. Auf Windows 95/98-Einzelplatzsystemen liegt sie im Windows-Verzeichnis (meist c:\windows). Weitere Informationen zur Policy-Datei sind im Kapitel ber Sicherheit und Kryptografie in Abschnitt 48.3.4, Seite 1222 zu finden.
1188
Aufbau eines einfachen Uhrzeit-Services
Kapitel 47
Registrierung des Remote-Objekts Nach dem ndern der Policy-Datei kann das Programm zur Registrierung des RemoteObjekts gestartet werden. Damit der Server spter die dynamischen Klassendateien findet, muss das System-Property »java.rmi.server.codebase« gesetzt werden. In unserem Fall handelt es sich um eine http-Verbindung in das WebServer-Root-Verzeichnis auf dem Rechner »ph02«. Der Aufruf des Programms sieht damit wie folgt aus: c:\--->java -Djava.rmi.server.codebase=http://ph02/ TimeServiceRegistration Registering TimeService Done. Er ist nur erfolgreich, wenn die RMI-Registry luft und die entsprechenden nderungen in der Policy-Datei vorgenommen wurden. Andernfalls wird eine Ausnahme ausgelçst und das Programm mit einer Fehlermeldung beendet. War die Registrierung erfolgreich, wird die main-Methode beendet, das Programm luft aber trotzdem weiter. Das liegt daran, dass der Konstruktor von UnicastRemoteObject einen neuen Thread zur Kommunikation mit der RMI-Registry aufgebaut hat, in dem er unter anderem das soeben erzeugte Objekt vorhlt. INFO
i
i
i
Die RMI-Kommunikation zwischen Client und Server kçnnte auch vçllig ohne SecurityManager, Web-Server und nderungen an den Policy-Dateien durchgefhrt werden. In diesem Fall wre es aber nicht mçglich, zur Laufzeit Bytecode zwischen den beiden Maschinen zu bertragen. Alle bençtigten Klassendateien mssten dann im lokalen Klassenpfad des Clients bzw. Servers liegen.
47.2.5 Zugriff auf den Uhrzeit-Service Nach der Implementierung des Servers wollen wir uns nun die Realisierung der ClientSeite ansehen. Dazu soll das folgende Programm verwendet werden: /* TimeServiceClient.java */ import java.rmi.*;
Listing 47.5: Der TimeServiceClient
public class TimeServiceClient { public static void main(String[] args) { try { String host = "ph01"; String port = "1099"; String srv = "TimeService";
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012
1189
Kapitel 47 Listing 47.5: Der TimeServiceClient (Forts.)
Remote Method Invocation 013 String url = "rmi://" + host + ":" + port + "/" + srv; 014 System.out.println("Looking-up TimeService " + url); 015 TimeService ts = (TimeService)Naming.lookup(url); 016 System.out.println(" Server time is " + ts.getTime()); 017 System.out.print(" MyTimeStore contains "); 018 TimeStore tsd = new MyTimeStore(); 019 tsd = ts.storeTime(tsd); 020 System.out.println(tsd.getTime()); 021 } catch (Exception e) { 022 System.err.println(e.toString()); 023 System.exit(1); 024 } 025 026 } 027 }
Das Programm erstellt zunchst den URL-String zur Suche in der RMI-Registry. Er lautet »rmi://ph01:1099/TimeService« und wird in Zeile 015 an die Methode lookup der Klasse Naming bergeben. Falls auf dem Rechner »ph01« eine RMI-Registry auf Port 1099 luft und ein Objekt mit dem Namen »TimeService« vorhlt, wird durch diesen Aufruf eine passende Remote-Referenz erzeugt und der Variablen ts zugewiesen. Deren Methode getTime wird in Zeile 016 aufgerufen und ber die Stub-Skeleton-Verbindung an das TimeServiceImpl-Objekt des Servers weitergeleitet. Der dort erzeugte Rckgabewert wird in umgekehrter Richtung an den Client zurckgegeben (die Klasse String ist standardmßig serialisierbar) und auf dessen Console ausgegeben. Damit das Programm funktioniert, muss zuvor allerdings die Stub-Klasse TimeServiceImpl_Stub.class in das Startverzeichnis der Client-Klasse kopiert werden. Obwohl auch das dynamische bertragen von Stubs leicht mçglich wre, haben wir es hier aus Grnden der bersichtlichkeit nicht realisiert. In Zeile 018 wird eine Instanz der Klasse MyTimeStore erzeugt und an die Methode storeTime des Remote-Objekts bergeben. Dort wird die aktuelle Uhrzeit des Servers eingetragen und das Objekt als Rckgabewert an den Aufrufer zurckgegeben. Vor der Rckbertragung wird es nun ebenfalls serialisiert und landet nach der Deserialisierung durch den Client in Zeile 019 in der Variablen tsd. Der darin enthaltene Uhrzeitstring wird dann ebenfalls auf der Console ausgegeben. Die im Client verwendete Klasse MyTimeStore ist sehr einfach aufgebaut: Listing 47.6: Die Klasse MyTimeStore
1190
001 002 003 004 005 006 007 008
/* MyTimeStore.java */ import java.io.*; public class MyTimeStore implements TimeStore, Serializable { String time;
Aufbau eines einfachen Uhrzeit-Services 009 010 011 012 013 014 015 016 017 018 019 }
public void setTime(String time) { this.time = time; }
Kapitel 47 Listing 47.6: Die Klasse MyTimeStore (Forts.)
public String getTime() { return this.time; }
Sie implementiert das Interface TimeStore, um zu Parameter und Rckgabewert der TimeService-Methode storeTime kompatibel zu sein. Das Interface Serializable implementiert sie dagegen, um vom RMI-Laufzeitsystem zwischen Client und Server bertragen werden zu kçnnen. Die Klasse MyTimeStore ist zunchst nur auf dem Client bekannt und wird dort bersetzt. Wie eingangs erwhnt, besitzt RMI die Fhigkeit, Bytecode dynamisch nachzuladen. Dazu wird allerdings kein eigenes, sondern das aus dem World Wide Web bekannte HTTP-Protokoll verwendet. Wie ein Web-Browser fragt also einer der beiden Teilnehmer per HTTP-GET-Transaktion (siehe Abschnitt 46.2.4, Seite 1158) bei seinem Partner nach der bençtigten Klassendatei. Damit der Server den Bytecode fr MyTimeStore laden kann, muss also auf dem Client ein Web-Server laufen, der den Bytecode auf Anfrage zur Verfgung stellt. Wir kçnnen dazu einfach den in Abschnitt 46.3.3, Seite 1167 entwickelten ExperimentalWebServer verwenden und vor dem Aufruf des Client-Programms in dem Verzeichnis mit der Datei MyTimeStore.class starten: c:\--->start java ExperimentalWebServer 80 Nun kann das Client-Programm gestartet werden: c:\--->java TimeServiceClient Vorausgesetzt, dass die Server-Programme wie zuvor beschrieben gestartet wurden, die Klassendateien MyTimeStore.class, TimeServiceClient.class und TimeServiceImpl_Stub.class auf dem Client vorhanden sind und der Web-Server luft, erhalten wir nun die Verbindung zum Server. Die Ausgabe des Clients sieht etwa so aus:
Teil VIII
Looking-up TimeService rmi://ph01:1099/TimeService Server time is 21:37:47 MyTimeStore contains 21:37:48 Abbildung 47.3, Seite 1192 stellt die Zusammenhnge noch einmal bildlich dar:
1191
Kapitel 47 Abbildung 47.3: Kommunikation im RMI-Beispiel
Remote Method Invocation
PH02
PH01
Web-Server
RMI-Registry
MyTimeStore
TimeServiceClient
Stub
Client-VM
TimeServiceRegistration
Skel
TimeServiceImpl
Server-VM
47.2.6 Ausblick Mit dem vorliegenden Beispiel wurden die grundlegenden Mechanismen von RMI vorgestellt. In der Praxis wird man meist etwas mehr Aufwand betreiben mssen, um eine stabile und performante RMI-Applikation zu erstellen. Nachfolgend seien einige der Aspekte genannt, die dabei von Bedeutung sind: " Zugriffe auf die RMI-Registry kçnnen je nach Konfiguration der Systeme recht kostspielig sein. Es ist daher sinnvoll, nur eines oder wenige Bootstrap-Objekte ber die Registry zu laden und an sie das Beschaffen weiterer Remote-Referenzen zu delegieren. " Die RMI-Registry bietet lediglich eine sehr einfache Abbildung von Namen auf Remote-Objekte. Hierarchische Namensrume, dynamische Objektsuche, Lastverteilung oder hnliche Eigenschaften fehlen ihr dagegen. Mçglicherweise ist es besser, einen anderen Namens-Service zu verwenden. Mit JNDI (Java Naming and Directory Interface) steht dabei seit dem JDK 1.3 bereits eine mçgliche Alternative standardmßig zur Verfgung. " Das dynamische Laden von Bytecode wurde hier nur angedeutet. In der Praxis sollen mçglicherweise auch Stubs dynamisch geladen werden. Andererseits kann vielleicht nicht jeder Client einen eigenen Web-Server zur Verfgung stellen. Die Verteilung des Bytecodes ist also ebenso zu organisieren wie die Verteilung der Objekte. " Auch auf den konkurrierenden Zugriff mehrerer Clients auf ein und dasselbe RemoteObjekt sind wir nicht eingegangen. Tatschlich ist es in der Regel so, dass das RMILaufzeitsystem fr jeden Zugriff eines Clients einen eigenen Thread erzeugt und somit parallel auf das Remote-Objekt zugegriffen wird. Die RMI-Spezifikation schreibt konsequenterweise vor, die Remote-Objekte thread-sicher zu implementieren.
1192
Zusammenfassung
Kapitel 47
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Die prinzipielle Arbeitsweise von RMI " Die Bedeutung der Begriffe Remote-Interface, Remote-Objekt, Remote-Referenz und RMI-Registry " Die Verwendung von Stubs und Skeletons zur Kommunikation zwischen Server und Client " Die drei unterschiedlichen Parameterarten bei der Kommunikation zwischen Client und Server " Entwurf des Remote-Interface TimeService und Bedeutung des Interface Remote " Erstellen der Implementierungsklasse TimeServiceImpl durch Ableiten aus UnicastRemoteObject " Erzeugen von Stub und Skeleton mit rmic " Starten der RMI-Registry durch Aufruf von rmiregistry " Erzeugen und Registrieren von Remote-Objekten und das Format der RMI-URLs " nderungen an den Policy-Dateien zum dynamischen Laden von Bytecode " Entwurf eines Clients zum Zugriff auf den Uhrzeit-Service
Teil VIII
" Verwendung eines Web-Servers zum dynamischen Laden von Bytecode
1193
48
Sicherheit und Kryptografie
48.1
Kryptografische Grundlagen
48.1.1 Wichtige Begriffe Thema dieses Kapitels ist es, die in Java verfgbaren Sicherheitsmechanismen vorzustellen. Wir werden dabei zunchst auf allgemeine Konzepte aus dem Gebiet der Kryptografie und ihre Implementierung in Java eingehen. Anschließend werden die eingebauten Sicherheitsmechanismen von Java vorgestellt. Zum Abschluss zeigen wir, wie signierte Applets erstellt und verwendet werden und wie mit ihrer Hilfe eine fein differenzierte Sicherheitspolitik etabliert werden kann. Zunchst sollen allerdings wichtige Begriffe erlutert werden, die fr das Verstndnis der nachfolgenden Abschnitte von Bedeutung sind.
Teil VIII
Angenommen, ein Sender will eine Nachricht an einen Empfnger bermitteln. Soll das geschehen, ohne dass ein Dritter, dem die Nachricht in die Hnde fallen kçnnte, diese entziffern kann, kçnnte sie verschlsselt werden. Der ursprngliche Nachrichtentext (der als Klartext bezeichnet wird) wird dabei mit Hilfe eines dem Sender bekannten Verfahrens unkenntlich gemacht. Das als Schlsseltext bezeichnete Ergebnis wird an den Empfnger bermittelt und mit Hilfe eines ihm bekannten Verfahrens wieder in den Klartext zurckverwandelt (was als entschlsseln bezeichnet wird).
Kapitel 48 Abbildung 48.1: Verschlsseln einer Nachricht
Sicherheit und Kryptografie
Sender
Empfänger
Klartext
Klartext
Verschlüsselung
Schlüsseltext
Entschlüsselung
Unsicherer Übertragungsweg
Solange der Algorithmus zum Entschlsseln geheim bleibt, ist die Nachricht sicher. Selbst wenn sie auf dem bertragungsweg entdeckt wird, kann kein Dritter sie entschlsseln. Wird das Entschlsselungsverfahren dagegen entdeckt, kann die Nachricht (und mit ihr alle anderen Nachrichten, die mit demselben Verfahren verschlsselt wurden) entziffert werden. Um den Schaden durch das Entdecken eines Verschlsselungsverfahrens gering zu halten, werden die Verschlsselungsalgorithmen in aller Regel parametrisiert. Dazu wird beim Verschlsseln eine als Schlssel bezeichnete Ziffern- oder Zeichenfolge angegeben, mit der die Nachricht verschlsselt wird. Der Empfnger bençtigt dann zustzlich zur Kenntnis des Verfahrens noch den vom Sender verwendeten Schlssel, um die Nachricht entziffern zu kçnnen. Die Wissenschaft, die sich mit dem Verschlsseln und Entschlsseln von Nachrichten und eng verwandten Themen beschftigt, wird als Kryptografie bezeichnet. Liegt der Schwerpunkt mehr auf dem Entschlsseln (insbesondere dem Entziffern geheimer Botschaften), wird dies als Kryptoanalyse bezeichnet. Die Kryptologie schließlich bezeichnet den Zweig der Mathematik, der sich mit den formal-mathematischen Aspekten der Kryptografie und Kryptoanalyse beschftigt.
48.1.2 Einfache Verschlsselungen Substitution Seit dem Altertum sind einfache Verschlsselungsverfahren bekannt. Zu ihnen zhlen beispielsweise die Substitutionsverschlsselungen, bei denen einzelne Buchstaben systematisch durch andere ersetzt werden. Angenommen, Klartexte bestehen nur aus den Buchstaben A bis Z, so kçnnte man sie dadurch verschlsseln, dass jeder Buchstabe des Klartextes durch den Buchstaben ersetzt wird, der im Alphabet um eine feste Anzahl Zeichen verschoben ist. Als Schlssel k kann beispielsweise die Lnge der Verschiebung verwendet werden. Ist k beispielsweise 3, so wrde jedes A durch ein D, jedes B durch ein E, jedes W durch ein Z, jedes X durch ein A usw. ersetzt werden. Dieses einfache Verfahren wurde beispielweise bereits von Julius Csar verwendet, um seinen Generlen geheime Nachrichten zu bermitteln. Es wird daher auch als Csarische
1196
Kryptografische Grundlagen
Kapitel 48
Verschlsselung bezeichnet. Das folgende Listing zeigt eine einfache Implementierung dieses Verfahrens, bei dem Schlssel und Klartext als Argument bergeben werden mssen: 001 002 003 004 005 006 007 008 009 010 011 012 013 014
/* Listing4801.java */ public class Listing4801 { public static void main(String[] args) { int key = Integer.parseInt(args[0]); String msg = args[1]; for (int i = 0; i < msg.length(); ++i) { int c = (msg.charAt(i) - 'A' + key) % 26 + 'A'; System.out.print((char)c); } } }
Listing 48.1: Verschlsselung durch Substitution
Um die Nachricht zu entschlsseln, verwendet der Empfnger dasselbe Verfahren, allerdings mit dem Schlssel 26 - k: --->java Test2 3 HALLO KDOOR --->java Test2 23 KDOOR HALLO
Exklusiv-ODER Ein hnlich weitverbreitetes Verfahren besteht darin, jedes Zeichen des Klartexts mit Hilfe des Exklusiv-ODER-Operators mit dem Schlssel zu verknpfen. Durch dessen Anwendung werden alle Bits invertiert, die zu einem gesetztem Bit im Schlssel korrespondieren, alle anderen bleiben unverndert. Das Entschlsseln erfolgt durch erneute Anwendung des Verfahrens mit demselben Schlssel. INFO
i
i
i
Ein Verfahren, bei dem Ver- und Entschlsselung mit demselben Algorithmus und Schlssel durchgefhrt werden, wird als symmetrische Verschlsselung bezeichnet.
001 /* Listing4802.java */ 002 003 public class Listing4802 004 { 005 public static void main(String[] args)
Listing 48.2: Verschlsselung mit Exklusiv-ODER
1197
Teil VIII
Eine einfache Implementierung der Exklusiv-ODER-Verschlsselung zeigt folgendes Listing:
Kapitel 48
Sicherheit und Kryptografie
Listing 48.2: Verschlsselung mit Exklusiv-ODER (Forts.)
006 { 007 int key = Integer.parseInt(args[0]); 008 String msg = args[1]; 009 for (int i = 0; i < msg.length(); ++i) { 010 System.out.print((char)(msg.charAt(i) ^ key)); 011 } 012 } 013 }
Ein Anwendungsbeispiel kçnnte so aussehen: --->java Test2 65 hallo ) --. --->java Test2 65 ") --." hallo
!
!
!
ACHTUNG Dass die Rckkonvertierung ber die Kommandozeile hier geklappt hat, liegt daran, dass die Verschlsselung keine nichtdarstellbaren Sonderzeichen produziert hat (der Schlssel 65 kippt lediglich 2 Bits in jedem Zeichen). Im Allgemeinen sollte der zu ver- oder entschlsselnde Text aus einer Datei gelesen und das Resultat auch wieder in eine solche geschrieben werden. Dann kçnnen alle 256 mçglichen Bitkombinationen je Byte zuverlssig gespeichert und bertragen werden.
Vorsicht! Derart einfache Verschlsselungen wie die hier vorgestellten sind zwar weit verbreitet, denn sie sind einfach zu implementieren. Leider bieten sie aber nicht die geringste Sicherheit gegen ernsthafte Krypto-Attacken. Einige der in letzter Zeit bekannt gewordenen (und fr die betroffenen Unternehmen meist peinlichen, wenn nicht gar kostspieligen) Flle von Einbrchen in Softwaressysteme waren auf die Verwendung von zu einfachen Sicherheitssystemen zurckzufhren. Wir wollen diesen einfachen Verfahren nun den Rcken zukehren, denn seit dem JDK 1.2 gibt es in Java Mçglichkeiten, professionelle Sicherheitskonzepte zu verwenden. Es ist ein großer Vorteil der Sprache, dass auf verschiedenen Ebenen Sicherheitsmechanismen fest eingebaut wurden und eine missbruchliche Anwendung der Sprache erschwert wird. In den folgenden Abschnitten werden wir die wichtigsten dieser Konzepte vorstellen.
i
i
i
INFO Allerdings sollte dieser Abschnitt nicht als umfassende Einfhrung in die Grundlagen der Kryptografie missverstanden werden. Das Thema ist ausgesprochen vielschichtig, mathematisch anspruchsvoll und es erfordert in seiner Detailflle weitaus mehr Raum als hier zur Verfgung steht. Wir werden neue Begriffe nur so weit einfhren, wie sie fr das Verstndnis der entsprechenden Abschnitte erforderlich sind. Fr Details sei auf weiterfhrende
1198
Kryptografische Grundlagen
Kapitel 48
Literatur verwiesen. Ein sehr gelungenes Buch ist »Applied Cryptography« von Bruce Schneier. Es bietet einen umfassenden und dennoch verstndlichen Einblick in die gesamte Materie und ist interessant zu lesen. Gleichermaßen unterhaltsam wie lehrreich ist auch die in »Geheime Botschaften« von Simon Singh dargestellte Geschichte der Kryptografie.
48.1.3 Message Digests Ein Message Digest ist eine Funktion, die zu einer gegebenen Nachricht eine Prfziffer berechnet. Im Gegensatz zu hnlichen Verfahren, die keine kryptografische Anwendung haben (siehe z.B. hashCode in Abschnitt 8.1.2, Seite 179), muss ein Message Digest zustzlich folgende Eigenschaften besitzen: " Die Wahrscheinlichkeit, dass zwei unterschiedliche Nachrichten dieselbe Prfsumme haben, muss vernachlssigbar gering sein. " Es muss praktisch unmçglich sein, aus der berechneten Prfsumme auf die ursprngliche Nachricht zurckzuschließen. Ein Message Digest wird daher auch als Einweg-Hashfunktion bezeichnet. Er ist meist 16 oder 20 Byte lang und kann als eine Art komplizierte mathematische Zusammenfassung der Nachricht angesehen werden. Message Digests haben Anwendungen im Bereich digitaler Unterschriften und bei der Authentifizierung. Allgemein gesprochen werden sie dazu verwendet, sicherzustellen, dass eine Nachricht nicht verndert wurde. Bevor wir auf diese Anwendungen in den nchsten Abschnitten zurckkommen, wollen wir uns ihre Implementierung im JDK 1.2 ansehen. Praktisch alle wichtigen Sicherheitsfunktionen sind im Paket java.security oder einem seiner Unterpakete untergebracht. Ein Message Digest wird durch die Klasse MessageDigest implementiert. Deren Objekte werden nicht direkt instanziert, sondern mit der Methode getInstance erstellt: public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException
java.security. MessageDigest
Als Argument wird dabei die Bezeichnung des gewnschten Algorithmus angegeben. Im JDK 1.2 sind beispielsweise folgende Angaben mçglich: " »SHA«: der 160-Bit lange »Secure Hash Algorithm« des amerikanischen National Institute of Standards and Technology " »MD5«: der 128-Bit lange »Message Digest 5« von Ron L. Rivest
Teil VIII
Nachdem ein MessageDigest-Objekt erzeugt wurde, bekommt es die Daten, zu denen die Prfziffer berechnet werden soll, in einzelnen Bytes oder Byte-Arrays durch fortgesetzten Aufruf der Methode update bergeben:
1199
Kapitel 48
Sicherheit und Kryptografie
public void update(byte input) public void update(byte[] input) public void update(byte[] input, int offset, int len)
java.security. MessageDigest
Wurden alle Daten bergeben, kann durch Aufruf von digest das Ergebnis ermittelt werden: java.security. MessageDigest
public byte[] digest() Zurckgegeben wird ein Array von 16 bzw. 20 Byte (im Falle anderer Algorithmen mçglicherweise auch andere Lngen), in dem der Message Digest untergebracht ist. Ein Aufruf fhrt zudem dazu, dass der Message Digest zurckgesetzt, also auf den Anfangszustand initialisiert, wird. Das folgende Listing zeigt, wie ein Message Digest zu einer beliebigen Datei erstellt wird. Sowohl Algorithmus als auch Dateiname werden als Kommandozeilenargumente bergeben:
Listing 48.3: Erstellen eines Message Digest
1200
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
/* Listing4803.java */ import java.io.*; import java.security.*; public class Listing4803 { /** * Konvertiert ein Byte in einen Hex-String. */ public static String toHexString(byte b) { int value = (b & 0x7F) + (b < 0 ? 128 : 0); String ret = (value < 16 ? "0" : ""); ret += Integer.toHexString(value).toUpperCase(); return ret; } public static void main(String[] args) { if (args.length < 2) { System.out.println( "Usage: java Listing4803 md-algorithm filename" ); System.exit(0); } try { //MessageDigest erstellen MessageDigest md = MessageDigest.getInstance(args[0]); FileInputStream in = new FileInputStream(args[1]); int len;
Kryptografische Grundlagen 032 byte[] data = new byte[1024]; 033 while ((len = in.read(data)) > 0) { 034 //MessageDigest updaten 035 md.update(data, 0, len); 036 } 037 in.close(); 038 //MessageDigest berechnen und ausgeben 039 byte[] result = md.digest(); 040 for (int i = 0; i < result.length; ++i) { 041 System.out.print(toHexString(result[i]) + " "); 042 } 043 System.out.println(); 044 } catch (Exception e) { 045 System.err.println(e.toString()); 046 System.exit(1); 047 } 048 } 049 }
INFO
Kapitel 48 Listing 48.3: Erstellen eines Message Digest (Forts.)
i
i
i
Im Paket java.security gibt es zwei Klassen, die einen Message Digest mit einem Stream kombinieren. DigestInputStream ist ein Eingabe-Stream, der beim Lesen von Bytes parallel deren Message Digest berechnet; DigestOutputStream fhrt diese Funktion beim Schreiben aus. Beide bertragen die eigentlichen Bytes unverndert und kçnnen dazu verwendet werden, in einer Komposition von Streams »nebenbei« einen Message Digest zu berechnen.
Authentifizierung Ein wichtiges Anwendungsgebiet von Message Digests ist die Authentifizierung, d.h. die berprfung, ob die Person oder Maschine, mit der kommuniziert werden soll, tatschlich »echt« ist (also die ist, die sie vorgibt zu sein). Eine Variante, bei der ein Anwender sich mit einem Benutzernamen und Passwort autorisiert, kann mit Hilfe eines Message Digest in folgender Weise realisiert werden: " Zunchst wird vom System ein Benutzername vergeben. " Beim ersten Anmelden gibt der Anwender den Benutzernamen und ein von ihm vergebenes Passwort ein. " Das System berechnet den Message Digest fr das Passwort und speichert ihn zusammen mit dem Benutzernamen in der Benutzerdatenbank ab.
Teil VIII
" Bei jedem weiteren Anmeldeversuch berechnet das System den Message Digest zum eingegebenen Passwort und vergleicht ihn mit dem in der Benutzerdatenbank zu diesem Benutzernamen gespeicherten. Sind beide identisch, wird der Zugang gewhrt, andernfalls wird er verweigert.
1201
Kapitel 48
Sicherheit und Kryptografie
Bemerkenswert daran ist, dass das System nicht die Passwçrter selbst speichert, auch nicht in verschlsselter Form. Ein Angriff auf die Benutzerdatenbank mit dem Versuch, gespeicherte Passwçrter zu entschlsseln, ist daher nicht mçglich. Eine bekannte (und leider schon oft erfolgreich praktizierte) Methode des Angriffs besteht allerdings darin, Message Digests zu allen Eintrgen in großen Wçrterbchern berechnen zu lassen, und sie mit den Eintrgen der Benutzerdatenbank zu vergleichen. Das ist einer der Grnde dafr, weshalb als Passwçrter niemals Allerweltsnamen oder einfache, in Wçrterbchern verzeichnete, Begriffe verwendet werden sollten.
»Unwissende« Beweise Eine weitere Anwendung von Message Digests besteht darin, die Existenz von Geheimnissen oder den Nachweis der Kenntnis bestimmter Sachverhalte nachzuweisen, ohne deren Inhalt preiszugeben – selbst nicht eigentlich vertrauenswrdigen Personen. Dies wird in Bruce Schneier's Buch als Zero-Knowledge Proof bezeichnet und funktioniert so: " A speichert das Geheimnis in elektronischer Form und berechnet den Message Digest dazu. " A deponiert das Geheimnis an einer Stelle, die fr Dritte unerreichbar ist. " A bergibt den Message Digest zum Zeitpunkt X einem Notar, der Inhalt und Eingangsdatum besttigt und urkundlich festhlt. Alternativ kann A den Message Digest auch in der regionalen Tagespresse verçffentlichen und sich den Zeitungsausschnitt an die Wand hngen. Das Geheimnis ist nicht verçffentlicht, der Nachweis fr seine Existenz zum Zeitpunkt X aber erbracht. Muß A Jahre spter die Existenz dieser Informationen nachweisen, holt es die Diskette mit dem Geheimnis aus dem Tresor, berechnet den Message Digest erneut und zeigt dessen bereinstimmung mit dem seinerzeit in der Zeitung verçffentlichten.
Fingerprints Eine weitere Anwendung von Message Digests besteht im Erstellen von Fingerprints (also digitalen Fingerabdrcken) zu çffentlichen Schlsseln (was das genau ist, wird in Abschnitt 48.1.5, Seite 1205 erklrt). Um die Korrektheit eines çffentlichen Schlssels nachzuweisen, wird daraus ein Message Digest berechnet und als digitaler Fingerabdruck an prominenter Stelle verçffentlicht (beispielsweise in den Signaturen der E-Mails des Schlsselinhabers). Soll vor der Verwendung eines çffentlichen Schlssel berprft werden, ob dieser auch wirklich dem gewnschten Inhaber gehçrt, ist lediglich der (durch das Schlsselverwaltungsprogramm adhoc berechnete) Fingerprint des çffentlichen Schlssels mit dem in der E-Mail verçffentlichten zu vergleichen. Stimmen beide berein, erhçht sich das Vertrauen
1202
Kryptografische Grundlagen
Kapitel 48
in die Authentizitt des çffentlichen Schlssels und er kann verwendet werden. Stimmen sie nicht berein, sollte der Schlssel auf keinen Fall verwendet werden. Wir werden in Abschnitt 48.1.7, Seite 1213 noch einmal auf diese Problematik zurckkommen.
48.1.4 Kryptographische Zufallszahlen Zufallszahlen wurden bereits in Abschnitt 16.1, Seite 385 vorgestellt. In kryptografischen Anwendungen werden allerdings bessere Zufallszahlengeneratoren bençtigt, als in den meisten Programmiersprachen implementiert sind. Einerseits sollte die Verteilung der Zufallszahlen besser sein, andererseits wird eine grçßere Periodizitt gefordert (das ist die Lnge der Zahlensequenz, nach der sich eine Folge von Zufallszahlen frhestens wiederholt). Zudem muss die nchste Zahl der Folge praktisch unvorhersagbar sein – selbst wenn deren Vorgnger bekannt sind. INFO
i
i
i
Es ist bekannt, dass sich mit deterministischen Maschinen (wie Computerprogramme es beispielsweise sind) keine echten Zufallszahlen erzeugen lassen. Eigentlich mssten wir daher von Pseudo-Zufallszahlen sprechen, um darauf hinzuweisen, dass unsere Zufallszahlengeneratoren stets deterministische Zahlenfolgen erzeugen. Mit der zustzlichen Forderung kryptografischer Zufallszahlen, praktisch unvorhersagbare Zahlenfolgen zu generieren, wird diese Unterscheidung an dieser Stelle unbedeutend. Tatschlich besteht der wichtigste Unterschied zu »echten« Zufallsgeneratoren nur noch darin, dass deren Folgen nicht zuverlssig reproduziert werden kçnnen (was bei unseren Pseudo-Zufallszahlen sehr wohl der Fall ist). Wir werden im Folgenden daher den Begriff »Zufallszahl« auch dann verwenden, wenn eigentlich »Pseudo-Zufallszahl« gemeint ist.
Die Klasse SecureRandom des Pakets java.security implementiert einen Generator fr kryptografische Zufallszahlen, der die oben genannten Eigenschaften besitzt. Er wird durch Aufruf der Methode getInstance hnlich instanziert wie ein Message Digest: public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException
java.security. MessageDigest
Als Algorithmus ist beispielsweise »SHA1PRNG« im JDK 1.2 implementiert. Hierbei entstehen die Zufallszahlen aus der Berechnung eines Message Digest fr eine Pseudonachricht, die aus einer Kombination aus Initialwert und fortlaufendem Zhler besteht. Die Klasse SecureRandom stellt weiterhin die Methoden setSeed und nextBytes zur Verfgung: java.security. MessageDigest
Teil VIII
public void setSeed(long seed) public void nextBytes(byte[] bytes) Mit setSeed wird der Zufallszahlengenerator initialisiert. Die Methode sollte nach der Konstruktion einmal aufgerufen werden, um den Initialwert festzulegen (andernfalls
1203
Kapitel 48
Sicherheit und Kryptografie
macht es der Generator selbst). Gleiche Initialwerte fhren auch zu gleichen Folgen von Zufallszahlen. Mit nextBytes wird eine beliebig lange Folge von Zufallszahlen erzeugt und in dem als Argument bergebenen Byte-Array zurckgegeben. Das folgende Listing instanziert einen Zufallszahlengenerator und erzeugt zehn Folgen zu je acht Byte Zufallszahlen, die dann auf dem Bildschirm ausgegeben werden: Listing 48.4: Erzeugen kryptografischer Zufallszahlen
1204
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040
/* Listing4804.java */ import java.security.*; public class Listing4804 { /** * Konvertiert ein Byte in einen Hex-String. */ public static String toHexString(byte b) { int value = (b & 0x7F) + (b < 0 ? 128 : 0); String ret = (value < 16 ? "0" : ""); ret += Integer.toHexString(value).toUpperCase(); return ret; } public static void main(String[] args) { try { //Zufallszahlengenerator erstellen SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); byte[] data = new byte[8]; //Startwert initialisieren rand.setSeed(0x123456789ABCDEF0L); for (int i = 0; i < 10; ++i) { //Zufallszahlen berechnen rand.nextBytes(data); //Ausgeben for (int j = 0; j < 8; ++j) { System.out.print(toHexString(data[j]) + " "); } System.out.println(); } } catch (Exception e) { System.err.println(e.toString()); System.exit(1); } } }
Kryptografische Grundlagen
Kapitel 48
48.1.5 Public-Key-Verschlsselung Eines der Hauptprobleme bei der Anwendung symmetrischer Verschlsselungen ist das der Schlsselbertragung. Eine verschlsselte Nachricht kann nmlich nur dann sicher bertragen werden, wenn der Schlssel auf einem sicheren Weg vom Sender zum Empfnger gelangt. Je nach rumlicher, technischer oder organisatorischer Distanz zwischen beiden Parteien kann das unter Umstnden sehr schwierig sein. Mit der Erfindung der Public-Key-Kryptosysteme wurde dieses Problem Mitte der siebziger Jahre entscheidend entschrft. Bei einem solchen System wird nicht ein einzelner Schlssel verwendet, sondern diese treten immer paarweise auf. Einer der Schlssel ist çffentlich und dient dazu, Nachrichten zu verschlsseln. Der anderen Schlssel ist privat. Er dient dazu, mit dem çffentlichen Schlssel verschlsselte Nachrichten zu entschlsseln. Das Schlsselbertragungsproblem wird nun dadurch gelçst, dass ein potenzieller Empfnger verschlsselter Nachrichten seinen çffentlichen Schlssel an allgemein zugnglicher Stelle publiziert. Seinen privaten Schlssel hlt er dagegen geheim. Will ein Sender eine geheime Nachricht an den Empfnger bermitteln, verwendet er dessen allgemein bekannten çffentlichen Schlssel und bertrgt die verschlsselte Nachricht an den Empfnger. Nur mit Hilfe seines privaten Schlssels kann dieser nun die Nachricht entziffern. Das Verfahren funktioniert natrlich nur, wenn der çffentliche Schlssel nicht dazu taugt, die mit ihm verschlsselte Nachricht zu entschlsseln. Auch darf es nicht mçglich sein, mit vertretbarem Aufwand den privaten Schlssel aus dem çffentlichen herzuleiten. Beide Probleme sind aber gelçst und es gibt sehr leistungsfhige und sichere Verschlsselungsverfahren, die auf dem Prinzip der Public-Key-Kryptografie beruhen. Bekannte Beispiele fr solche Systeme sind RSA (benannt nach ihren Erfindern Rivest, Shamir und Adleman) und DSA (Digital Signature Architecture). Asymmetrische Kryptosysteme haben meist den Nachteil, sehr viel langsamer zu arbeiten als symmetrische. In der Praxis kombiniert man daher beide Verfahren und kommt so zu hybriden Kryptosystemen. Um eine geheime Nachricht von A nach B zu bertragen, wird dabei in folgenden Schritten vorgegangen: " Mit Hilfe eines kryptografischen Zufallszahlengenerators erzeugt A einen Einmalschlssel (der auch als Session Key bezeichnet wird). " A verschlsselt die geheime Nachricht mit Hilfe des Session Keys und eines (schnellen) symmetrischen Verfahrens.
Teil VIII
" A verschlsselt den Session-Key mit dem çffentlichen Schlssel von B auf der Basis des vereinbarten Public-Key-Kryptoverfahrens und sendet ihn zusammen mit der verschlsselten Nachricht an B. " B entschlsselt den Session-Key mit seinem privaten Schlssel. " B entschlsselt die geheime Nachricht mit dem Session Key.
1205
Kapitel 48
Sicherheit und Kryptografie
Fast alle Public-Key-Kryptosysteme arbeiten in dieser Weise als Hybridsysteme. Andernfalls wrde das Ver- und Entschlsseln bei großen Nachrichten viel zu lange dauern. Ein bekanntes Beispiel fr ein solches System ist PGP (Pretty Good Privacy) von Phil Zimmermann. Es wird vorwiegend beim Versand von E-Mails verwendet und gilt als sehr sicher. Freie Implementierungen stehen fr viele Plattformen zur Verfgung.
i
i
i
INFO Das Ver- und Entschlsseln von Daten mit Hilfe von asymmetrischen Verfahren war bis zur Version 1.3 nicht im JDK enthalten. Zwar gab es als Erweiterung zum JDK die JCE (JAVA Cryptography Extension), doch diese durfte nur in den USA und Kanada verwendet werden. Mit dem JDK 1.4 wurden die JCE sowie die Java Secure Socket Extension (JSSE) und der Java Authentication and Authorization Service (JAAS) fester Bestandteil des JDK. Dennoch gibt es nach wie vor einige Einschrnkungen in der Leistungsfhigkeit der einzelnen Pakete, die auf US-Exportbeschrnkungen zurckzufhren sind. Details kçnnen in der Dokumentation zum JDK 1.4 oder neueren Versionen nachgelesen werden.
48.1.6 Digitale Unterschriften Ein großer Vorteil der Public-Key-Kryptosysteme ist es, dass sie Mçglichkeiten zum Erstellen und Verifizieren von digitalen Unterschriften bieten. Eine digitale Unterschrift besitzt folgende wichtige Eigenschaften: " Sie stellt sicher, dass eine Nachricht von einem ganz bestimmten und eindeutig identifizierbaren Absender stammt. " Sie stellt sicher, dass die Nachricht intakt ist und nicht whrend der bertragung verndert wurde. Beide Eigenschaften sind fr den elektronischen Datenverkehr so fundamental wie die Verschlsselung selbst. Technisch basieren sie darauf, dass die Funktionsweise eines Public-Key-Kryptosystems sich umkehren lsst. Dass es also mçglich ist, Nachrichten, die mit einem privaten Schlssel verschlsselt wurden, mit Hilfe des korrespondierenden çffentlichen Schlssels zu entschlsseln. Im Prinzip funktioniert eine digitale Unterschrift so: Will A eine Nachricht signieren, so verschlsselt er sie mit seinem privaten Schlssel. Jeder, der im Besitz des çffentlichen Schlssel von A ist, kann sie entschlsseln. Da nur A seinen eigenen privaten Schlssel kennt, muss die Nachricht von ihm stammen. Da es keinem Dritten mçglich ist, die entschlsselte Nachricht zu modifizieren und sie erneut mit dem privaten Schlssel von A zu verschlsseln, ist auch die Integritt der Nachricht sichergestellt. Den Vorgang des berprfens der Integritt und Authentizitt bezeichnet man als Verifizieren einer digitalen Unterschrift. In der Praxis sind die Dinge wieder einmal etwas komplizierter, denn die Langsamkeit der asymmetrischen Verfahren erfordert eine etwas aufwndigere Vorgehensweise. Statt
1206
Kryptografische Grundlagen
Kapitel 48
die komplette Nachricht zu verschlsseln, berechnet A zunchst einen Message Digest der Nachricht. Diesen verschlsselt A mit seinem privaten Schlssel und versendet ihn als Anhang zusammen mit der Nachricht. Ein Empfnger wird die Nachricht lesen, ihren Message Digest bilden und diesen dann mit dem (mit Hilfe des çffentlichen Schlssels von A entschlsselten) Original-Message-Digest vergleichen. Stimmen beide berein, ist die Signatur gltig. Die Nachricht stammt dann sicher von A und wurde nicht verndert. Stimmen sie nicht berein, wurde sie ver- oder geflscht. Das JDK stellt Klassen zum Erzeugen und Verifizieren digitaler Unterschriften zur Verfgung. Wir wollen uns beide Verfahren in den folgenden Abschnitten ansehen. Zuvor wird allerdings ein Schlsselpaar bençtigt, dessen Generierung im nchsten Abschnitt besprochen wird.
Erzeugen und Verwalten von Schlsseln mit dem JDK Um digitale Unterschriften erzeugen und verifizieren zu kçnnen, mssen Schlsselpaare erzeugt und verwaltet werden. Seit dem JDK 1.2 wird dazu eine Schlsseldatenbank verwendet, auf die mit Hilfe des Hilfsprogramms keytool zugegriffen werden kann. keytool kann Schlsselpaare erzeugen, in der Datenbank speichern und zur Bearbeitung wieder herausgeben. Zudem besitzt es die Fhigkeit, Zertifikate (siehe Abschnitt 48.1.7, Seite 1213) zu importieren und in der Datenbank zu verwalten. Die Datenbank hat standardmßig den Namen ».keystore« und liegt im Home-Verzeichnis des angemeldeten Benutzers (bzw. im Verzeichnis \windows eines Windows-95/98-Einzelplatzsystems). keytool ist ein kommandozeilenbasiertes Hilfsprogramm, das eine große Anzahl an Funktionen bietet. Wir wollen hier nur die fr den Umgang mit digitalen Unterschriften bençtigten betrachten. Eine vollstndige Beschreibung findet sich in der Tool-Dokumentation des JDK. JDK 1.1–6.0 Im JDK 1.1 gab es keytool noch nicht. Stattdessen wurde das Programm javakey zur Schlsselverwaltung verwendet. Hier soll nur das Security-API des JDK 1.2 und darber betrachtet werden. Wir wollen daher auf javakey und andere Eigenschaften der Pr-1.2-JDKs nicht eingehen.
» » »
Um ein neues Schlsselpaar zu erzeugen, ist keytool mit dem Kommando -genkey aufzurufen. Zustzlich mssen weitere Parameter angegeben werden:
Teil VIII
" Mit -alias wird der Aliasname des neu zu generierenden Eintrags angegeben. Er dient als eindeutiger Bezeichner und wird knftig immer dann gebraucht, wenn auf diesen Eintrag zugegriffen werden soll. " Mit -dname wird ein strukturierter Name fr den Schlsselbesitzer angegeben. Er besteht aus mehreren Teilen, die durch Kommata voneinander getrennt sind. Jeder einzelne Teil besteht aus einer mnemonischen Bezeichnung, gefolgt von einem Gleich-
1207
Kapitel 48
Sicherheit und Kryptografie
heitszeichen und dem zugehçrigen Wert. Einzelne Bestandteile kçnnen ausgelassen werden. Der strukturierte Name kann folgende Teile enthalten : " CN: blicher Name (Common Name) " OU: Organisatorische Einheit (Organisational Unit) " O: Unternehmen/Organisation (Organisation) " L: Stadt (Location) " S: Bundesstaat (State) " C: Land (Countrycode) Die Optionen fr den Schlssel- und Signaturtyp (-keyalg und -sigalg) sowie die Schlssellnge (-keysize) und die Gltigkeitsdauer (-validity) sollen unspezifiziert bleiben (und daher gemß den eingebauten Voreinstellungen belegt werden). Zustzlich besitzt jede Schlsseldatenbank ein Zugriffspasswort, das mit der Option -storepass (oder alternativ in der Eingabezeile) angegeben wird. Schließlich besitzt jeder private Schlssel ein Schlsselpasswort, das mit der Option -keypass (oder ber die Eingabezeile) angegeben wird. Wir wollen zunchst ein Schlsselpaar mit dem Aliasnamen »hjp3« erzeugen und mit dem Passwort »hjp3key« vor unberechtigtem Zugriff schtzen. Die Schlsseldatenbank wird beim Anlegen des ersten Schlssels automatisch erzeugt und bekommt das Passwort »hjp3ks« zugewiesen. Wir verwenden dazu folgendes Kommando (bitte haben Sie etwas Geduld, das Programm bençtigt eine ganze Weile): c:\-->keytool -genkey -alias hjp3 -dname "CN=Guido Krueger,O=Computer Books,C=de" Enter keystore password: hjp3ks Enter key password for
1208
Kryptografische Grundlagen
Kapitel 48
Serial number: 38663e2d Valid from: Sun Dec 26 17:11:25 GMT+01:00 1999 until: Sat Mar 25 17:11:25 GMT+01:00 2000 Certificate fingerprints: MD5: D5:73:AB:06:25:16:7F:36:27:DF:CF:9D:C9:DE:AD:35 SHA1: E0:A4:39:65:60:06:48:61:82:5E:8C:47:8A:2B:04:A4:6D:43:56:05 Gleichzeitig wird ein Eigenzertifikat fr den gerade generierten çffentlichen Schlssel erstellt. Es kann dazu verwendet werden, digitale Unterschriften zu verifizieren. Jedes Zertifikat in der Schlsseldatenbank (und damit jeder eingebettete çffentliche Schlssel) gilt im JDK automatisch als vertrauenswrdig.
Erstellen einer digitalen Unterschrift Wie erwhnt, entsteht eine digitale Unterschrift zu einer Nachricht durch das Verschlsseln des Message Digest der Nachricht mit dem privaten Schlssel des Unterzeichnenden. Nachdem wir ein Schlsselpaar erstellt haben, kçnnen wir es nun dazu verwenden, beliebige Dateien zu signieren. Dazu wird die Klasse Signature des Pakets java.security verwendet. Ihre Programmierschnittstelle hnelt der der Klasse MessageDigest: Zunchst wird ein Objekt mit Hilfe einer Factory-Methode beschafft, dann wird es initialisiert und schließlich werden die Daten durch wiederholten Aufruf von update bergeben. Nachdem alle Daten angegeben wurden, berechnet ein letzter Methodenaufruf das Resultat. Ein Signature-Objekt kann wahlweise zum Signieren oder zum Verifizieren verwendet werden. Welche der beiden Funktionen aktiviert wird, ist nach der Instanzierung durch den Aufruf einer Initialisierungsmethode festzulegen. Ein Aufruf von initSign initialisiert das Objekt zum Signieren, ein Aufruf von initVerify zum Verifizieren. public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
java.security. Signature
public final void initSign(PrivateKey privateKey) throws InvalidKeyException public final void initVerify(PublicKey publicKey) throws InvalidKeyException INFO
i
i
i Teil VIII
Als Argument von getInstance wird der gewnschte Signier-Algorithmus bergeben. Auch hier wird – wie an vielen Stellen im Security-API des JDK – eine Strategie verfolgt, nach der die verfgbaren Algorithmen konfigurier- und austauschbar sind. Dazu wurde ein ProviderKonzept entwickelt, mit dessen Hilfe dem API Klassenpakete zur Verfgung gestellt werden kçnnen, die Funktionalitten des Security-Pakets teilweise oder ganz austauschen. Falls der
1209
Kapitel 48
Sicherheit und Kryptografie
Provider beim Aufruf von getInstance nicht angegeben wird, benutzt die Methode den Standard-Provider »SUN«, der zusammen mit dem JDK ausgeliefert wird. Der zu dem von uns generierten Schlssel passende Algorithmus ist »SHA/DSA«.
Die zum Aufruf der init-Methoden bençtigten Schlssel kçnnen aus der Schlsseldatenbank beschafft werden. Auf sie kann mit Hilfe der Klasse KeyStore des Pakets java.security zugegriffen werden. Dazu wird zunchst ein KeyStore-Objekt instanziert und durch Aufruf von load mit den Daten aus der Schlsseldatenbank gefllt. Mit getKey kann auf einen privaten Schlssel zugegriffen werden, mit getCertificate auf einen çffentlichen: java.security. KeyStore
public static KeyStore getInstance(String type) throws KeyStoreException public final Key getKey(String alias, char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException public final Certificate getCertificate(String alias) throws KeyStoreException
!
!
!
ACHTUNG Das von getCertificate zurckgegebene Objekt vom Typ Certificate stammt nicht aus dem Paket java.security, sondern java.security.cert. Das in java.security vorhandene gleichnamige Interface wurde bis zum JDK 1.1 verwendet, ab 1.2 aber als deprecated markiert. Wenn nicht mit qualifizierten Klassennamen gearbeitet wird, muss daher die import-Anweisung fr java.security.cert.Certificate im Quelltext vor der importAnweisung von java.security.Certificate stehen.
Die Klasse Certificate besitzt eine Methode getPublicKey, mit der auf den im Zertifikat enthaltenen çffentlichen Schlssel zugegriffen werden kann: java.security.cert. Certificate
java.security. Signature
1210
public PublicKey getPublicKey() Ist das Signature-Objekt initialisiert, wird es durch Aufruf von update mit Daten versorgt. Nachdem alle Daten bergeben wurden, kann mit sign die Signatur abgefragt werden. Wurde das Objekt zum Verifizieren initialisiert, kann das Ergebnis durch Aufruf von verify abgefragt werden: public final byte[] sign() throws SignatureException
Kryptografische Grundlagen
Kapitel 48
public final boolean verify(byte[] signature) throws SignatureException Nach diesen Vorberlegungen kçnnen wir uns nun das Programm zum Erstellen einer digitalen Unterschrift ansehen. Es erwartet zwei Kommandozeilenargumente: den Namen der zu signierenden Datei und den Namen der Datei, in den die digitale Unterschrift ausgegeben werden soll. /* DigitalSignature.java */ import java.io.*; import java.security.cert.Certificate; import java.security.*; public class DigitalSignature { static final String KEYSTORE static final char[] KSPASS static final String ALIAS static final char[] KEYPASS
= = = =
Listing 48.5: Erstellen einer digitalen Unterschrift
"c:\\windows\\.keystore"; {'h','j','p','3','k','s'}; "hjp3"; {'h','j','p','3','k','e','y'};
public static void main(String[] args) { try { //Laden der Schlsseldatenbank KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream ksin = new FileInputStream(KEYSTORE); ks.load(ksin, KSPASS); ksin.close(); //Privaten Schlssel "hjp3" lesen Key key = ks.getKey(ALIAS, KEYPASS); //Signatur-Objekt erstellen Signature signature = Signature.getInstance("SHA/DSA"); signature.initSign((PrivateKey)key); //Eingabedatei einlesen FileInputStream in = new FileInputStream(args[0]); int len; byte[] data = new byte[1024]; while ((len = in.read(data)) > 0) { //Signatur updaten signature.update(data, 0, len); } in.close(); //Signatur berechnen byte[] result = signature.sign(); //Signatur ausgeben FileOutputStream out = new FileOutputStream(args[1]); out.write(result, 0, result.length); out.close();
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041
1211
Kapitel 48
Sicherheit und Kryptografie
Listing 48.5: Erstellen einer digitalen Unterschrift (Forts.)
042 } catch (Exception e) { 043 System.err.println(e.toString()); 044 System.exit(1); 045 } 046 } 047 }
Will beispielsweise der Benutzer, dessen privater Schlssel unter dem Aliasnamen »hjp3« in der Schlsseldatenbank gespeichert wurde, die Datei DigitalSignature.java signieren und das Ergebnis in der Datei ds1.sign abspeichern, so ist das Programm wie folgt aufzurufen: C:\--->java DigitalSignature DigitalSignature.java ds1.sign
i
i
i
INFO Die Laufzeit des Programms ist betrchtlich. Das Verschlsseln des Message Digest kann auf durchschnittlichen Rechnern durchaus etwa 30 Sekunden dauern. Glcklicherweise ist die Laufzeit nicht nennenswert von der Dateilnge abhngig, denn das Berechnen des Message Digest erfolgt sehr schnell.
Verifizieren einer digitalen Unterschrift Das Programm zum Verifizieren arbeitet hnlich wie das vorige. Statt mit initSign wird das Signature-Objekt nun mit initVerify initialisiert und das Ergebnis wird nicht durch Aufruf von sign, sondern durch Aufruf von verify ermittelt. Listing 48.6: Verifizieren einer digitalen Unterschrift
1212
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021
/* VerifySignature.java */ import java.io.*; import java.security.cert.Certificate; import java.security.*; public class VerifySignature { static final String KEYSTORE = "c:\\windows\\.keystore"; static final char[] KSPASS = {'h','j','p','3','k','s'}; static final String ALIAS = "hjp3"; public static void main(String[] args) { try { //Laden der Schlsseldatenbank KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream ksin = new FileInputStream(KEYSTORE); ks.load(ksin, KSPASS); ksin.close(); //Zertifikat "hjp3" lesen
Kryptografische Grundlagen 022 Certificate cert = ks.getCertificate(ALIAS); 023 //Signature-Objekt erstellen 024 Signature signature = Signature.getInstance("SHA/DSA"); 025 signature.initVerify(cert.getPublicKey()); 026 //Eingabedatei lesen 027 FileInputStream in = new FileInputStream(args[0]); 028 int len; 029 byte[] data = new byte[1024]; 030 while ((len = in.read(data)) > 0) { 031 //Signatur updaten 032 signature.update(data, 0, len); 033 } 034 in.close(); 035 //Signaturdatei einlesen 036 in = new FileInputStream(args[1]); 037 len = in.read(data); 038 in.close(); 039 byte[] sign = new byte[len]; 040 System.arraycopy(data, 0, sign, 0, len); 041 //Signatur ausgeben 042 boolean result = signature.verify(sign); 043 System.out.println("verification result: " + result); 044 } catch (Exception e) { 045 System.err.println(e.toString()); 046 System.exit(1); 047 } 048 } 049 }
Kapitel 48 Listing 48.6: Verifizieren einer digitalen Unterschrift (Forts.)
Soll die Datei DigitalSignature.java mit der im vorigen Beispiel erstellten Signatur verifiziert werden, kann das durch folgendes Kommando geschehen: C:\--->java VerifySignature DigitalSignature.java ds1.sign verification result: true Wird nur ein einziges Byte in DigitalSignature.java verndert, ist die Verifikation negativ und das Programm gibt false aus. Durch eine erfolgreich verifizierte digitale Unterschrift kçnnen wir sicher sein, dass die Datei nicht verndert wurde. Zudem kçnnen wir sicher sein, dass sie mit dem privaten Schlssel von »hjp3« signiert wurde, denn wir haben sie mit dessen çffentlichem Schlssel verifiziert.
48.1.7 Zertifikate Teil VIII
Ein großes Problem bei der Public-Key-Kryptografie besteht darin, die Authentizitt von çffentlichen Schlsseln sicherzustellen. Wrde beispielsweise B einen çffentlichen Schlssel publizieren, der glaubhaft vorgibt, A zu gehçren, kçnnte dies zu verschiedenen Unannehmlichkeiten fhren:
1213
Kapitel 48
Sicherheit und Kryptografie
" Angenommen, C will eine verschlsselte Nachricht an A schicken und verwendet dazu versehentlich den çffentlichen Schlssel von B (den es fr den von A hlt). B kann nun mit seinem eigenen privaten Schlssel die vertrauliche Nachricht lesen. Um weiterhin unentdeckt zu bleiben, kçnnte B die Nachricht anschließend sogar mit dem echten çffentlichen Schlssel von A verschlsseln und an A weitersenden. " Noch folgenreicher ist die Umkehrung. B kçnnte (als A getarnt) Dokumente mit einer digitalen Unterschrift versenden, die fr die von A gehalten wird und so im Namen von A beispielsweise geschftliche oder rechtlich relevante Transaktionen auslçsen. A wre anschließend in der unangenehmen Sitution, nachweisen zu mssen, dass ihm der von B verwendete private Schlssel nie gehçrte und bekannt war. Einen Schutz gegen derartigen Missbrauch bringen Zertifikate. Ein Zertifikat ist eine Art Echtheitsbeweis fr einen çffentlichen Schlssel, das damit hnliche Aufgaben erfllt wie ein Personalausweis oder Reisepass. Ein Zertifikat besteht meist aus folgenden Teilen: " Dem çffentlichen Schlssel des Zertifikatsinhabers " Identittsmerkmalen des Inhabers (beispielsweise Name, Wohnort, Firma, einem Photo etc.) " Der Bezeichnung des Zertifikatsausstellers " Der digitalen Signatur des Ausstellers " Der digitalen Signatur des Inhabers Die Glaubwrdigkeit des Zertifikats hngt von der Glaubwrdigkeit des Ausstellers ab. Wird dieser als vertrauenswrdig angesehen, d.h., kann man seiner digitialen Unterschrift trauen, so wird man auch dem Zertifikat trauen und den darin enthaltenen çffentlichen Schlssel akzeptieren. Dieses Vertrauen kann einerseits darauf basieren, dass der Aussteller eine anerkannte Zertifizierungsautoritt ist (auch Certification Authority, kurz CA, genannt), deren çffentlicher Schlssel bekannt und deren Seriçsitt institutionell manifestiert ist. Mit anderen Worten: dessen eigenes Zertifikat in der eigenen Schlsselverwaltung bekannt und als vertrauenswrdig deklariert ist. Andererseits kann das Vertrauen in das Zertifikat daher stammen, dass der Aussteller persçnlich bekannt ist, sein çffentlicher Schlssel eindeutig nachgewiesen ist und seiner Unterschrift Glauben geschenkt wird. Der erste Ansatz wird beispielsweise bei X.509-Zertifikaten verfolgt. Institute, die derartige Zertifikate ausstellen, werden meist staatlich autorisiert und geprft. Beispiele dafr sind VeriSign, Thawte oder das TA Trustcenter. Der zweite Ansatz liegt beispielsweise den Zertifikaten in PGP zugrunde. Hier ist es sogar mçglich, çffentliche Schlssel mit mehreren digitalen Unterschriften unterschiedlicher Personen zu signieren und so die Glaubwrdigkeit (bzw. ihre Reichweite) zu erhçhen.
1214
Sicherheitsmechanismen in Java
Kapitel 48
Zertifizierungsinstitute stellen meist auch Schlsseldatenbanken zur Verfgung, aus denen Zertifikate abgerufen werden kçnnen. Diese dienen auch als Anlaufstelle, um ungltig gewordene oder unbrauchbare Zertifikate zu registrieren. Lokale Schlsselverwaltungen kçnnen sich mit diesen Informationen synchronisieren, um ihren eigenen Schlsselbestand up-to-date zu halten.
48.2 Sicherheitsmechanismen in Java 48.2.1 Sprachsicherheit Java wurde von Anfang an mit hçheren Sicherheitsansprchen entworfen, als dies blicherweise bei Programmiersprachen der Fall ist. Einer der Hauptgrnde dafr war der Wunsch, den Aufruf von Applets, die aus dem Internet geladen wurden, so sicher wie mçglich zu machen. Selbst bçsartige Applets sollten nicht in der Lage sein, ernsthafte Angriffe auf den Computer, das Betriebssystem oder die Ressourcen des Anwenders auszufhren. Sicherheit beginnt in Java schon bei der Implementierung der Sprache. Anders als in C oder C++ gibt es beispielsweise keine direkten Zugriffe auf den Hauptspeicher und keine Pointerarithmetik. Das Memory-Management arbeitet vollautomatisch. Sicherheitslcken, die durch (provozierte) Speicherberlufe verursacht werden, sind damit nicht ohne Weiteres mçglich. Alle Typkonvertierungen werden zur Laufzeit geprft und unerlaubte Umwandlungen von vorne herein ausgeschlossen. Auch Zugriffe auf Array-Elemente und Strings werden grundstzlich auf Einhaltung der Bereichsgrenzen geprft. Zugriffe, die außerhalb des erlaubten Bereichs liegen, fhren nicht zu undefiniertem Verhalten, sondern werden definiert abgebrochen und lçsen eine Ausnahme aus. Beim Laden von Bytecode ber das Netz wird dieser vor der Ausfhrung von einem Bytecode-Verifier untersucht. Auf diese Weise wird beispielsweise sichergestellt, dass nur gltige Opcodes verwendet werden, dass alle Sprunganweisungen auf den Anfang einer Anweisung zeigen, dass alle Methoden mit korrekten Signaturen versehen sind und dass Ausdrcke korrekt typisiert sind. Zudem implementiert der Klassenlader einen lokalen Namensraum, der verhindert, dass bestehende Klassen verndert oder ersetzt werden kçnnen.
48.2.2 Das Sandbox-Konzept Teil VIII
Traditionell wurde in Java zwischen lokalem Code und solchem, der aus dem Netz geladen wird, bezglich seiner Sicherheitsanforderungen rigoros unterschieden. Whrend lokalem Code (also Applikationen und von der Festplatte geladenen Applets) der Zugriff auf alle verfgbaren Ressourcen gestattet ist, drfen Applets, die aus dem Netz geladen wurden, nur einen kleinen Teil davon verwenden. Sie halten sich gewissermaßen in einem
1215
Kapitel 48
Sicherheit und Kryptografie
Sandkasten auf, in dem sie nur ungefhrliche Spielzeuge verwenden und keinen ernsthaften Schaden anrichten kçnnen (daher der Name »Sandbox«). Zu den »gefhrlichen Spielzeugen«, die nicht verwendet werden drfen, zhlen: " der lesende und schreibende Zugriff auf Dateien des lokalen Computers, " das ffnen von TCP/IP-Verbindungen zu einem anderen als dem Host, von dem das Applet geladen wurde, " das Akzeptieren von TCP/IP-Verbindungen auf privilegierten Port-Nummern, " das Lesen benutzerbezogener System-Properties wie »user.name«, »user.home«, »user.dir« oder »java.home«, " das Erzeugen eines Top-Level-Fensters ohne Warnhinweis, " das Ausfhren externer Programme, " das Laden von System-Libraries, " das Beenden der virtuellen Maschine.
i
i
i
INFO Bençtigte ein Applet Zugriff auf diese Ressourcen, gab es im JDK 1.0 die Mçglichkeit, die zugehçrigen Dateien auf der lokalen Festplatte abzulegen. Denn wenn das Applet zur Ausfhrung nicht aus dem Netz, sondern aus den lokalen Dateien gestartet wurde, galt es automatisch als vertrauenswrdig und hatte Zugriff auf alle ansonsten verbotenen Ressourcen.
48.2.3 Vernderungen im JDK 1.1 und 1.2 Mit dem JDK 1.1 wurde eine neue Mçglichkeit eingefhrt, Applets Zugriff auf geschtzte Ressourcen zu ermçglichen. Dazu mssen alle zum Applet gehçrenden Dateien in eine jar-Datei verpackt und mit einer digitalen Unterschrift versehen werden. Wird der Unterzeichner auf dem ausfhrenden Computer als vertrauenswrdig angesehen (indem sein çffentlicher Schlssel an geeigneter Stelle bekanntgemacht wurde), kann das Applet die Sandbox verlassen und hat Zugriff auf alle geschtzten Ressourcen. Mit dem JDK 1.2 wurde dieses Konzept weiter verfeinert. Whrend es im JDK 1.1 schwierig war, die Zugriffsbeschrnkungen schrittweise zu lockern, ist das nun viel einfacher. Die Zugriffsbeschrnkungen sind konfigurierbar und kçnnen mit Hilfe einer Policy-Datei auch ohne Programmnderungen angepasst werden. Sie kçnnen wahlweise davon abhngig gemacht werden, von wem die Signatur stammt, als auch davon, woher das Applet geladen wurde. Zudem wurde die prinzipielle Unterscheidung zwischen lokalem und netzwerkbasiertem Code aufgegeben. Obwohl die Sicherheitseinstellungen so konfiguriert werden kçnnten, dass lokalem Code voller Zugriff auf alle Ressourcen gewhrt wird, ist das standardmßig nicht mehr der Fall.
1216
Signierte Applets
Kapitel 48
48.3 Signierte Applets In diesem Abschnitt wird beschrieben, wie einem Applet der Zugriff auf geschtzte Ressourcen gewhrt werden kann. Wir gehen dazu in folgenden Schritten vor: 1. Zunchst wird ein Applet entwickelt, das auf einige beschrnkte Ressourcen zugreift. Ohne weitere Vorkehrungen ist es nicht lauffhig, sondern wird mit einer SecurityException abgebrochen. 2. Anschließend zeigen wir, wie das Applet mit Hilfe des in Abschnitt 48.1.6, Seite 1206 erzeugten Schlsselpaars signiert wird. 3. Danach demonstrieren wir die Weitergabe von Zertifikaten. 4. Schließlich zeigen wir, wie die Sicherheitseinstellungen so angepasst werden, dass das Applet Zugriff auf die gewnschten Ressourcen erhlt.
48.3.1 Ein »unerlaubtes« Applet Wir wollen uns die Aufgabe stellen, ein Applet zu schreiben, das einige Sicherheitsverstçße begeht. Zunchst soll es eine Datei auf dem lokalen Computer erzeugen und einen Zeitstempel hineinschreiben. Zustzlich soll es auf einige geschtzte System-Properties zugreifen und deren Inhalt in die Datei schreiben. Das Applet hat folgenden Aufbau: /* TrustedApplet.java */ import import import import
java.awt.*; java.applet.*; java.util.*; java.io.*;
Listing 48.7: Ein »unerlaubtes« Applet
public class TrustedApplet extends Applet { static final String ALLOWED_DIR = "c:\\tmp\\applets\\"; static final String FNAME = "TrustedApplet.log"; static final String LOGMSG = "Erzeugt von Applet: "; String msg; public void init() { msg = "Uninitialisiert"; FileWriter out = null; try { //Ausgabedatei erzeugen out = new FileWriter(ALLOWED_DIR + FNAME); //Logmessage schreiben out.write(LOGMSG); //Zeitstempel schreiben
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025
1217
Kapitel 48 Listing 48.7: Ein »unerlaubtes« Applet (Forts.)
Sicherheit und Kryptografie 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 }
GregorianCalendar cal = new GregorianCalendar(); out.write(cal.get(Calendar.DATE) + "."); out.write((cal.get(Calendar.MONTH) + 1) + "."); out.write(cal.get(Calendar.YEAR) + " "); out.write(cal.get(Calendar.HOUR_OF_DAY) + ":"); out.write(cal.get(Calendar.MINUTE) + ":"); out.write(cal.get(Calendar.SECOND) + ""); out.write(System.getProperty("line.separator")); //System-Properties lesen und in Datei schreiben out.write(getProp("user.name")); out.write(getProp("user.home")); out.write(getProp("user.dir")); //Datei schließen msg = "Alle Sicherheitshuerden ueberwunden!"; } catch (Exception e) { msg = e.toString(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { //silently ignore } } } } public void paint(Graphics g) { g.drawString(msg, 20, 20); } private String getProp(String prop) { return prop + "=" + System.getProperty(prop) + System.getProperty("line.separator"); }
Es versucht zunchst, eine Datei c:\tmp\applets\TrustedApplet.log zu erzeugen. Wenn dies gelingt, instanziert es ein aktuelles GregorianCalendar-Objekt und schreibt dessen Werte in die Datei. Schließlich versucht es, die System-Properties »user.name«, »user.home« und »user.dir« zu lesen und deren Werte ebenfalls in die Datei zu schreiben. Sind all diese Versuche erfolgreich, gibt das Applet die Meldung »Alle Sicherheitshuerden ueberwunden!« aus. Tritt eine Ausnahme auf, wird deren Text ausgegeben.
1218
Signierte Applets
INFO
Kapitel 48
i
i
i
Um das Schreiben der Datei zu ermçglichen, ist ein Verzeichnis c:\tmp\applets anzulegen. Andernfalls gibt es eine IOException – selbst wenn alle Sicherheitshrden genommen sind.
Das Applet kann mit folgender HTML-Datei gestartet werden: 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018
Listing 48.8: Vorlufige HTMLDatei zum Aufruf des unerlaubten Applets
TrustedApplet Demo
Das Applet kann nun beispielsweise mit dem appletviewer gestartet werden: appletviewer TrustedApplet.html Wird es ohne weitere Vorkehrungen gestartet, scheitert es bereits am Erzeugen der Ausgabedatei und gibt eine SecurityException auf dem Bildschirm aus.
48.3.2 Signieren des Applets Zum Signieren ist es zunchst erforderlich, alle fr den Betrieb des Applets nçtigen Dateien in ein jar-File zu packen. Signiert wird also nicht eine einzelne .class-Datei, sondern alle Dateien innerhalb des jar-Archivs. Dazu verwenden wir folgendes Kommando: jar cvf trapp.jar TrustedApplet.class
Teil VIII
Jetzt wird ein jar-Archiv trapp.jar erstellt, das die Klassendatei TrustedApplet.class enthlt. Dieses Archiv muss nun signiert werden. Dazu steht im JDK das Hilfsprogramm jarsigner zur Verfgung. Es arbeitet kommandozeilenbasiert und wird folgendermaßen aufgerufen: jarsigner -signedjar outjar injar alias
1219
Kapitel 48
Sicherheit und Kryptografie
Die einzelnen Elemente haben folgende Bedeutung: " injar ist der Name des zu signierenden jar-Archivs. " outjar ist der Name der Ausgabedatei, also des signierten Archivs. " alias ist der Aliasname des Eintrags in der Schlsseldatenbank, dessen privater Schlssel zum Signieren verwendet werden soll. Nachdem wir in Abschnitt 48.1.6, Seite 1206 bereits ein Schlsselpaar mit dem Alias »hjp3« erzeugt und in der Schlsseldatenbank abgelegt haben, muss der Aufruf von jarsigner so erfolgen: C:\--->jarsigner -signedjar strapp.jar trapp.jar hjp3 Enter Passphrase for keystore: hjp3ks Enter key password for hjp3: hjp3key Die beiden Passwçrter zum Zugriff auf die Schlsseldatenbank und den Schlssel werden auf Nachfrage in der Kommandozeile angegeben. Nachdem das Programm einige Zeit gerechnet hat, erzeugt es das signierte Archiv mit dem Namen strapp.jar.
i
i
i
INFO jarsigner bietet neben den hier erwhnten noch weitere Optionen, auf die wir nicht weiter eingehen wollen. Das Programm wird zusammen mit den anderen Hilfsprogrammen in der Tool-Dokumentation des JDK ausfhrlich beschrieben.
Bisher wurde das Applet direkt aus der .class-Datei geladen. Um es aus einem jar-Archiv zu laden, muss das APPLET-Tag der HTML-Datei um das archive-Argument erweitert werden: Listing 48.9: Aufruf des signierten Applets
1220
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021
<-- TrustedApplet.html --> TrustedApplet Demo
Signierte Applets
INFO
Kapitel 48
i
i
i
Wir kçnnten das Applet jetzt wie zuvor starten, wrden aber immer noch dieselbe SecurityException erhalten. Es ist zwar signiert und das Zertifikat ist auf diesem Rechner bekannt (denn hier wurde es erstellt). Die Policy-Datei ist aber noch nicht angepasst und daher lehnt der SecurityManager des JDK die Ausfhrung der gefhrlichen Operationen nach wie vor ab.
48.3.3 Ex- und Import von Zertifikaten Soll das signierte Applet auf anderen Arbeitspltzen laufen, ist es erforderlich, das Zertifikat des Schlssels, mit dem es signiert wurde, dort zu installieren. Soll es dagegen nur auf dem Arbeitsplatz laufen, auf dem auch der Schlssel generiert wurde, ist das nicht erforderlich. Bei der Generierung des Schlssels wurde ja auch ein (selbst signiertes) Zertifikat erzeugt. Um das Zertifikat weitergeben zu kçnnen, muss es zunchst unter Verwendung der Option -export von keytool aus der lokalen Schlsseldatenbank exportiert werden: keytool -export -alias hjp3 -file hjp3.cert Es liegt nun in der Datei hjp3.cert und kann auf das Zielsystem kopiert werden. Mit der -import-Option von keytool kann es dort in die Schlsseldatenbank aufgenommen werden: C:\--->keytool -import -alias hjp3 -file hjp3.cert Enter keystore password: hjp3ks Owner: CN=Guido Krueger, O=Computer Books, C=de Issuer: CN=Guido Krueger, O=Computer Books, C=de Serial number: 38663e2d Valid from: Sun Dec 26 17:11:25 GMT+01:00 1999 until: Sat Mar 25 17:11:25 GMT+01 :00 2000 Certificate fingerprints: MD5: D5:73:AB:06:25:16:7F:36:27:DF:CF:9D:C9:DE:AD:35 SHA1: E0:A4:39:65:60:06:48:61:82:5E:8C:47:8A:2B:04:A4:6D:43:56:05 Trust this certificate? [no]: y Certificate was added to keystore
Teil VIII
Nach dem Aufruf muss zunchst das Passwort der Schlsseldatenbank angegeben werden. Dann zeigt das Programm die Eigenschaften des Zertifikats an und erwartet, dass die Informationen besttigt werden. Anschließend wird das Zertifikat in die Schlsseldatenbank aufgenommen.
1221
Kapitel 48
Sicherheit und Kryptografie
48.3.4 Anpassen der Policy-Datei Policy-Dateien Der letzte Schritt besteht darin, die Sicherheitseinstellungen auf dem Zielsystem anzupassen. Applets, die mit dem Zertifikat verifiziert werden kçnnen, das unter dem Alias »hjp3« in der Schlsseldatenbank abgelegt wurde, sollen Dateien im Verzeichnis c:\tmp\applets lesen und schreiben und auf die System-Properties »user.name«, »user.home« und »user.dir« zugreifen kçnnen. Die Sicherheitseinstellungen des JDK werden mit Hilfe von Policy-Dateien definiert. Es gibt zwei Stellen im Dateisystem, von denen das JDK sie standardmßig einliest: " Die System-Policies befinden sich in der Datei java.policy im Unterverzeichnis jre\lib\security des JDK-Installationsverzeichnisses. Diese Datei braucht normalerweise nicht verndert zu werden, sie enthlt die globalen Sicherheitseinstellungen. " Die benutzerbezogenen Sicherheitseinstellungen kçnnen in der Datei .java.policy abgelegt werden. Sie liegt im Home-Verzeichnis des aktuellen Benutzers. Auf Windows-95/98-Einzelplatzsystemen liegt sie (wie die Schlsseldatenbank) im Verzeichnis c:\windows. Diese Datei ist standardmßig nicht vorhanden, kann aber leicht selbst angelegt werden.
*
*
*
TIPP Policy-Dateien kçnnen auch an beliebigen anderen Stellen im Dateisystem liegen. In diesem Fall muss beim Aufruf des Java-Interpreters das System-Property »java.security.policy« mit dem Namen der zu verwendenen Policy-Datei angegeben werden. Wre beispielsweise hjp3policy die zu verwendende Policy-Datei, so msste der Appletviewer mit der Option »-J-Djava.security.policy=hjp3policy« aufgerufen werden.
Das Format einer Policy-Datei Policy-Dateien sind zeilenorientierte Textdateien, die mit einem gewçhnlichen Texteditor bearbeitet werden kçnnen. Alternativ stellt das JDK ein einfaches GUI-basiertes Hilfsprogramm mit dem Namen policytool zur Verfgung, mit dem Policy-Dateien erstellt und bearbeitet werden kçnnen. Auf seine Verwendung wollen wir aber nicht weiter eingehen. Eine Policy-Datei enthlt zwei Arten von Eintrgen. Beide sind optional: " Einen »keystore«-Eintrag, der die Lage der Schlsseldatenbank angibt " Beliebig viele »grant«-Eintrge, mit denen Berechtigungen definiert werden. Alle Eintrge werden mit einem Semikolon beendet. Kommentare kçnnen an beliebiger Stelle durch // oder /* ... */ angelegt werden.
1222
Signierte Applets
Kapitel 48
Der »keystore«-Eintrag erwartet als Argument einen URL, der auf die Schlsseldatenbank verweist. Auf einem Windows-98-Einzelplatzsystem sieht er beispielsweise so aus: keystore "file:/c:/windows/.keystore"; Die »grant«-Eintrge haben folgende Syntax: grant [SignedBy "signer"] [, CodeBase "URL"] { permission permission_class [ "target" ] [, "action"] [, SignedBy "signers"]; ... }; Eine Berechtigung kann wahlweise an einen Unterzeichner oder eine Ladeadresse (oder beide) vergeben werden. Die Option »SignedBy« fhrt eine Liste von Aliasnamen auf, deren Zertifikate vorhanden sein mssen, damit die Berechtigung gewhrt wird. Die Option »CodeBase« spezifiziert die Adresse, von der ein Applet geladen werden darf, um die Berechtigung zu halten. Fehlt die CodeBase-Klausel, wird nur die Unterzeichnerliste verwendet; fehlt die SignedBy-Klausel, ist es nur die Ladeadresse. Nach einer çffnenden geschweiften Klammer folgen beliebig viele Berechtigungen, die jeweils durch das Schlsselwort »permission« eingeleitet werden. Anschließend wird der Eintrag mit einer schließenden geschweiften Klammer abgeschlossen. Der zuvor spezifizierte Berechtigte erhlt alle Berechtigungen, die zwischen den beiden Klammern angegeben sind.
Teil VIII
Jede Berechtigung muss als erstes Argument den Namen einer Berechtigungsklasse angeben. Daneben kann sie zwei weitere Argumente target und action haben, mit denen Details spezifiziert werden. Tabelle 48.1, Seite 1224 listet die gebruchlichsten Berechtigungen und ihre Argumente auf. Details kçnnen (und mssen) in dem Dokument »Java Security Architecture« nachgelesen werden, das Bestandteil der JDK-Dokumentation ist.
1223
Kapitel 48
Tabelle 48.1: Wichtige Permission-Klassen
Sicherheit und Kryptografie
Klasse
Zugriff auf
Target
Action
java.io.
Dateien und
Datei- oder Verzeichnis- read, write, delete, exe-
FilePermission
Verzeichnisse
namen. Wird als letztes cute Zeichen ein »*« angegeben, so gilt die Berechtigung fr das komplette Verzeichnis. Steht dort ein »-«, so gilt sie zustzlich fr alle Unterverzeichnisse. Wird »<
java.net.
TCP/IP-Verbindungen
Hostname oder IP-Adres- accept, connect, listen, se, gefolgt vom Port-
SocketPermission
resolve
Nummern-Bereich java.util.
System-Properties
Name des Proper
read, write
Die Klasse Runtime
exitVM, stopThread, lo- -
PropertyPermission java.lang.
adLibrary, queuePrintJob,
RuntimePermission
... java.awt.
Window-Ressourcen
accessClipboard, show-
-
WindowWithoutWar-
AWTPermission
ningBanner, ... java.security.
Alle Ressourcen
-
-
AllPermission
Erstellen der Policy-Datei Nach diesen Vorbemerkungen kçnnen wir die Policy-Datei \windows\.java.policy erstellen. Sie hat folgenden Inhalt: keystore "file:/c:/windows/.keystore"; grant SignedBy "hjp3" { permission java.io.FilePermission "c:\\tmp\\applets\\*", "read,write";
1224
Signierte Applets
Kapitel 48
permission java.util.PropertyPermission "user.name", "read"; permission java.util.PropertyPermission "user.home", "read"; permission java.util.PropertyPermission "user.dir", "read"; }; Im ersten Eintrag geben wir die Position der Schlsseldatenbank an, sie liegt im Verzeichnis c:\windows. Anschließend definieren wir die Berechtigungen fr alle Applets, die mit dem Zertifikat »hjp3« signiert wurden. Zunchst erhalten sie Schreib- und Leseberechtigung im Verzeichnis c:\tmp\applets. Dort kçnnen sie ohne weitere Einschrnkungen Dateien anlegen, berschreiben und lesen. Zustzlich erlauben wir den so signierten Applets, die drei System-Properties »user.name«, »user.home« und »user.dir« zu lesen. Nun lsst sich unser signiertes Applet ohne SecurityException aufrufen und gibt die erlçsende Meldung »Alle Sicherheitshuerden ueberwunden« aus. Im Verzeichnis c:\tmp\applets sollte sich anschließend eine Datei TrustedApplet.log befinden und etwa folgenden Inhalt haben: Erzeugt von Applet: 30.12.1999 20:50:40 user.name=Guido Krger user.home=C:\WINDOWS user.dir=C:\arc\doku\hjp3\misc
48.3.5 Die Klasse SecurityManager Die Prfung der Zugriffsberechtigungen wird mit Hilfe der Klasse SecurityManager aus dem Paket java.lang vorgenommen. Der SecurityManager ist ein Objekt, das entweder gar nicht oder genau einmal im laufenden Java-Programm vorhanden ist. Nach der ersten Instanzierung kann es nicht mehr gendert oder entfernt werden. Zugriffe auf den SecurityManager sind an den Stellen der Laufzeitbibliothek eingebaut, an denen auf gefhrliche Ressourcen zugegriffen wird. Ein Beispiel aus der Klasse FileInputStream sieht etwa so aus: ... SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); } //Gefhrlicher Code ...
Teil VIII
Zunchst wird geprft, ob ein SecurityManager installiert wurde. Ist das nicht der Fall, fhrt das Programm ohne Einschrnkung fort. Gibt es dagegen einen SecurityManager, wird dessen checkRead-Methode aufgerufen. Sie lçst eine SecurityException aus, wenn die gewnschte Berechtigung fehlt. Der Code hinter dem checkRead wird in diesem Fall
1225
Kapitel 48
Sicherheit und Kryptografie
nicht mehr erreicht. Ist die Berechtigung dagegen vorhanden, wird checkRead ohne weitere Aktionen beendet und der dahinterliegende Code ausgefhrt. Applets besitzen grundstzlich einen SecurityManager. Der AppletViewer bzw. WebBrowser sorgen whrend der Initialisierung fr dessen Instanzierung. Applikationen dagegen haben normalerweise keinen SecurityManager (das ist der Grund, weshalb in Applikationen alle gefhrlichen Operationen erlaubt sind). Soll eine Applikation einen SecurityManager erhalten, so kann sie entweder mit der Option »-Djava.security.manager« gestartet werden oder der SecurityManager kann im Programm selbst installiert werden: ... System.setSecurityManager(new SecurityManager()); ... Das folgende Beispielprogramm gibt den Inhalt des System-Proper »user.name« aus. Normalerweise kann es ohne Fehler ausgefhrt werden: Listing 48.10: Ausgeben des System-Property »user.name«
001 002 003 004 005 006 007 008 009 010 011
/* SecuMgrTest.java */ public class SecuMgrTest { public static void main(String[] args) { System.out.println( "user.name is " + System.getProperty("user.name") ); } }
Luft es dagegen unter Kontrolle eines SecurityManagers, so fhrt der Aufruf zu einer SecurityException: C:\--->java -Djava.security.manager SecuMgrTest Exception in thread "main" java.security.AccessControlException: access denied (java.util.PropertyPermission user.name read) at java.security.AccessControlContext.checkPermission( AccessControlContext.java:276) at java.security.AccessController.checkPermission( AccessController.java:403) at java.lang.SecurityManager.checkPermission( SecurityManager.java:549) at java.lang.SecurityManager.checkPropertyAccess( SecurityManager.java:1242) at java.lang.System.getProperty(System.java:555) at Test1.main(SecuMgrTest.java:7)
1226
Zusammenfassung
Kapitel 48
Bei Bedarf kann man Applikationen auf diese Weise mit denselben Sicherheitsmechanismen ausstatten wie Applets. jar-Dateien, aus denen Applikationen geladen werden, lassen sich ebenso signieren wie solche, aus denen Applets geladen werden. Die in der Policy-Datei definierten Rechte gelten dann fr die daraus gestartete Applikation.
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Einfache Verschlsselungen wie Ziffernsubstitution oder Exklusiv-ODER " Message Digests und die Klasse MessageDigest " Kryptografische Zufallszahlen und die Klasse SecureRandom " Public-Key-Kryptosysteme und Hybrid-Kryptosysteme " Erzeugen und Verifizieren von digitalen Unterschriften mit der Klasse Signature " Verwalten von Schlsseln, der Umgang mit dem Programm keytool und der Zugriff auf die Schlsseldatenbank mit der Klasse KeyStore " Die Bedeutung von Zertifikaten in der Public-Key-Kryptografie " Die eingebauten Sicherheitsmechanismen der verschiedenen Java-Versionen und das Sandbox-Konzept " Das Signieren eines Applets mit jarsigner, der Ex- und Import von Zertifikaten und das Erstellen einer Policy-Datei
Teil VIII
" Die Klasse SecurityManager
1227
49
Sound
49.1
Grundlagen und Konzepte
Seit der Version 1.3 besitzt das JDK Sound-Fhigkeiten, die weit ber die in Abschnitt 39.3, Seite 933 erluterten Mçglichkeiten hinausgehen. Mit Hilfe des Sound-API kçnnen Samples abgespielt oder aufgenommen werden. Es kçnnen Midi-Dateien erzeugt oder wiedergegeben werden und es ist mçglich, direkt auf angeschlossene oder eingebaute Tonerzeuger zuzugreifen. Das API abstrahiert alle fr das Erzeugen und Bearbeiten von Sounds wesentlichen Konzepte und untersttzt die Erkennung und Verwendung unterschiedlichster Hardware-Komponenten. Das Sound-API ist allerdings nicht ganz leicht zu bedienen und wird in der Literatur sehr stiefmtterlich behandelt. Die Schwierigkeiten haben mehrere Ursachen: " Einerseits handelt es sich um ein Low-Level-API, also eines, bei dem schon zur Erzielung relativ einfacher Effekte recht viel Programmieraufwand nçtig ist.
" Zu guter Letzt erfordert der Umgang mit dem Sound-API ein grundlegendes Verstndnis fr viele der auf diesem Gebiet relevanten Konzepte. Das API
Teil VIII
" Andererseits kann das API wenig Annahmen ber standardmßig verfgbare Hardware machen. Soll beispielsweise eine Flçtenmelodie erklingen, muss das Programm erst einmal herausfinden, ob ein Synthesizer eingebaut oder ber einen der Midi-Ports erreichbar ist. Zudem muss er das entsprechende Instrument zur Verfgung stellen kçnnen. Erst dann kann dieser konfiguriert und mit den entsprechenden Tonerzeugungskommandos beschickt werden.
Kapitel 49
Sound
ist sehr eng an Begriffe angelehnt, die direkte Pendants in der elektronischen oder elektronikuntersttzten Musik haben. Ohne ein Basiswissen in Themenbereichen wie Samples, Midi, Tracks, Timecodes, Sequencer, Synthesizer Soundbanks oder Mixer sind die korrespondierenden Klassen und Interfaces schwerlich korrekt zu verwenden. Wir wollen deshalb in diesem Kapitel einen sehr pragmatischen Ansatz whlen. Erforderliche Begriffe werden, wo nçtig, lediglich kurz erklrt, denn wir gehen davon aus, dass beim Leser bereits ein Grundstock an einschlgigen Grundkenntnissen vorhanden ist. Oder wenigstens die Bereitschaft, sich diese whrend des Lesens und Experimentierens anzueignen. Auch werden wir die APIs nur ansatzweise erlutern, denn mehr ist aus Platzgrnden nicht mçglich. Die Beispielprogramme wurden so gewhlt, dass sie einen unmittelbaren Praxisnutzen haben. Sie stellen leicht einzusetzende Routinen zum Abspielen von Samples sowie zum Erzeugen einfacher Midi-Sequenzen und zum Abspielen von Midi-Files zur Verfgung. Damit werden die wichtigsten Standardflle beim Einsatz von Sound abgedeckt. Das Sound-API dient als Basis fr alle Arten von Sound-Support in Java. Seine Anwendungsgebiete reichen von interaktiven Applikationen oder Spielen mit Sound-Untersttzung ber Media-Player und Musik-Tools bis hin zu Telefonie- und Konferenzapplikationen. Des Weiteren ist das Sound-API Basis hçherer Programmierschnittstellen, wie etwa des Java Media Framework, das eine Schnittstelle zum Abspielen und Erzeugen einer ganzen Reihe von Audio- und Videoformaten zur Verfgung stellt.
!
!
!
ACHTUNG Die Beispiele in diesem Buch funktionieren natrlich nur dann, wenn auf dem Computer, an dem sie nachvollzogen werden sollen, eine geeignete (und vom Java-Sound-API untersttzte) Sound-Hardware vorhanden ist. Dabei handelt es sich typischerweise um eine SoundKarte, es kann aber (wenigstens beim Midi-API) auch eine Midi-Schnittstelle mit angeschlossenem Synthesizer verwendet werden. Ist eine solche Hardware nicht verfgbar, erklingt beim Ausfhren der Beispielprogramme entweder gar nichts (oder das Falsche) oder es wird eine Ausnahme ausgelçst.
49.2 Gesampelter Sound 49.2.1 Was ist Sampling? Das Sound-API macht eine sehr grundlegende Unterscheidung zwischen gesampeltem Sound und Midi-Sound. Beim Sampling, das wir in diesem Abschnitt behandeln wollen, wird ein Audio-Signal in viele kleine Stcke zerlegt, deren Amplitude in sehr kurzen Abstnden mit Hilfe eines Analog-Digital-Konverters gemessen wird:
1230
Gesampelter Sound
Kapitel 49 Abbildung 49.1: Samplen eines Audio-Signals
Die Frequenz, mit der die Abtastung geschieht, bezeichnet man als Sampling Rate und sie sollte mindestens doppelt so hoch sein wie die grçßte aufzuzeichnende Frequenz. Bei Audio-CDs betrgt sie 44100 Hz und die Auflçsung des A/D-Konverters betrgt 16 Bit. Speichert man die so entstehenden Amplitudenwerte fortlaufend ab, so kann man bei Kenntnis der Sampling-Rate daraus spter das Originalsignal nherungsweise rekonstruieren. Sind Sampling-Rate und Auflçsung hoch genug, kann das menschliche Ohr keinen Unterschied zwischen gesampeltem und Originalsignal feststellen: Abbildung 49.2: Ein gesampeltes Audio-Signal
49.2.2 Das Sampling-API Das Sound-API macht keine Annahmen ber vorhandene Hardware oder angeschlossene Gerte. Stattdessen stellt es Methoden zur Verfgung, mit denen die vorhandene Hardware zur Laufzeit ermittelt und Objekte zum Zugriff darauf beschafft werden kçnnen. Im Falle von gesampeltem Sound dient dazu die Klasse AudioSystem aus dem Paket javax.sound.sampled. Sie besitzt eine Reihe von statischen Methoden, mit denen die grundlegenden Hilfsmittel fr den Umgang mit gesampeltem Sound beschafft werden kçnnen: " Die Klasse AudioFormat beschreibt das Format von gesampeltem Sound. Sie enthlt unter anderem Informationen ber das Kodierungsverfahren, die Anzahl der Kanle, die Sampling Rate oder die Auflçsung der einzelnen Samples.
Teil VIII
" Die Klasse AudioFileFormat beschreibt das Format von Dateien, die gesampelten Sound enthalten. Im Wesentlichen wird dazu ein eingebettetes AudioFormat-Objekt verwendet, das mit einigen Zusatzinformationen versehen ist. Die wichtigsten Dateiformate, die seit dem JDK 1.3 standardmßig untersttzt werden, sind wav, aiff und au. " Eine weitere wichtige Abstraktion ist die der Line. Sie reprsentiert die verschiedenen, miteinander verbundenen Elemente der Audio-Pipeline, mit denen die Sound-Daten
1231
Kapitel 49
Sound
erzeugt, transportiert oder modifiziert werden. Die abstrakten Eigenschaften einer Line sind, dass sie entweder geçffnet oder geschlossen ist und dass sie eine Reihe von Control-Objekten haben kann, um etwa die Lautstrke, das Stereo-Panorama oder den Hall zu verndern. Zudem sendet eine Line bei wichtigen Statusnderungen Events an registrierte Listener. " Wichtige Subinterfaces von Line sind Port und Mixer. Ein Port ist ein Endpunkt der Audio-Pipeline, also etwa ein Mikrofon oder CD-Laufwerk auf der Eingabeseite oder ein Kopfhçrer- oder Verstrkerausgang auf der Ausgabeseite. Ein Mixer ist ein AudioElement mit mehreren Ein-/Ausgabeleitungen. Er dient typischerweise dazu, verschiedene Eingangssignale getrennt aufzubereiten und zu einem Summensignal zusammenzumischen. Ein Mixer kann auch Vernderungen an den Eingangssignalen vornehmen, etwa einen Halleffekt hinzufgen oder mit Hilfe eines Equalizers den Klang verndern. " Mit DataLine kommt das dritte Subinterface von Line ins Spiel. Eine DataLine ist das Vaterinterface fr alle Lines, die explizit mit Datenstrçmen umgehen. Eine SourceDataLine versorgt einen Mixer mit Eingabedaten und eine TargetDataLine empfngt Daten von ihm. Ein Clip ist eine spezielle Datenquelle, die vor der Weitergabe alle Daten in einem Stck liest und fortan im Hauptspeicher hlt. Ein Clip kann dadurch wahlfrei auf die Daten zugreifen und beispielsweise nur einen Teil des Signals wiedergeben oder Ausschnitte beliebig oft wiederholen. Allerdings kommt er nur fr relativ kleine Datenmengen in Betracht.
Zugriff auf Audio-Dateien Die Klasse AudioSystem stellt einige Methoden zum Zugriff auf Dateien mit gesampeltem Sound zur Verfgung: javax.sound. sampled. AudioSystem
public static AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException public static AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException public static AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException
public static AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException public static AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException public static AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
1232
Gesampelter Sound
Kapitel 49
public static boolean isConversionSupported( AudioFormat targetFormat, AudioFormat sourceFormat ) public static AudioInputStream getAudioInputStream( AudioFormat targetFormat, AudioInputStream sourceStream ) Mit getAudioFileFormat kann das AudioFileFormat einer Sound-Datei ermittelt werden. Die Eingabedatei kann entweder als File, InputStream oder URL bergeben werden. Mit getAudioInputStream kann ein AudioInputStream beschafft werden, mit dem der Inhalt der Sound-Datei gelesen werden kann. Auch hier darf der Parameter wahlweise vom Typ File, InputStream oder URL sein. Die Klasse AudioSystem untersttzt sogar Konvertierungen zwischen verschiedenen Formaten. Ob eine bestimmte Konvertierung verfgbar ist, kann mit isConversionSupported abgefragt werden. Wird getAudioInputStream mit einem Zielformat und einem anderen AudioInputStream als Parameter aufgerufen, fhrt die Methode die Konvertierung durch und liefert einen AudioInputStream, der das gewnschte Zielformat hat.
Audio-Gerte beschaffen Die Klasse AudioSystem stellt auch Methoden zum Zugriff auf Audio-Gerte zur Verfgung: public static Mixer.Info[] getMixerInfo() public static Mixer getMixer(Mixer.Info info)
javax.sound. sampled. AudioSystem
public static Line getLine(Line.Info info) throws LineUnavailableException
Teil VIII
Um herauszufinden, welche Mixer verfgbar sind, muss zunchst getMixerInfo aufgerufen werden. Der Rckgabewert ist ein Array mit Mixer.Info-Objekten, das je vorhandenem Mixer ein Element enthlt. Durch bergabe eines Mixer.Info-Objekts an getMixer kann der zugehçrige Mixer beschafft werden. Man kann allerdings auch ohne explizite Verwendung eines Mixers gesampelten Sound ausgegeben, wenn mit getLine direkt ein geeignetes Audio-Gert beschafft wird. Dazu muss ein Line.Info-Objekt bergeben werden, das dessen Eigenschaften beschreibt. Wir werden in Listing 49.1, Seite 1235 zeigen, wie das Line.Info-Objekt konstruiert werden muss, um einen Clip zu erzeugen.
1233
Kapitel 49
Sound
Die Steuerelemente eines Audio-Gerts Wir hatten eingangs erwhnt, dass eine Line eine Reihe von Steuerelementen zur Verfgung stellt, mit denen Parameter wie Lautstrke, Stereo-Panorama oder Hall eingestellt werden kçnnen. Auf diese kann mit folgenden Methoden zugegriffen werden: javax.sound. sampled.Line
public Control[] getControls() public boolean isControlSupported(Control.Type control) public Control getControl(Control.Type control) getControls liefert ein Array aller verfgbaren Steuerelemente, die durch Instanzen der Klasse Control reprsentiert werden. Mit isControlSupported kann durch bergabe eines Control.Type-Objekts festgestellt werden, ob ein bestimmter Typ vorhanden ist. Mit getControl kann dieser schließlich beschafft werden. Control ist die Basisklasse einer ganzen Gruppe von Kontrollelementen, die sich durch den Datentyp des zu verndernden Parameters unterscheiden. Es gibt die Unterklassen BooleanControl, EnumControl, FloatControl und CompoundControl. Ein FloatControl beispielsweise dient zur Vernderung eines Fließkommawerts (wie etwa der Lautstrke), whrend ein BooleanControl einen An-/Aus-Wert verndern kann (beispielsweise die Stummschaltung eines Elements). Die wichtigsten Methoden der Klasse FloatControl sind:
javax.sound. sampled. FloatControl
public float getMaximum() public float getMinimum() public float getValue() public void setValue(float newValue) Mit getMinimum und getMaximum kçnnen der kleinste und grçßte einstellbare Wert abgefragt werden, mit getValue der aktuelle. Mit setValue kann der Wert des Controls verndert werden. Die Type-Klassen der einzelnen Steuerelemente besitzen jeweils eine Reihe von vordefinierten Konstanten, die an getControl bergeben werden kçnnen. Fr FloatControl.TYPE sind das beispielsweise MASTER_GAIN zur Einstellung der Lautstrke oder PAN zur Vernderung des Stereo-Panoramas. Ein Steuerelement des Typs MASTER_GAIN bestimmt die Gesamtverstrkung, die das Audio-Element dem Ursprungssignal hinzufgt. Ihr Wert wird in Dezibel (dB) angegeben, wobei positive Werte eine Verstrkung und negative eine Abschwchung des Eingangssignals anzeigen. Das Dezibel ist eine logarithmische Maßeinheit, die den Verstrkungsfaktor durch die Formel 10dB/20 ausdrckt. 20 dB entsprechen also einer zehnfachen
1234
Gesampelter Sound
Kapitel 49
Verstrkung, -40 dB einer 100-fachen Abschwchung. 0 dB bedeutet, dass die Strke des Ausgangs- im Verhltnis zum Eingangssignal unverndert bleibt. Ein Steuerelement des Typs PAN bestimmt die Lage des Audio-Signals im Stereo-Panorama. Es kann Werte von -1.0 (ganz links) bis +1.0 (ganz rechts) annehmen. Ein Wert von 0 legt das Signal in die Mitte.
Der Clip Ein Clip ist eine besondere Form einer DataLine, der alle Audiodaten komplett im Hauptspeicher hlt. Wie jede Line muss er vor der Verwendung durch Aufruf von open geçffnet werden und nach Gebrauch mit close geschlossen werden. Zum Abspielen stellt er folgende Methoden zur Verfgung: public void start() public void stop()
javax.sound. sampled.Clip
public boolean isRunning() Ein Aufruf von start startet das Abspielen des Clips, mit stop wird es angehalten. Mit isRunning kann berprft werden, ob die Wiedergabe noch luft oder bereits beendet wurde. INFO
i
i
i
Die Methode start ist nicht modal, d.h., sie wartet beim Aufruf nicht, bis der Clip vollstndig abgespielt ist. Sie initiiert lediglich den Abspielvorgang und kehrt dann sofort zum Aufrufer zurck. Falls dieser auf das Ende warten will, muss er entweder durch wiederholten Aufruf von isRunning den Status des Clips abfragen oder sich bei diesem als Listener registrieren und auf das STOP-Signal warten.
49.2.3 Abspielen einer Sample-Datei Nach den Erklrungen der vorangegangenen Abschnitte wollen wir nun das Beispielprogramm zum Abspielen einer Sample-Datei vorstellen: /* Listing4901.java */ import java.io.*; import javax.sound.sampled.*;
Listing 49.1: Abspielen einer Sample-Datei
public class Listing4901 { private static void playSampleFile(String name, float pan, float gain) throws Exception { //AudioInputStream çffnen
Teil VIII
001 002 003 004 005 006 007 008 009 010 011
1235
Kapitel 49 Listing 49.1: Abspielen einer Sample-Datei (Forts.)
1236
Sound 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060
AudioInputStream ais = AudioSystem.getAudioInputStream( new File(name) ); AudioFormat format = ais.getFormat(); //ALAW/ULAW samples in PCM konvertieren if ((format.getEncoding() == AudioFormat.Encoding.ULAW) || (format.getEncoding() == AudioFormat.Encoding.ALAW)) { AudioFormat tmp = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits() * 2, format.getChannels(), format.getFrameSize() * 2, format.getFrameRate(), true ); ais = AudioSystem.getAudioInputStream(tmp, ais); format = tmp; } //Clip erzeugen und çffnen DataLine.Info info = new DataLine.Info( Clip.class, format, ((int) ais.getFrameLength() * format.getFrameSize()) ); Clip clip = (Clip)AudioSystem.getLine(info); clip.open(ais); //PAN einstellen FloatControl panControl = (FloatControl)clip.getControl( FloatControl.Type.PAN ); panControl.setValue(pan); //MASTER_GAIN einstellen FloatControl gainControl = (FloatControl)clip.getControl( FloatControl.Type.MASTER_GAIN ); gainControl.setValue(gain); //Clip abspielen clip.start(); while (true) { try { Thread.sleep(100); } catch (Exception e) { //nothing } if (!clip.isRunning()) { break; }
Midi 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 }
} clip.stop(); clip.close(); }
Kapitel 49 Listing 49.1: Abspielen einer Sample-Datei (Forts.)
public static void main(String[] args) { try { playSampleFile( args[0], Float.parseFloat(args[1]), Float.parseFloat(args[2]) ); } catch (Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Die Methode playSampleFile çffnet zunchst einen AudioInputStream und bestimmt dessen AudioFormat. Ist dessen Kodierung ULAW oder ALAW, konvertiert es den Stream in das PCM-Format, denn die anderen beiden Formate werden standardmßig nicht untersttzt. Anschließend wird ein DataLine.Info-Objekt instanziert und in Zeile 038 ein Clip damit erzeugt. Dieser wird geçffnet und MASTER_GAIN und PAN werden auf die als Methodenparameter bergebenen Werte eingestellt. In Zeile 051 wird der Clip gestartet und anschließend gewartet, bis er vollstndig abgespielt ist. Das Programm wird mit dem Namen der Datei und den Werten fr PAN und MASTER_GAIN als Kommandozeilenparameter aufgerufen. Es kann zum Abspielen von wav-, aiff- und au-Dateien verwendet werden.
49.3 Midi 49.3.1 Was ist Midi?
Teil VIII
In den siebziger Jahren standen Musiker, die sich mit elektronischer Musik beschftigten, vor einigen Herausforderungen. Zwar gab es gut klingende Synthesizer, die unzhlige Sounds und Erweiterungsmçglichkeiten boten. Doch schwierig wurde es, wenn zwei von ihnen miteinander verbunden werden sollten. Es gab nmlich keinen einheitlichen Standard zur bertragung der Daten zwischen den Systemen. Mit den ersten digitialen Synthesizern der 80er Jahre wurde dieses Problem durch die Schaffung des Midi-Standards behoben. Midi steht fr Musical Instrument Digital Interface und bezeichnet einen Standard, der die bertragung von Daten zwischen zwei oder mehr elektronischen
1237
Kapitel 49
Sound
Musikinstrumenten beschreibt. Neben der Standardisierung der Hardware (Kabel und Stecker) wurde dabei insbesondere festgelegt, welche Daten bertragen und wie sie kodiert werden sollten. Midi war ursprnglich eine serielle Schnittstelle, auf der die Daten byteweise bertragen werden. Drckte der Musiker auf seinem Keyboard die Taste C, wurde diese Information in eine drei Byte lange Nachricht verpackt (Status-/Kanalinformation, Tonhçhe, Lautstrke) und in Echtzeit an die angeschlossenen Synthesizer verschickt. Auch beim Loslassen der Taste wurde eine entsprechende Nachricht verschickt. Die angeschlossenen Synthesizer wurden also ber die Midi-Schnittstelle ferngesteuert. Neben Notendaten kçnnen dabei auch Statusinformationen und Einstellungen von Reglern (Lautstrke, Effekte, Pitch-Bend etc.) bertragen werden. Auch die bertragung proprietrer Daten ist vorgesehen, um die Kommunikation nichtstandardisierter, gertespezifischer Informationen in kontrollierter Weise zu ermçglichen.
i
i
i
INFO Es ist wichtig zu verstehen, dass beim Midi-Protokoll nicht die Audio-Signale an sich bertragen werden, sondern lediglich die Ereignisse, die zur ihrer Entstehung fhren. Midi-Daten kçnnen also in einem gewissen Sinne als die Partitur eines Stcks angesehen werden. Was dann tatschlich erklingt, wird durch die dadurch angesteuerten Synthesizer und ihre klanglichen Eigenschaften bestimmt.
Zunchst war Midi ein reines »Wire«-Protokoll, das die bertragung von Echtzeitdaten ber eine elektrische Verbindung beschrieb. Spter wollte man Midi-Datenstrçme auch aufzeichnen und in Dateien speichern kçnnen und man entwickelte dazu die Midi-Dateiprotokolle. Darin werden die eigentlichen Midi-Nachrichten mit Zeitstempeln versehen, um sie spter mit Hilfe eines Sequenzers in ihrer exakten zeitlichen Abfolge wiedergeben zu kçnnen. Im Sound-API werden Midi-Daten ohne Zeitstempel als Midi-Nachrichten (Midi-Messages) und solche mit Zeitstempel als Midi-Ereignisse (Midi-Events) bezeichnet. Der Inhalt einer Midi-Datei wird blicherweise als Sequenz bezeichnet. Eine Sequenz enthlt eine Reihe von Spuren, die ihrerseits die Midi-Events enthalten. Meist reprsentieren die Spuren die unterschiedlichen Instrumente eines Stcks, so dass etwa in Spur eins das Piano liegt, in Spur zwei der Bass usw. Die verschiedenen Spuren werden innerhalb der Midi-Events durch Kanle reprsentiert, von denen es maximal 16 pro Midi-Schnittstelle gibt.
49.3.2 Grundlegende Klassen des Midi-API hnlich wie im Sampling-API gibt es eine Reihe von Klassen und Interfaces, mit denen die zuvor beschriebenen Konzepte innerhalb des Midi-API umgesetzt werden. Sie befinden sich im zweiten großen Bestandteil des Java Sound-API, dem Paket javax.sound. midi. Wir wollen die wichtigsten von ihnen kurz vorstellen:
1238
Midi
Kapitel 49
" Analog zur Klasse AudioSystem gibt es im Paket javax.sound.midi eine Klasse MidiSystem, mit der Midi-Gerte und Midi-Dateien beschafft und Informationen ber sie abgefragt werden kçnnen. " Ein Midi-Gert wird durch die Klasse MidiDevice reprsentiert. Ein MidiDevice kann entweder geçffnet oder geschlossen sein und besitzt eine Reihe von Ein- und Ausgabeelementen. Die Eingabeelemente werden durch das Interface Receiver, die Ausgabeelemente durch das Interface Transmitter dargestellt. Ein MidiDevice kennt die Anzahl seiner Receiver und Transmitter und stellt diese auf Anfrage zur Verfgung. " Die wichtigsten Unterklassen von MidiDevice sind Synthesizer und Sequencer. Gegenber seiner Vaterklasse besitzt ein Synthesizer zustzlich Informationen ber die verfgbaren Instrumente und ihre Zuordnung auf die verschiedenen Kanle. Ein Sequencer besitzt dagegen Methoden, um eine Sequenz abzuspielen oder anzuhalten und Parameter wie Tempo, Synchronisierung oder Positionierung zu beeinflussen. " Eine Midi-Nachricht wird durch die Klasse MidiMessage und deren Unterklassen ShortMessage, MetaMessage und SysexMessage reprsentiert. Ein Midi-Ereignis wird durch die Klasse MidiEvent dargestellt, die zustzlich zur MidiMessage einen Zeitstempel enthlt. Eine Sequenz wird durch die Klasse Sequence reprsentiert. Sie enthlt neben einigen globalen Informationen zum Timing der Daten eine Reihe von Tracks, die ihrerseits die MidiEvents enthalten. Weitere Details zu den genannten Klassen werden in den folgenden Abschnitten vorgestellt.
49.3.3 Alle meine Entchen – erster Versuch In diesem Abschnitt wollen wir uns die Aufgabe stellen, das allseits bekannte »Alle meine Entchen« mit Hilfe des Midi-API wiederzugeben. Zuerst wollen wir einen sehr einfachen Ansatz whlen, bei dem die Midi-Nachrichten in Echtzeit an einen Synthesizer geschickt werden, wobei das Timing mit Hilfe von Thread.sleep-Aufrufen manuell gesteuert wird. Zunchst wird also ein Synthesizer bençtigt, den wir von der Klasse MidiSystem beziehen kçnnen: public static Synthesizer getSynthesizer() throws MidiUnavailableException
javax.sound.midi. MidiSystem
Teil VIII
getSynthesizer liefert den Default-Synthesizer der installierten Sound-Hardware, typischerweise den auf der Soundkarte eingebauten. Ist mehr als ein Synthesizer vorhanden, muss die Liste aller verfgbaren Synthesizer durch Aufruf von getMidiDeviceInfo durchsucht und mit getMidiDevice der gewnschte ausgewhlt werden. Wir wollen zunchst davon ausgehen, dass ein Default-Synthesizer vorhanden ist, der unseren Ansprchen gengt.
1239
Kapitel 49
Sound
Nachdem der Synthesizer verfgbar ist, muss er geçffnet und zur bergabe von MidiNachrichten ein Receiver beschafft werden: javax.sound.midi. Synthesizer
public void open() throws MidiUnavailableException public void close() public boolean isOpen() public int getMaxReceivers() public Receiver getReceiver() throws MidiUnavailableException Das ffnen und Schließen eines Midi-Gerts wird mit open und close erledigt und mit isOpen kann sein aktueller Status herausgefunden werden. Ein Receiver kann durch Aufruf von getReceiver beschafft werden, die Gesamtzahl aller vorhandenen Receiver kann mit getMaxReceivers abgefragt werden. Um an ein Midi-Gert Daten zu senden, werden diese einfach an einen seiner Receiver geschickt. Dazu besitzt dieser eine Methode send, an die beim Aufruf die gewnschte MidiMessage bergeben wird:
javax.sound.midi. Receiver
javax.sound.midi. MidiDevice
public void send(MidiMessage message, long timeStamp) Das zweite Argument timeStamp ist zur Feinsynchronisierung der Midi-Nachrichten vorgesehen. Damit soll ein Synthesizer in der Lage sein, leichte Timing-Schwankungen beim Anliefern der Daten auszugleichen. Ob ein Gert dieses Feature untersttzt, kann durch Aufruf von getMicrosecondPosition bestimmt werden. Ist dessen Rckgabewert -1, werden derartige Timestamps nicht untersttzt: public long getMicrosecondPosition() Aber auch, wenn diese Timestamps untersttzt werden, sollte man keine Wunder von ihnen erwarten. Die Spezifikation weist ausdrcklich darauf hin, dass damit nur kleinere Timing-Schwankungen ausgeglichen werden kçnnen. Liegt ein Zeitstempel dagegen weit in der Zukunft (oder gar in der Vergangenheit), ist das Midi-Gert nicht verpflichtet, diesen korrekt zu behandeln. Wird -1 an das timeStamp-Argument von send bergeben, ignoriert das entsprechende Gert den Zeitstempel und bearbeitet die Midi-Nachricht, so schnell es kann. Um eine MidiMessage zu konstruieren, wird diese zunchst mit new erzeugt und durch Aufruf von setMessage mit Daten gefllt. Da wir weder Meta- noch Sysex-Daten bençtigen, wollen wir uns lediglich die Konstruktion einer ShortMessage mit Hilfe der folgenden setMessage-Methode ansehen:
1240
Midi
public void setMessage( int command, int channel, int data1, int data2 ) throws InvalidMidiDataException
Kapitel 49
javax.sound.midi. ShortMessage
Als erstes Argument muss das gewnschte Midi-Kommando bergeben werden. Die fr uns relevanten Kommandos sind NOTE_ON (Taste wird gedrckt), NOTE_OFF (Taste wird losgelassen) und PROGRAM_CHANGE (Instrumentenwechsel). Sie werden als Konstanten in der Klasse ShortMessage definiert. Als zweites Argument wird der Kanal angegeben, auf den sich das Kommando auswirken soll. Anschließend folgen zwei Datenbytes, die kommandospezifisch sind. Das NOTE_ON-Kommando erwartet darin beispielsweise die Tonhçhe (die verfgbaren Noten sind als Ganzzahlen durchnummeriert) und die relative Lautstrke (Anschlagsdynamik) der Note. NOTE_OFF erwartet die Tonhçhe als erstes Datenbyte und ignoriert das zweite. PROGRAM_CHANGE erwartet die gewnschte Programmnummer und ignoriert das zweite Datenbyte. Nach diesen Vorbemerkungen wollen wir uns nun ein Beispielprogramm ansehen: /* Listing4902.java */ import javax.sound.midi.*;
Listing 49.2: Alle meine Entchen – erster Versuch
public class Listing4902 { private static void playAlleMeineEntchen() throws Exception { //Partitur {{Tonhoehe, DauerInViertelNoten, AnzahlWdh},...} final int DATA[][] = { {60, 1, 1}, //C {62, 1, 1}, //D {64, 1, 1}, //E {65, 1, 1}, //F {67, 2, 2}, //G,G {69, 1, 4}, //A,A,A,A {67, 4, 1}, //G {69, 1, 4}, //A,A,A,A {67, 4, 1}, //G {65, 1, 4}, //F,F,F,F {64, 2, 2}, //E,E {62, 1, 4}, //D,D,D,D {60, 4, 1} //C }; //Synthesizer çffnen und Receiver holen
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026
1241
Kapitel 49 Listing 49.2: Alle meine Entchen – erster Versuch (Forts.)
Sound 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 }
Synthesizer synth = MidiSystem.getSynthesizer(); synth.open(); Receiver rcvr = synth.getReceiver(); //Melodie spielen ShortMessage msg = new ShortMessage(); for (int i = 0; i < DATA.length; ++i) { for (int j = 0; j < DATA[i][2]; ++j) { //Anzahl Wdh. je Note //Note an msg.setMessage(ShortMessage.NOTE_ON, 0, DATA[i][0], 64); rcvr.send(msg, -1); //Pause try { Thread.sleep(DATA[i][1] * 400); } catch (Exception e) { //nothing } //Note aus msg.setMessage(ShortMessage.NOTE_OFF, 0, DATA[i][0], 0); rcvr.send(msg, -1); } } //Synthesizer schließen synth.close(); } public static void main(String[] args) { try { playAlleMeineEntchen(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Ab Zeile 027 wird ein Synthesizer aktiviert und zur bergabe von Midi-Nachrichten auf einen seiner Receiver zugegriffen. Anschließend wird die Melodie durch wiederholten Aufruf seiner send-Methode abgespielt. Die Melodie ist in dem Array DATA in Zeile 011 versteckt. Fr jede einzelne Note wird dort die Tonhçhe, die Tondauer in Viertelnoten und die Anzahl der Wiederholungen angegeben. Die jeweilige Noteninformation wird mit setMessage an die vorinstanzierte ShortMessage bergeben und als NOTE_ON-Nachricht an den Synthesizer geschickt. In Zeile 039 pausiert das Programm, um die Note entsprechend ihrer Lnge erklingen zu lassen (in unserem Beispiel 400 ms je Viertelnote). Anschließend wird die NOTE_OFF-Nachricht geschickt, um den Ton zu beenden.
1242
Midi
ACHTUNG
Kapitel 49
!
!
!
Wenn wir das Programm mit dem Java-Interpreter starten und eine passende Sound-Hardware vorhanden ist, hçren wir tatschlich »Alle meine Entchen«. Bei unvernderter Standardinstrumentierung sollte die Melodie auf einem Klavier gespielt werden. Wenn wir genau hinhçren, stellen wir allerdings ein Problem fest: Das Timing des Stcks ist nicht przise, sondern schwankt whrend der Darbietung. Manche Noten werden etwas zu kurz, andere dagegen zu lang gespielt. Das liegt daran, dass die mit Thread.sleep erzeugten Notenlngen bei weitem nicht przise genug sind. Die beim Aufruf erzeugten Schwankungen sind fr das menschliche Ohr sehr gut hçrbar und fhren dazu, dass das Musikstck ungenießbar wird. Obwohl das Verfahren prinzipiell funktioniert, bençtigen wir also ein prziseres Wiedergabewerkzeug. Und das ist das Thema des nchsten Abschnitts.
49.3.4 Alle meine Entchen mit dem Sequencer Neben dem Synthesizer ist der Sequencer das zweite wichtige MidiDevice. Er dient dazu, Midi-Sequenzen entsprechend der darin enthaltenen Timing-Information przise wiederzugeben. Das hçrt sich zunchst einmal einfach an, ist es aber nicht. Einerseits bençtigt ein Sequencer einen Zeitgeber, der genauer ist als die blicherweise vom Betriebssystem zur Verfgung gestellten Timer. Zweitens muss dieser mçglichst immun gegen Schwankungen der CPU-Last sein, d.h., der Sequencer sollte auch dann noch stabil arbeiten, wenn im Hintergrund CPU-intensive Operationen ablaufen. Drittens muss ein Sequencer nicht nur, wie in unserem Beispiel, eine einzige Spur mit verhltnismßig langsamen Viertelnoten abspielen, sondern mçglicherweise ein Dutzend von ihnen, mit Achteln, Sechzehnteln oder noch krzeren Noten, wie sie beispielsweise bei Schlagzeugspuren auftreten. Zudem enthalten die Spuren oft immense Mengen an Controller-Daten (z.B. Pitch-Bend), die ebenfalls przise wiedergegeben werden mssen. Zu guter Letzt besitzt ein Sequencer Zusatzfunktionen, wie das ndern der Abspielgeschwindigkeit, das Ausblenden einzelner Spuren oder das Synchronisieren mit externen Taktgebern, und er besitzt in aller Regel einen Aufnahmemodus, mit dem Midi-Daten in Echtzeit aufgenommen werden kçnnen. Wir sehen also, dass die Implementierung eines guten Sequenzers gar nicht so einfach ist. Glcklicherweise stellt das MidiSystem einen eigenen Sequencer zur Verfgung, dessen Standardimplementierung durch einen Aufruf von getSequencer beschafft werden kann: javax.sound.midi. MidiSystem
Beim Abspielen einer Melodie mit dem Sequencer werden die Midi-Nachrichten nicht mehr direkt an den Synthesizer geschickt, sondern zunchst in eine Sequence verpackt. Diese kann wie folgt konstruiert werden: public Sequence(float divisionType, int resolution) throws InvalidMidiDataException
javax.sound.midi. Sequence
1243
Teil VIII
public static Sequencer getSequencer() throws MidiUnavailableException
Kapitel 49
Sound
Das erste Argument gibt die Art und Weise an, wie das Timing erzeugt werden soll. Hier gibt es im Wesentlichen die Mçglichkeiten, einen internen Timer zu verwenden, der auf Bruchteilen von Viertelnoten basiert, oder mit externer Synchronisation zu arbeiten, bei der die Timing-Informationen im SMPTE-Format zur Verfgung gestellt werden. Wir wollen die erste Variante whlen und bergeben dazu die Konstante Sequence.PPQ als erstes Argument. Das zweite Argument resoultion bezieht sich auf das erste und gibt die Auflçsung des Timers an. In unserem Fall wrde es also die Anzahl der Zeitimpulse je Viertelnote angeben. Um eine Sequence mit Daten zu fllen, wird mindestens ein Track bençtigt, der durch Aufruf von createTrack erzeugt werden kann: javax.sound.midi. Sequence
javax.sound.midi. Track
javax.sound.midi. Sequencer
public Track createTrack() Ein Track-Objekt ist zunchst leer und wird durch wiederholte Aufrufe von add mit Midi-Ereignissen versehen: public boolean add(MidiEvent event) Nachdem die Sequence fertiggestellt ist, kann sie durch Aufruf von setSequence an den Sequencer bergeben werden: public void setSequence(Sequence sequence) throws InvalidMidiDataException public void setTempoInBPM(float bpm) public void start() public void stop() public boolean isRunning() Mit setTempoInBPM kann das Abspieltempo in »Beats Per Minute« (kurz BPM), also in Viertelnoten pro Minute, angegeben werden. start startet das Abspielen der Sequenz, stop beendet es. Mit isRunning kann geprft werden, ob der Sequencer gerade luft. Bevor eine Sequence abgespielt werden kann, mssen Synthesizer und Sequencer miteinander verbunden werden. Dies geschieht, indem ein Transmitter des Sequenzers an einen Receiver des Synthesizers angeschlossen wird. Der Transmitter verfgt dazu ber eine Methode setReceiver, an die der empfangende Receiver bergeben wird:
javax.sound.midi. Transmitter
1244
public void setReceiver(Receiver receiver) Nach diesen Vorbemerkungen kçnnen wir uns nun ansehen, wie »Alle meine Entchen« mit Hilfe eines Sequenzers wiedergegeben werden kann.
Midi
/* Listing4903.java */ import javax.sound.midi.*;
Listing 49.3: Alle meine Entchen mit dem Sequenzer
public class Listing4903 { private static void playAlleMeineEntchen() throws Exception { //Partitur {{Tonhoehe, DauerInViertelNoten, AnzahlWdh},...} final int DATA[][] = { {60, 1, 1}, //C {62, 1, 1}, //D {64, 1, 1}, //E {65, 1, 1}, //F {67, 2, 2}, //G,G {69, 1, 4}, //A,A,A,A {67, 4, 1}, //G {69, 1, 4}, //A,A,A,A {67, 4, 1}, //G {65, 1, 4}, //F,F,F,F {64, 2, 2}, //E,E {62, 1, 4}, //D,D,D,D {60, 4, 1} //C }; //Sequence bauen final int PPQS = 16; final int STAKKATO = 4; Sequence seq = new Sequence(Sequence.PPQ, PPQS); Track track = seq.createTrack(); long currentTick = 0; ShortMessage msg; //Kanal 0 auf "EnsembleStrings" umschalten msg = new ShortMessage(); msg.setMessage(ShortMessage.PROGRAM_CHANGE, 0, 48, 0); track.add(new MidiEvent(msg, currentTick)); //Partiturdaten hinzufgen for (int i = 0; i < DATA.length; ++i) { for (int j = 0; j < DATA[i][2]; ++j) { //Anzahl Wdh. je Note msg = new ShortMessage(); msg.setMessage(ShortMessage.NOTE_ON, 0, DATA[i][0], 64); track.add(new MidiEvent(msg, currentTick)); currentTick += PPQS * DATA[i][1] - STAKKATO; msg = new ShortMessage(); msg.setMessage(ShortMessage.NOTE_OFF, 0, DATA[i][0], 0); track.add(new MidiEvent(msg, currentTick)); currentTick += STAKKATO; } }
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049
Kapitel 49
1245
Kapitel 49 Listing 49.3: Alle meine Entchen mit dem Sequenzer (Forts.)
Sound 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 }
//Sequencer und Synthesizer initialisieren Sequencer sequencer = MidiSystem.getSequencer(); Transmitter trans = sequencer.getTransmitter(); Synthesizer synth = MidiSystem.getSynthesizer(); Receiver rcvr = synth.getReceiver(); //Beide çffnen und verbinden sequencer.open(); synth.open(); trans.setReceiver(rcvr); //Sequence abspielen sequencer.setSequence(seq); sequencer.setTempoInBPM(145); sequencer.start(); while (true) { try { Thread.sleep(100); } catch (Exception e) { //nothing } if (!sequencer.isRunning()) { break; } } //Sequencer anhalten und Gerte schließen sequencer.stop(); sequencer.close(); synth.close(); } public static void main(String[] args) { try { playAlleMeineEntchen(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Die Partiturdaten stimmen mit denen des vorigen Beispiels berein, werden allerdings anders verwendet. Zunchst wird ab Zeile 027 eine Sequence mit einem einzelnen Track angelegt, deren Auflçsung 16 Ticks per Viertelnote betrgt. Ab Zeile 038 werden die Daten in ShortMessage-Objekte bertragen und dem Track hinzugefgt. Anders als im vorigen Beispiel lassen wir die Note allerdings nicht whrend der kompletten Notenlnge an, sondern beenden sie STAKKATO Ticks frher als vorgesehen. Diese Zeit zhlen wir in Zeile 047 zu der anschließenden Pause hinzu. Durch diese Maßnahme gehen die Noten
1246
Midi
Kapitel 49
nicht direkt ineinander ber, sondern werden mit einem hçrbaren Abstand gespielt. In Zeile 034 wird eine ShortMessage zur Programmumschaltung generiert, um Kanal 0 auf Instrument 48 umzuschalten. Dadurch erklingt die Sequenz nicht mit einem Piano-, sondern mit einem Streichersound. Ab Zeile 051 werden Sequencer und Synthesizer initialisiert und miteinander verbunden. Anschließend wird die Sequence an den Sequenzer bergeben, die Abspielgeschwindigkeit eingestellt und das Stck gespielt. In der nachfolgenden Schleife wartet das Programm durch wiederholten Aufruf von isRunning, bis die Sequenz vollstndig abgespielt ist. Anschließend stoppt es den Sequenzer und schließt alle Gerte.
49.3.5 Zugriff auf Midi-Dateien Lesen und Abspielen einer Midi-Datei Als letztes Beispiel zum Thema Midi wollen wir uns ansehen, wie eine Midi-Datei gelesen und abgespielt werden kann. Dazu bençtigen wir nur noch eine zustzliche Methode, nmlich getSequence aus der Klasse MidiSystem: public static Sequence getSequence(File file) throws InvalidMidiDataException, IOException
javax.sound.midi. MidiSystem
getSequence erwartet ein File-Objekt als Argument, mit dem die abzuspielende MidiDatei angegeben wird. Es liefert als Rckgabewert eine Sequence, die an den Sequenzer bergeben und von diesem abgespielt werden kann. Ein Beispielprogramm zur Wiedergabe einer Midi-Datei ist nun sehr einfach zu konstruieren. Mit Ausnahme der expliziten Konstruktion der Sequence entspricht es vollkommen dem Beispielprogramm des vorigen Abschnitts: /* Listing4904.java */ import java.io.*; import javax.sound.midi.*;
Listing 49.4: Abspielen einer Midi-Datei
public class Listing4904 { private static void playMidiFile(String name) throws Exception { //Sequencer und Synthesizer initialisieren Sequencer sequencer = MidiSystem.getSequencer(); Transmitter trans = sequencer.getTransmitter(); Synthesizer synth = MidiSystem.getSynthesizer(); Receiver rcvr = synth.getReceiver(); //Beide çffnen und verbinden sequencer.open(); synth.open(); trans.setReceiver(rcvr);
Teil VIII
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019
1247
Kapitel 49 Listing 49.4: Abspielen einer Midi-Datei (Forts.)
Sound 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 }
//Sequence lesen und abspielen Sequence seq = MidiSystem.getSequence(new File(name)); sequencer.setSequence(seq); sequencer.setTempoInBPM(145); sequencer.start(); while (true) { try { Thread.sleep(100); } catch (Exception e) { //nothing } if (!sequencer.isRunning()) { break; } } //Sequencer anhalten und Gerte schließen sequencer.stop(); sequencer.close(); synth.close(); } public static void main(String[] args) { try { playMidiFile(args[0]); } catch (Exception e) { e.printStackTrace(); System.exit(1); } System.exit(0); }
Das Programm erwartet in der Kommandozeile den Namen der abzuspielenden MidiDatei. Wird es mit der (ebenfalls im Verzeichnis der Beispieldateien befindlichen) Datei ame.mid als Argument aufgerufen, ertçnt das altbekannte »Alle meine Entchen«.
Abspeichern einer Sequenz in einer Midi-Datei Das Abspeichern einer Sequence in einer Midi-Datei ist fast so einfach wie ihr Abspielen. Die Klasse MidiSystem besitzt dazu eine Methode write, die drei Parameter erwartet: javax.sound.midi. MidiSystem
public static int write(Sequence in, int type, File out) throws IOException Als erstes Argument wird die zu speichernde Sequence bergeben, als zweites Argument der Midi-Dateityp und als Letztes ein File-Objekt mit dem Namen der Ausgabedatei. Fr einfache Experimente kann als Midi-Dateityp einfach 0 bergeben werden. Ein Array mit allen untersttzten Dateitypen lsst sich durch Aufruf von getMidiFileTypes beschaffen.
1248
Zusammenfassung
Kapitel 49
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Grundlagen des Samplings " Die Klasse AudioSystem zur Beschaffung von Audio-Ressourcen " Sampling-Formate und die Klassen AudioFormat und AudioFileFormat " Zugriff auf Audio-Dateien mit der Klasse AudioInputStream " Die Audio-Gerte Mixer, Line und Clip " Die Steuerelemente eines Audio-Gerts sowie die Klasse Control und ihre Unterklassen " Verwendung der Klasse Clip zum Abspielen einer Sound-Datei " Grundlagen von Midi " Die Klasse MidiSystem zur Beschaffung von Midi-Ressourcen " Die Midi-Gerte-Klassen MidiDevice, Synthesizer und Sequencer sowie ihre Verbindungselemente Transmitter und Receiver " Direkter Zugriff auf einen Synthesizer zum Abspielen einer Folge von Midi-Nachrichten " Erstellen von Sequenzen und Abspielen derselben mit dem Sequenzer " Lesen und Abspielen von Midi-Dateien
Teil VIII
" Abspeichern einer Sequence in eine Midi-Datei
1249
Teil IX Verschiedenes 50 Performance-Tuning................................. 1253
Teil IX
51 Hilfsprogramme des JDK .......................... 1277
50
Performance-Tuning
50.1
Einleitung
Java gilt gemeinhin als Sprache, die mit PerformanceProblemen zu kmpfen hat. Nicht nur die Ablaufgeschwindigkeit des Compilers und anderer Entwicklungswerkzeuge, sondern vor allem die der eigenen Programme lsst oft zu wnschen brig. Aufgrund der Plattformunabhngigkeit des vom Compiler generierten Bytecodes kann dieser normalerweise nicht direkt auf dem jeweiligen Betriebssystem ausgefhrt werden. Er verwendet stattdessen einen eigenen Interpreter, die Virtuelle Maschine (kurz: VM), zur Ausfhrung der erstellten Programme. Interpretierter Code wird naturgemß langsamer ausgefhrt als kompilierter, selbst wenn er in Form von Bytecodes vorliegt. Zwar ist es prinzipiell mçglich, auch Java-Programme in Native-Code zu bersetzen (es gibt sogar einige kommerzielle Tools, die das tun), aber dann ist es mit der Plattformunabhngigkeit vorbei und das fertige Programm luft nur noch auf einem Betriebssystem. Whrend das fr Applikationen in bestimmten Fllen akzeptabel sein mag, verbietet sich diese Vorgehensweise fr Applets, die im Internet auf vielen verschiedenen Browsern und Betriebssystemen laufen mssen, von selbst. Zudem konterkarieren native-kompilierte Programme die Grundidee der plattformbergreifenden Binrkompatibilitt, die eine der herausragenden Eigenschaften von Java ist.
Teil IX
Eine Alternativlçsung bieten Just-In-Time-Compiler (kurz: JIT), deren Entwicklung in großen Schritten voranschreitet. Ein JIT ist ein Programm, das den Bytecode von Methoden whrend der Ausfhrung des Programms in Maschinencode der aktuellen Plattform ber-
Kapitel 50
Performance-Tuning
setzt und so beim nchsten Aufruf wesentlich schneller ausfhren kann. Vorteilhaft ist dabei, dass die Klassendateien mit dem Bytecode unverndert ausgeliefert werden kçnnen und das Programm seinen plattformbergreifenden Charakter erhlt. Nur der Just-In-Time-Compiler ist plattformspezifisch und an ein bestimmtes Betriebssystem gebunden. Nahezu alle Hersteller kommerzieller Java-Produkte haben mittlerweile einen JIT als festen Bestandteil ihres Java-Entwicklungssystems eingebunden. Auch SUN liefert seit dem JDK 1.1.6 den Just-In-Time-Compiler von Symantec als festen Bestandteil des JDK aus. Leider ist auch ein Just-In-Time-Compiler kein Allheilmittel gegen Performanceprobleme. Zwar ist er in der Lage, bestimmte Codeteile so stark zu beschleunigen, dass ihre Ablaufgeschwindigkeit der von kompiliertem C-Code nahekommt. Andererseits gibt es nach wie vor gengend Mçglichkeiten, Programme zu schreiben, die inhrent langsamen Code enthalten, der auch von einem Just-In-Time-Compiler nicht entscheidend verbessert werden kann. Zudem ensteht durch den Einsatz des JIT ein gewisser Overhead, der mçglicherweise einen Netto-Performancegewinn verhindert, denn das Kompilieren des Bytecodes kostet Zeit und zustzlichen Speicher. Des Weiteren ist zu bedenken, dass zur Laufzeit eine Vielzahl von Checks durchgefhrt werden mssen, die die Ablaufgeschwindigkeit von Java-Programmen vermindert: " Array- und String-Zugriffe werden auf Bereichsberschreitungen geprft. " Zeiger werden vor der Dereferenzierung gegen null gecheckt. " Zuweisungen von Objektinstanzen werden auf korrekte Typisierung geprft. " Es gibt Checks zu vielen arithmetischen Operationen (berlufe, Teilen durch Null usw.). Am besten ist es daher, bereits whrend der Entwicklung der Programme auf die Ablaufgeschwindigkeit des erzeugten Codes zu achten. Wir wollen uns in diesem Kapitel einige typische Java-Konstrukte ansehen, die bei unachtsamer Verwendung zu PerformanceProblemen fhren kçnnen. Gleichzeitig wollen wir Mçglichkeiten aufzeigen, wie man mit alternativem Code den Engpass umgehen und die Ablaufgeschwindigkeit des Programms verbessern kann. Wenn man diese Regeln beachtet, ist es durchaus mçglich, in Java grçßere Programme zu schreiben, deren Laufzeitverhalten auf aktuellen Rechnern absolut akzeptabel ist.
i
i
i
INFO Wir wollen uns in diesem Kapitel nicht mit grundlegenden Techniken der Codeoptimierung beschftigen. Auch wenn sie zeitweilig kurz angedeutet werden, kçnnen diese Themen besser in Bchern ber Programmiersprachen, Algorithmen oder Optimierungstechniken fr Compiler nachgelesen werden. Auch Tipps & Tricks, die in aller Regel nur marginale
1254
Tuning-Tipps
Kapitel 50
Verbesserungen bringen, oder langsamer Code, fr den keine einfach anzuwendenden Alternativen bekannt sind, sollen hier nicht behandelt werden. Stattdessen wollen wir uns auf einige große Themenkomplexe konzentrieren, die leicht umzusetzen sind und in der Praxis schnell zu Verbesserungen fhren.
50.2 Tuning-Tipps 50.2.1 String und StringBuilder String-Verkettung In Java gibt es zwei unterschiedliche Klassen String und StringBuilder zur Verarbeitung von Zeichenketten, deren prinzipielle Eigenschaften in Kapitel 11, Seite 265 erlutert wurden. Java-Anfnger verwenden meist hauptschlich die Klasse String, denn sie stellt die meisten Methoden zur Zeichenkettenextraktion und -verarbeitung zur Verfgung und bietet mit dem +-Operator eine bequeme Mçglichkeit, Zeichenketten miteinander zu verketten. Dass diese Bequemlichkeit ihren Preis hat, zeigt folgender Programmausschnitt: 001 002 003 004 005
String s; s = ""; for (int i = 0; i < 20000; ++i) { s += "x"; }
Listing 50.1: Langsame StringVerkettung
Das Programmfragment hat die Aufgabe, einen String zu erstellen, der aus 20000 aneinandergereihten »x« besteht. Das ist zwar nicht sehr praxisnah, illustriert aber die hufig vorkommende Verwendung des +=-Operators auf Strings. Der obige Code ist sehr ineffizient, denn er luft langsam und belastet das Laufzeitsystem durch 60000 temporre Objekte, die alloziert und vom Garbage Collector wieder freigegeben werden mssen. Der Compiler bersetzt das Programmfragment etwa so: 001 002 003 004 005
String s; s = ""; for (int i = 0; i < 20000; ++i) { s = new StringBuilder(s).append("x").toString(); }
Listing 50.2: Wie der Java-Compiler String-Verkettungen bersetzt
1255
Teil IX
Dieser Code ist in mehrfacher Hinsicht unglcklich. Pro Schleifendurchlauf wird ein temporres StringBuilder-Objekt alloziert und mit dem zuvor erzeugten String initialisiert. Der Konstruktor von StringBuilder erzeugt ein internes Array (also eine weitere Objektinstanz), um die Zeichenkette zu speichern. Immerhin ist dieses Array 16 Byte grçßer als eigentlich erforderlich, so dass der nachfolgende Aufruf von append das Array nicht neu allozieren und die Zeichen umkopieren muss. Schließlich wird durch den Aufruf von toString ein neues String-Objekt erzeugt und s zugewiesen. Auf diese Weise
Kapitel 50
Performance-Tuning
werden pro Schleifendurchlauf drei temporre Objekte erzeugt und der Code ist durch das wiederholte Kopieren der Zeichen im Konstruktor von StringBuilder sehr ineffizient. Eine eminente Verbesserung ergibt sich, wenn die Klasse StringBuilder und ihre Methode append direkt verwendet werden: Listing 50.3: Performante String-Verkettungen mit StringBuilder.append
001 002 003 004 005 006
String s; StringBuilder sb = new StringBuilder(1000); for (int i = 0; i < 20000; ++i) { sb.append("x"); } s = sb.toString();
Hier wird zunchst ein StringBuilder erzeugt und mit einem 1000 Zeichen großen Puffer versehen. Da die StringBuilder-Klasse sich die Lnge der gespeicherten Zeichenkette merkt, kann der Aufruf append("x") meist in konstanter Laufzeit erfolgen. Dabei ist ein Umkopieren nur dann erforderlich, wenn der interne Puffer nicht mehr gengend Platz bietet, um die an append bergebenen Daten zu bernehmen. In diesem Fall wird ein grçßeres Array alloziert und der Inhalt des bisherigen Puffers umkopiert. In der Summe ist die letzte Version etwa um den Faktor 10 schneller als die ersten beiden und erzeugt 60000 temporre Objekte weniger. Interessant ist dabei der Umfang der Puffervergrçßerung, den das StringBuilder-Objekt vornimmt, denn er bestimmt, wann bei fortgesetztem Aufruf von append das nchste Mal umkopiert werden muss. Anders als beispielsweise bei der Klasse Vector, die einen vernderbaren Ladefaktor besitzt, verdoppelt sich die Grçße eines StringBuilder-Objekts bei jeder Kapazittserweiterung. Dadurch wird zwar mçglicherweise mehr Speicher als nçtig alloziert, aber die Anzahl der Kopiervorgnge wchst hçchstens logarithmisch mit der Gesamtmenge der eingefgten Daten. In unserem Beispiel kann der interne Puffer zunchst 1000 Zeichen aufnehmen, wird beim nchsten berlauf auf etwa 2000 Zeichen vergrçßert, dann auf 4000, 8000, 16000 und schließlich auf 32000 Zeichen. Htten wir die initiale Grçße auf 20000 Zeichen gesetzt, wre sogar berhaupt kein Kopiervorgang erforderlich geworden und das Programm htte 12000 Zeichen weniger alloziert.
!
!
!
ACHTUNG Bei der Verwendung der Operatoren + und += auf String-Objekten sollte man zustzlich bedenken, dass deren Laufzeit nicht konstant ist (bzw. ausschließlich von der Lnge des anzuhngenden Strings abhngt). Tatschlich hngt sie auch stark von der Lnge des Strings ab, an den angehngt werden soll, denn die Laufzeit eines Kopiervorgangs wchst nun einmal proportional zur Lnge des zu kopierenden Objekts. Damit wchst das Laufzeitverhalten der Schleife in Listing 50.1, Seite 1255 nicht linear, sondern annhernd quadratisch. Es verschlechtert sich also mit zunehmender Lnge der Schleife berproportional.
1256
Tuning-Tipps
Kapitel 50
Einfgen und Lçschen in Strings Ein immer noch deutlicher, wenn auch nicht ganz so drastischer Vorteil bei der Verwendung von StringBuilder ergibt sich beim Einfgen von Zeichen am vorderen Ende des Strings: 001 002 003 004 005
String s; s = ""; for (int i = 0; i < 10000; ++i) { s = "x" + s; }
Listing 50.4: Langsames Einfgen in einen String
In diesem Beispiel wird wiederholt ein Zeichen vorne in den String eingefgt. Der Compiler wandelt das Programm auch hier in wiederholte Aufrufe von StringBuilderMethoden um, wobei unnçtig viele Zwischenobjekte entstehen und unnçtig oft kopiert werden muss. Eine bessere Lçsung kann man auch hier durch direkte Verwendung eines StringBuilder-Objekts erzielen: 001 002 003 004 005 006
String s; StringBuilder sb = new StringBuilder(1000); for (int i = 0; i < 10000; ++i) { sb.insert(0, "x"); } s = sb.toString();
Listing 50.5: Schnelles Einfgen in einen String
Im Test war die Laufzeit dieser Variante etwa um den Faktor vier besser als die der ersten Version. Außerdem wird nicht ein einziges temporres Objekt erzeugt, so dass zustzlich das Memory-Subsystem und der Garbage Collector entlastet werden. JDK 1.1–6.0 Seit dem JDK 1.2 gibt es in der Klasse StringBuilder (beziehungsweise in der Klasse StringBuffer) eine Methode delete, mit der ein Teil der Zeichenkette gelçscht werden kann. Dadurch kçnnen beispielsweise Programmteile der folgenden Art beschleunigt werden:
» » »
String sub1 = s.substring(0, 1000) + s.substring(2000); Anstatt hier die ersten 1000 Zeichen mit allen Zeichen ab Position 2000 zu verbinden, kann unter Verwendung eines StringBuilder auch direkt das gewnschte Stck gelçscht werden:
String sub2 = sb.delete(1000, 2000).toString();
Die Methode toString der Klasse StringBuilder
1257
Teil IX
Den vorangegangenen Abschnitten lsst sich entnehmen, dass die Verwendung der Klasse StringBuilder meist dann sinnvoll ist, wenn die Zeichenkette zunchst aus vielen kleinen Teilen aufgebaut werden soll oder wenn sie sich hufig ndert. Ist der String dagegen fertig konstruiert oder muss auf einen vorhandenen String lesend zugegriffen werden, geht dies im Allgemeinen mit den vielseitigeren Methoden der Klasse String
Kapitel 50
Performance-Tuning
besser. Um einen StringBuilder in einen String zu konvertieren, wird die Methode toString aufgerufen, die durch einen kleinen Trick sehr effizient arbeitet. Anstatt beim Aufruf von toString einen Kopiervorgang zu starten, teilen sich String- und StringBuilder-Objekt nach dem Aufruf das interne Zeichenarray, d.h., beide Objekte verwenden einund denselben Puffer. Normalerweise wre diese Vorgehensweise indiskutabel, denn nach der nchsten nderung des StringBuilder-Objekts htte sich dann auch der Inhalt des String-Objekts verndert (was per Definition nicht erlaubt ist). Um das zu verhindern, wird vom Konstruktor der String-Klasse whrend des Aufrufs von toString ein shared-Flag im StringBuilder-Objekt gesetzt. Dieses wird bei allen verndernden StringBuilder-Methoden abgefragt und fhrt dazu, dass – wenn es gesetzt ist – der Pufferinhalt vor der Vernderung kopiert und die nderung auf der Kopie vorgenommen wird. Ein echter Kopiervorgang wird also so lange nicht erforderlich, wie auf den StringBuilder nicht schreibend zugegriffen wird.
Die Unvernderlichkeit von String-Objekten Da die Klasse String keine Mçglichkeit bietet, die gespeicherte Zeichenkette nach der Instanzierung des Objekts zu verndern, kçnnen einige Operationen auf Zeichenketten sehr effizient implementiert werden. So erfordert beispielsweise die einfache Zuweisung zweier String-Objekte lediglich das Kopieren eines Zeigers, ohne dass durch Aliasing die Gefahr besteht, beim ndern eines Strings versehentlich weitere Objekte zu ndern, die auf denselben Speicherbereich zeigen. Soll ein String physikalisch kopiert werden, kann das mit Hilfe eines speziellen Konstruktors erreicht werden: String s2 = new String(s1); Da der interne Puffer hierbei kopiert wird, ist der Aufruf natrlich ineffizienter als die einfache Zuweisung. Auch die Methode substring der Klasse String konnte sehr effizient implementiert werden. Sie erzeugt zwar ein neues String-Objekt, aber den internen Zeichenpuffer teilt es sich mit dem bisherigen Objekt. Lediglich die Membervariablen, in denen die Startposition und relevante Lnge des Puffers festgehalten werden, mssen im neuen Objekt angepasst werden. Dadurch ist auch das Extrahieren von langen Teilzeichenketten recht performant. Dasselbe gilt fr die Methode trim, die ebenfalls substring verwendet und daher keine Zeichen kopieren muss.
1258
Tuning-Tipps
Kapitel 50
Durchlaufen von Zeichenketten Soll ein String durchlaufen werden, so lsst sich mit der Methode length seine Lnge ermitteln und durch wiederholten Aufruf von charAt kçnnen alle Zeichen nacheinander abgeholt werden. Alternativ kçnnte man auch zunchst ein Zeichenarray allozieren und durch Aufruf von getChars alle Zeichen hineinkopieren. Beim spteren Durchlaufen wre dann kein Methodenaufruf mehr erforderlich, sondern die einzelnen Array-Elemente kçnnten direkt verwendet werden. Die Laufzeitunterschiede zwischen beiden Varianten sind allerdings minimal und werden in der Praxis kaum ins Gewicht fallen (da die Klasse String als final deklariert wurde und die Methode charAt nicht synchronized ist, kann sie sehr performant aufgerufen werden).
Das Interface CharSequence und die Methode toString Wenn Sie eine Zeichenkette aus Einzelstcken zusammensetzen, verwenden Sie am besten die Klasse StringBuilder. Doch wenn Sie diese Zeichenkette anschließend als Parameter oder Rckgabewert bergeben, wird dieser hufig ber die Methode toString in einen quivalenten String umgewandelt. Wird die Zeichenkette anschließend weiterbearbeitet, wird der bergebene String anschließend wieder in einen StringBuilder umgewandelt und so weiter. Sie kçnnen sich diese unnçtigen Kopieroperationen allerdings auch sparen und Ihren Code gleichzeitig wesentlich lesbarer machen, indem Sie in diesen Fllen einfach in der Methodensignatur einen Parameter vom Typ StringBuilder definieren und das Objekt direkt bergeben. Kçnnen Sie die Signatur der Methode allerdings nicht ndern – etwa, weil die Methode auch mit gewçhnlichen Strings aufgerufen werden soll –, hlt das JDK seit der Version 5 das Interface CharSequence fr Sie bereit, welches bereits in Abschnitt 11.5, Seite 277 vorgestellt wurde. Dieses Interface wird sowohl von der Klasse String als auch von StringBuilder implementiert und gestattet es, Objekte beiden Typs zu bergeben.
50.2.2 Methodenaufrufe
1259
Teil IX
Eine der hufigsten Operationen in objektorientierten Programmiersprachen ist der Aufruf einer Methode an einer Klasse oder einem Objekt. Generell werden Methodenaufrufe in Java recht performant ausgefhrt. Ihr Laufzeitverhalten ist jedoch stark von ihrer Signatur und ihren Attributen abhngig. Tabelle 50.1, Seite 1260 gibt einen berblick ber die Laufzeit (in msec.) von 10 Millionen Aufrufen einer trivialen Methode unter unterschiedlichen Bedingungen. Alle Messungen wurden mit dem JDK 1.2 Beta 4 auf einem PentiumII-266 unter Windows 95 vorgenommen.
Kapitel 50
Tabelle 50.1: Geschwindigkeit von Methodenaufrufen
Performance-Tuning
Signatur/Attribute
Ohne JIT
Mit JIT
public
5650
280
public, mit vier Parametern
7800
390
public static
5060
110
protected
5770
280
private
5820
50
public synchronized
9500
4660
public final
6260
50
Dabei fallen einige Dinge auf: " In jedem Fall bringt der JIT einen erheblichen Geschwindigkeitsvorteil. Er liegt (mit Ausnahme der synchronized-Methode) in diesem Beispiel durchweg bei ber einer Zehnerpotenz. " Methoden des Typs final und private werden am schnellsten ausgefhrt, insbesondere bei aktiviertem JIT. " Klassenmethoden werden schneller ausgefhrt als Instanzmethoden. " Die bergabe von Parametern erfordert zustzliche Zeit. In unserem Beispiel wurden vier Argumente (int, String, double und boolean) bergeben. " Mit Abstand am langsamsten ist der Aufruf von Methoden, die das synchronizedAttribut verwenden, denn der Zugriff auf die Sperre zur Synchronisation in MultiThreading-Umgebungen kostet erhebliche Zeit. Auch der Just-In-Time-Compiler bringt hier keine nennenswerten Vorteile. Weiterhin ist zu beachten, dass der polymorphe Aufruf von Methoden Zeit kostet (was nicht aus dieser Tabelle abgelesen werden kann). Ist beispielsweise aus einer Klasse A eine weitere Klasse B abgeleitet, so ist der Aufruf von Methoden auf einem Objekt des Typs A kostspieliger als der auf einem Objekt des Typs B. Aus diesen Ergebnissen allgemeingltige Empfehlungen abzuleiten, ist schwierig. Zwar empfiehlt es sich offensichtlich, Methoden als private bzw. final zu deklarieren, wenn sicher ist, dass sie in abgeleiteten Klassen nicht aufgerufen bzw. berlagert werden sollen. Auch kçnnte man versuchen, verstrkt Klassenmethoden zu verwenden oder zur Vermeidung von polymorphen Aufrufen die Vererbungshierarchie zu beschrnken oder mit Hilfe des Attributs final ganz abzuschneiden. All diese Entscheidungen htten aber einen starken Einfluss auf das Klassendesign der Anwendung und kçnnten sich leicht an anderer Stelle als Sackgasse herausstellen. Der einzig wirklich allgemeingltige Rat besteht darin, Methoden nur dann als synchronized zu deklarieren, wenn es wirklich erforderlich ist. Eine Methode, die keine Membervariablen verwendet, die gleichzeitig von anderen Threads manipuliert werden, braucht
1260
Tuning-Tipps
Kapitel 50
auch nicht synchronisiert zu werden. Eine Anwendung, die nur einen einzigen Thread besitzt und deren Methoden nicht von Hintergrundthreads aufgerufen werden, braucht berhaupt keine synchronisierten Methoden in eigenen Klassen.
50.2.3 Vektoren und Listen Ein Vector ist ein bequemes Hilfsmittel, um Listen von Objekten zu speichern, auf die sowohl sequentiell als auch wahlfrei zugriffen werden kann. Aufgrund seiner einfachen Anwendung und seiner Flexibilitt bezglich der Art und Menge der zu speichernden Elemente wird er in vielen Programmen ausgiebig verwendet. Bei falschem Einsatz kçnnen Vektoren durchaus zum Performance-Killer werden, und wir wollen daher einige Hinweise zu ihrer Verwendung geben. Zunchst einmal ist der Datenpuffer eines Vektors als Array implementiert. Da die Grçße von Arrays nach ihrer Initialisierung nicht mehr verndert werden kann, erfordert das Einfgen neuer Elemente mçglicherweise das Allozieren eines neuen Puffers und das Umkopieren der vorhandenen Elemente. Ein Vector besitzt dazu die beiden Attribute Kapazitt und Ladefaktor. Die Kapazitt gibt an, wie viele Elemente insgesamt aufgenommen werden kçnnen, also wie groß der interne Puffer ist. Der Ladefaktor bestimmt, um wie viele Elemente der interne Puffer erweitert wird, wenn beim Einfgen eines neuen Elements nicht mehr ausreichend Platz vorhanden ist. Je kleiner die anfngliche Kapazitt und der Ladefaktor sind, desto hufiger ist beim fortgesetzten Einfgen von Elementen ein zeitaufwndiges Umkopieren erforderlich. Wird ein Vector ohne Argumente instanziert, so hat sein Puffer eine anfngliche Kapazitt von zehn Objekten und der Ladefaktor ist 0. Letzteres bedeutet, dass die Kapazitt bei jeder Erweiterung verdoppelt wird (analog zur Klasse StringBuilder, s. Abschnitt 50.2.1, Seite 1255). Alternativ kçnnen die Kapazitt oder auch beide Werte beim Instanzieren an den Konstruktor bergeben werden. Durch die folgende Deklaration wird ein Vector mit einer anfnglichen Kapazitt von 100 Elementen und einem Ladefaktor von 50 angelegt: Vector v = new Vector(100, 50); Ein weiteres Problem der Klasse Vector ist, dass die meisten ihrer Methoden als synchronized deklariert wurden. Dadurch kann ein Vector zwar sehr einfach als gemeinsame Datenstruktur mehrerer Threads verwendet werden. Die Zugriffsmethoden sind aber leider auch ohne Multi-Threading-Betrieb entsprechend langsam.
Seit der Version 1.2 des JDK stehen mit den Klassen LinkedList und ArrayList auch alternative Listenimplementierungen zur Verfgung, die anstelle von Vector verwendet werden kçnnen. Hier ist jedoch Vorsicht geboten, soll das Programm nicht langsamer laufen als vorher. Die Klasse LinkedList implementiert die Datenstruktur in klassischer Form als doppelt verkettete Liste ihrer Elemente. Zwar entfallen dadurch die Kopiervorgnge, die beim Erweitern des Arrays erforderlich waren. Durch die Vielzahl der allozierten Objekte, in
» » »
1261
Teil IX
JDK 1.1–6.0
Kapitel 50
Performance-Tuning
denen die Listenelemente und die Zeiger gespeichert werden mssen, und die teilweise ineffiziente Implementierung einiger Grundoperationen (insbesondere add) hat sich LinkedList jedoch im Test als relativ ineffizient herausgestellt. Wesentlich bessere Ergebnisse gab es mit der Klasse ArrayList. Sie ist hnlich wie Vector implementiert, verzichtet aber (wie die meisten 1.2er Collections) auf die synchronized-Attribute und ist daher – insbesondere bei aktiviertem JIT und Zugriff mit add und get sehr – performant.
Listing 50.6, Seite 1262 zeigt drei Methoden, die jeweils ein String-Array bergeben bekommen und daraus eine bestimmte Anzahl von Elementen zurckgeben. Die erste Version verwendet einen Vector, die zweite eine LinkedList und die dritte eine ArrayList zur Datenspeicherung. Im Test war die dritte Version eindeutig die schnellste. Bei aktiviertem JIT und bergabe von 100000 Elementen, von denen jeweils die Hlfte zurckgegeben wurden, war das Verhltnis der Laufzeiten der drei Methoden etwa 3:18:1. Listing 50.6: Vergleich von Listen und Vektoren
1262
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032
public static String[] vtest1(String el[], int retsize) { //Verwendet Vector Vector v = new Vector(el.length + 10); for (int i = 0; i < el.length; ++i) { v.addElement(el[i]); } String[] ret = new String[retsize]; for (int i = 0; i < retsize; ++i) { ret[i] = (String)v.elementAt(i); } return ret; } public static String[] vtest2(String el[], int retsize) { //Verwendet LinkedList LinkedList l = new LinkedList(); for (int i = 0; i < el.length; ++i) { l.add(el[i]); } String[] ret = new String[retsize]; Iterator it = l.iterator(); for (int i = 0; i < retsize; ++i) { ret[i] = (String)it.next(); } return ret; } public static String[] vtest3(String el[], int retsize) { //Verwendet ArrayList
Tuning-Tipps 033 034 035 036 037 038 039 040 041 042 }
ArrayList l = new ArrayList(el.length + 10); for (int i = 0; i < el.length; ++i) { l.add(el[i]); } String[] ret = new String[retsize]; for (int i = 0; i < retsize; ++i) { ret[i] = (String)l.get(i); } return ret;
Kapitel 50 Listing 50.6: Vergleich von Listen und Vektoren (Forts.)
Ist es dagegen erforderlich, viele Einfgungen und Lçschungen innerhalb der Liste vorzunehmen, sollte im Allgemeinen eine zeigerbasierte Implementierung der arraybasierten vorgezogen werden. Whrend es bei Letzterer stets erforderlich ist, einen Teil des Arrays umzukopieren, wenn ein Element eingefgt oder gelçscht wird, brauchen bei den verzeigerten Datenstrukturen lediglich ein paar Verweise aktualisiert zu werden.
50.2.4 Dateizugriffe Schreiben von Streams Seit dem JDK 1.1 gibt es die Writer-Klassen, mit denen Character-Streams verarbeitet werden kçnnen. Passend zur internen Darstellung des char-Typs in Java verwenden sie 16-Bit breite UNICODE-Zeichen zur Ein- und Ausgabe. Um eine Datei zu erzeugen, kann ein FileWriter-Objekt angelegt werden, und die Zeichen werden mit den write-Methoden geschrieben. Um die Performance zu erhçhen, kann der FileWriter in einen BufferedWriter gekapselt werden, der mit Hilfe eines internen Zeichenpuffers die Anzahl der Schreibzugriffe reduziert. Im Test ergab sich dadurch ein Geschwindigkeitszuwachs um den Faktor drei bis vier gegenber dem ungepufferten Zugriff. Die von BufferedWriter verwendete Standard-Puffergrçße von 8 Kbyte ist in aller Regel ausreichend, weitere Vergrçßerungen bringen keine nennenswerten Beschleunigungen. Das Dilemma der Writer-Klassen besteht darin, dass die meisten externen Dateien mit 8-Bit-Zeichen arbeiten, statt mit 16-Bit-UNICODE-Zeichen. Ein FileWriter fhrt also vor der Ausgabe eine Konvertierung der UNICODE-Zeichen durch, um sie im korrekten Format abzuspeichern. Der Aufruf der dazu verwendeten Methoden der Klasse CharToByteConverter aus dem Paket sun.io kostet natrlich Zeit und vermindert die Performance der Writer-Klasse. Wesentlich schneller sind die (lteren) OutputStream-Klassen, die nicht mit Zeichen, sondern mit Bytes arbeiten. Sie fhren keine aufwndige Konvertierung durch, sondern geben je Zeichen einfach dessen niederwertige 8 Bit aus. Das spart viel Zeit und fhrte im Test zu einer nochmals um den Faktor drei bis vier beschleunigten Ausgabe (wenn auch der FileOutputStream in einen BufferedOutputStream eingeschlossen wurde).
1263
Teil IX
Die OutputStream-Klassen sind also immer dann den Writer-Klassen vorzuziehen, wenn entweder sowieso Binrdaten ausgegeben werden sollen oder wenn sichergestellt ist, dass
Kapitel 50
Performance-Tuning
keine UNICODE-Zeichen verwendet werden, die durch das simple Abschneiden der oberen 8 Bit falsch ausgegeben wrden. Da der UNICODE-Zeichensatz in den ersten 256 Zeichen zum ISO-8859-1-Zeichensatz kompatibel ist, sollten sich fr die meisten europischen und angelschsischen Sprachen keine Probleme ergeben, wenn zur Ausgabe von Zeichen die OutputStream-Klassen verwendet werden. Listing 50.7, Seite 1264 zeigt das Erzeugen einer etwa 300 Kbyte großen Datei, bei der zunchst die Writer- und dann die OutputStream-Klassen verwendet wurden. Im Test lag die Ausfhrungsgeschwindigkeit der zweiten Variante um etwa eine Zehnerpotenz ber der ersten. Listing 50.7: Performance von Writer und OutputStream
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028
public static void createfile1() throws IOException { Writer writer = new FileWriter(FILENAME); for (int i = 0; i < LINES; ++i) { for (int j = 0; j < 60; ++j) { writer.write('x'); } writer.write(NL); } writer.close(); } public static void createfile4() throws IOException { OutputStream os = new BufferedOutputStream( new FileOutputStream(FILENAME) ); for (int i = 0; i < LINES; ++i) { for (int j = 0; j < 60; ++j) { os.write('x'); } os.write('\r'); os.write('\n'); } os.close(); }
Lesen von Streams Die Performance des sequentiellen Lesens von Zeichen- oder Byte-Streams zeigt ein hnliches Verhalten wie die des sequentiellen Schreibens. Am langsamsten war der ungepufferte Zugriff mit der Klasse FileReader. Die grçßten Geschwindigkeitsgewinne ergaben sich durch das Kapseln des FileReader in einen BufferedReader, die Performance lag um etwa eine Zehnerpotenz hçher als im ungepufferten Fall. Der Umstieg auf das byte-orientierte Einlesen mit den Klassen FileInputStream und BufferedInputStream
1264
Tuning-Tipps
Kapitel 50
brachte dagegen nur noch geringe Vorteile. Mçglicherweise muss der zur Eingabekonvertierung in den Reader-Klassen verwendete ByteToCharConverter weniger Aufwand treiben, als ausgabeseitig nçtig war.
RandomAccess-Dateien Der wahlfreie Zugriff auf eine Datei zum Lesen oder Schreiben erfolgt in Java mit der Klasse RandomAccessFile. Da sie nicht Bestandteil der Reader- Writer-, InputStream- oder OutputStream-Hierarchien ist, besteht auch nicht die Mçglichkeit, sie zum Zweck der Pufferung zu schachteln. Tatschlich ist der ungepufferte byteweise Zugriff auf ein RandomAccessFile sehr langsam, er liegt etwa in der Grçßenordnung des ungepufferten Zugriffs auf Character-Streams. Wesentlich schneller kann mit Hilfe der read- und writeMethoden gearbeitet werden, wenn nicht nur ein einzelnes, sondern ein ganzes Array von Bytes verarbeitet wird. Je nach Puffergrçße und Verarbeitungsaufwand werden dann Geschwindigkeiten wie bei gepufferten Bytestreams oder hçher erzielt. Das folgende Beispiel zeigt, wie man mit einem 100 Byte großen Puffer eine Random-Access-Datei bereits sehr schnell lesen kann. 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016
public static void randomtest2() throws IOException { RandomAccessFile file = new RandomAccessFile(FILENAME, "rw"); int cnt = 0; byte[] buf = new byte[100]; while (true) { int num = file.read(buf); if (num <= 0) { break; } cnt += num; } System.out.println(cnt + " Bytes read"); file.close(); }
Listing 50.8: Gepufferter Zugriff auf RandomAccess-Dateien
1265
Teil IX
Das Programm liest die komplette Datei in Stcken von jeweils 100 Byte ein. Der Rckgabewert von read gibt die tatschliche Zahl gelesener Bytes an. Sie entspricht normalerweise der Puffergrçße, liegt aber beim letzten Datenpaket darunter, wenn die Dateigrçße nicht zufllig ein Vielfaches der Puffergrçße ist. Die Performance von randomtest2 ist sehr gut, sie lag auf dem Testrechner (Pentium II, 266 MHz, 128 MB, UW-SCSI) bei etwa 5 Mbyte pro Sekunde, was fr ein Java-Programm sicherlich ein respektabler Wert ist. Ein wesentlicher Grund ist darin zu suchen, dass durch den programmeigenen Puffer ein Großteil der Methodenaufrufe zum Lesen einzelner Bytes vermieden werden (in diesem Fall sind es um den Faktor 100 weniger). Auf die gleiche Weise lassen sich auch die streamorientierten Dateizugriffe beschleunigen, wenn die Anwendung nicht unbedingt darauf angewiesen ist, zeichenweise zu lesen bzw. zu schreiben.
Kapitel 50
Performance-Tuning
50.2.5 Speicheroptimierung Neben den direkten Prozessoraktivitten hat auch die Art und Weise, in der das Programm mit dem Hauptspeicher umgeht, einen erheblichen Einfluss auf dessen Performance. Einige der Aspekte, die dabei eine Rolle spielen, sind: " Jede Allozierung von Speicher kostet Rechenzeit. Der Speicher muss entweder vom Betriebssystem oder vom Laufzeitsystem der VM beschafft werden. Auch das (automatische) Initialisieren des Speichers kostet Zeit. Das Anlegen eines Arrays mit 1000 Elementen dauert wesentlich lnger als das eines mit 10 Elementen. " Objekte mit aufwndigen Konstruktoren bençtigen mçglicherweise viel Zeit zur Initialisierung. Bei ihnen kann es sinnvoll sein, sie zu »recyceln«. Dazu werden sie nach Gebrauch in einer geeigneten Datenstruktur gesammelt und kçnnen dem nchsten Interessenten (alternativ zur Erzeugung eines neuen Objekts) zur Verfgung gestellt werden. Vor der Verwendung muss dieser das Objekt natrlich geeignet initialisieren. " Nicht mehr referenzierter Speicher belastet den Garbage Collector und erfordert CPU-Zeit, um dem Programm wieder zugefhrt werden zu kçnnen. " In ungnstigen Fllen kann es sein, dass die VM den bençtigten Speicher schrittweise in relativ kleinen Stcken beim Betriebssystem anfordert. Das kostet unter Umstnden sehr viel Zeit. In diesem Fall kann es sinnvoll sein, mit Hilfe des Schalters -Xms den beim Start der VM anzufordernden Speicher auf einen hçheren Wert einzustellen. " Große Mengen an temporren, kurzlebigen Objekten belasten die VM ebenfalls. Derartige Allokationsszenarien entstehen beispielsweise beim Modifizieren von Strings oder wenn primitive Typen mit Hilfe ihrer Wrapper-Klassen in Collections gespeichert werden sollen. In Abschnitt 50.3, Seite 1267 zeigen wir ein harmlos aussehendes Programm, das beim Anlegen von 10 Kbyte Nutzdaten 75 Mbyte Datenmll erzeugt. " Werden Referenzen auf Objekte nicht gelçscht, bleibt der zugeordnete Speicher belegt und der Garbage Collector kann ihn nicht wieder freigeben. Das belastet nicht nur die VM, die zunehmend neuen Speicher beim Betriebssystem anfordern muss, sondern fhrt frher oder spter zum Absturz des Programms mit einem OutOfMemoryError. " Derartige Speicherlecks entstehen, wenn eigentlich nicht mehr bençtigte Objekte an »lebenden« Referenzen hngen (also an Variablen, die im Programm noch bençtigt werden). Lebende Referenzen sind die lokalen Variablen auf den Stacks aller laufenden Threads plus alle statischen Variablen des Programms. Zudem natrlich alle Variablen, die indirekt daran hngen. Als Programmierer sollte man diesbezglich den statischen Variablen (insbesondere wenn sie auf Collections verweisen) besonderes Augenmerk schenken. " Um dem Garbage Collector die Arbeit zu erleichtern, kann es sinnvoll sein, ihn in Programmpausen von Zeit zu Zeit durch Aufruf der Methode gc der Klasse System explizit aufzurufen. Das Programm kann ihm auch dadurch helfen, dass nicht mehr bençtigten Objektvariablen explizit der Wert null zugewiesen wird.
1266
Einsatz eines Profilers
Kapitel 50
50.3 Einsatz eines Profilers 50.3.1 Grundlagen Die bisher vorgestellten Tipps und Tricks sind sicherlich eine Hilfe, um bereits whrend der Entwicklung eines Programms grundstzliche Performanceprobleme zu vermeiden. Luft das fertige Programm dann trotzdem nicht mit der gewnschten Geschwindigkeit (was in der Praxis hufig vorkommt), helfen pauschale Hinweise leider nicht weiter. Stattdessen gilt es herauszufinden, welche Teile des Programms fr dessen schlechte Performance verantwortlich sind. Bei grçßeren Programmen, die aus vielen tausend Zeilen Quellcode bestehen, ist das eine komplizierte Aufgabe, die nur mit Hilfe eines guten Profilers bewltigt werden kann. Der Profiler ist ein Werkzeug, mit dessen Hilfe im laufenden Programm Performanceparameter, wie beispielsweise die verbrauchte CPU-Zeit, die Anzahl der allozierten Objekte oder die Anzahl der Aufrufe bestimmter Methoden, berwacht und gemessen werden kçnnen. Durch manuelle Inspektion der erzeugten Logdateien oder mit Hilfe eines Auswertungsprogramms kann dann festgestellt werden, welche Teile des Programms die grçßte Last erzeugen und daher verbesserungsbedrftig sind. JDK 1.1–6.0 Das Standard-JDK enthlt bereits seit der Version 1.0 einen eingebauten Profiler, der Informationen ber Laufzeit und Aufrufhufigkeit von Methoden geben kann. Im JDK 1.2 wurde er erweitert und kann seither den Speicherverbrauch messen und Profiling-Informationen threadweise ausgeben. Mit dem JDK 1.3 wurde er erneut verbessert und mit einem offenen Profiler-API versehen (JVMPI, Java Virtual Machine Profiler Interface). Mit dessen Hilfe ist es mçglich, eigene Profiling-Werkzeuge zu schreiben. Fester Bestandteil des JDK ist eine Beispielimplementierung hprof, die fr einfache Profiling-Aufgaben verwendet werden kann.
» » »
Im Vergleich zu spezialisierten Produkten sind die Fhigkeiten des eingebauten Profilers etwas rudimentr. Insbesondere die vom Profiler erzeugte Ausgabedatei erfordert einigen Nachbearbeitungsaufwand. Zudem gibt es keine grafischen Auswertungen wie bei kommerziellen Profilern. Dennoch ist der JDK-Profiler ein brauchbares und hilfreiches Instrument, mit dem Performanceprobleme und Speicherengpsse analysiert werden kçnnen. Wir wollen uns in diesem Abschnitt mit den Grundlagen seiner Bedienung vertraut machen.
1267
Teil IX
Als Beispiel fr die Anwendung des Profiler wollen wir ein Programm verwenden, dessen simple Aufgabe darin besteht, einen String mit 10000 Punkten zu erzeugen und auf dem Bildschirm auszugeben. Statt die Ratschlge aus dem vorigen Abschnitt zu beherzigen, verwendet das Programm den Operator +=, um den String zeichenweise in
Kapitel 50
Performance-Tuning
einer Schleife zusammenzusetzen. Auf langsameren Rechnern kann es durchaus einige Sekunden dauern, bis der String erzeugt und vollstndig auf dem Bildschirm ausgegeben wurde: Listing 50.9: Ein Beispielprogramm zum Testen des Profilers
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021
/* ProfTest1A.java */ import java.util.*; public class ProfTest1A { public static String dots(int len) { String ret = ""; for (int i = 0; i < len; ++i) { ret += "."; } return ret; } public static void main(String[] args) { String s = dots(10000); System.out.println(s); } }
Nachfolgend wollen wir uns eine Beispielsitzung mit dem Profiler ansehen. hnlich wie bei einem Debugger besteht die typische Vorgehensweise darin, schrittweise Informationen ber Rechenzeit- und Speicherverbrauch zu gewinnen und das Programm mit diesen Informationen nach und nach zu optimieren. Fr gewçhnlich gibt es dabei kein Patentrezept, das direkt zum Erfolg fhrt. Stattdessen hnelt der Umgang mit dem Profiler einer Detektivarbeit, bei der die einzelnen Teile der Lçsung nach und nach gefunden werden.
50.3.2 Eine Beispielsitzung mit dem Profiler Erzeugen der Profiling-Informationen Zunchst muss das Programm wie gewçhnlich bersetzt werden: javac ProfTest1A.java Um das Programm unter Kontrolle des Profilers zu starten, ist die Option -Xrunhprof zu verwenden und nach einem Doppelpunkt mit den erforderlichen Parametrisierungen zu versehen. Die Parameter werden als kommaseparierte Liste von Argumenten der Form »Name=Wert« angegeben. Die wichtigsten Parameter von hprof sind:
1268
Einsatz eines Profilers
Name
Mçgliche Werte
cpu
samples, times, old
heap
dump, sites, all
file
Name der Ausgabedatei
depth
Maximale Tiefe der Stacktraces
Kapitel 50
Tabelle 50.2: Parameter von hprof
Mit der Option cpu wird der CPU-Profiler aktiviert. Er kennt die Modi »samples«, »times« und »old«. Im Modus »samples« werden die Profiling-Informationen dadurch gewonnen, dass das laufende Programm mit Hilfe eines separaten Threads regelmßig unterbrochen wird. Bei jeder Unterbrechung wird ein Stacktrace gezogen, der dem Profiler Auskunft darber gibt, welche Methode gerade ausgefhrt wird, in welcher Quelltextzeile das Programm steht und wie die Kette ihrer Aufrufer aussieht. Jeder derartige Schnappschuss wird als Sample bezeichnet. Die unterschiedlichen Stacktraces werden mit einem Aufrufzhler versehen, der immer dann um 1 erhçht wird, wenn bei einer Unterbrechung ein entsprechender Stacktrace gefunden wird. Aus dem Endwert der Zhler kann dann abgeleitet werden, wo das Programm die meiste Rechenzeit verbraucht hat. Denn je hçher der Zhler war, desto çfter wurde das Programm an der zugehçrigen Programmstelle »angetroffen« und desto wahrscheinlicher ist es, dass dort nennenswert Rechenzeit verbraucht wird. ACHTUNG
!
!
!
Natrlich ist diese Vorgehensweise nicht sehr przise und es sind Flle denkbar, bei denen sie ganz versagt. Aber sie ist einfach zu implementieren und beeintrchtigt die Laufzeit des Programms nur unwesentlich. In der Praxis sollten die Ergebnisse mit der nçtigen Vorsicht betrachtet werden. Sie drfen nicht als absolute Messwerte angesehen werden, sondern sind vorwiegend dazu geeignet, Tendenzen zu erkennen und Programmteile mit besonders hoher Rechenzeit ausfindig zu machen.
Der zweite Modus »times« arbeitet etwas anders. Statt lediglich die Anzahl der Stacktraces zu zhlen, misst er tatschlich die innerhalb der einzelnen Methoden verbrauchte Rechenzeit. Allerdings wird dadurch auch die Laufzeit des Programms strker erhçht als im Modus »samples«. In der Praxis kann eine gemischte Vorgehensweise sinnvoll sein, bei der zunchst per »samples« die grçßten Performancefresser eliminiert werden und dann per »times« das Feintuning vorgenommen wird. Die Option »old« erstellt die Ausgabedatei in einem Format, wie sie von den Profilern der Pr-1.2-Versionen verwendet wurde. Wir wollen hier nicht weiter darauf eingehen.
1269
Teil IX
Bei der Verwendung des CPU-Profilers sind weiterhin die Optionen file und depth von Bedeutung. Mit file kann der Name der Ausgabedatei angegeben werden, er ist standardmßig java.hprof.txt. Mit depth wird festgelegt, mit welcher maximalen Tiefe die Stacktraces aufgezeichnet werden (standardmßig 4). Ist die Aufrufkette einer Methode
Kapitel 50
Performance-Tuning
lnger als der angegebene Wert, wird der Stacktrace abgeschnitten. Bei der Analyse ist nicht mehr bis ins letzte Detail erkennbar, von welcher Stelle aus der Aufruf erfolgte. Wird depth auf 1 gesetzt, sind nur noch die Aufrufstellen sichtbar, die Aufrufer selbst bleiben unsichtbar. Wir wollen einen ersten Lauf mit dem CPU-Profiler im Modus »samples« und mit einer maximalen Stacktiefe von 10 machen und rufen das Programm daher wie folgt auf: java -Xint -Xrunhprof:cpu=samples,depth=10 ProfTest1A
i
i
i
INFO Die Option -Xint geben wir an, um das Programm im Interpreter-Modus laufen zu lassen und mçgliche Verflschungen durch den Hotspot-Compiler zu vermeiden.
Das CPU-Profile Das Programm erzeugt nun die Ausgabedatei java.hprof.txt mit den Profiling-Informationen. Sie besteht aus drei Teilen: " Im oberen Teil werden allgemeine Informationen zur Struktur der Datei und den darin verwendeten Eintrgen gegeben. " Im mittleren Teil befinden sich die Stacktraces. " Im unteren Teil werden die Sampling-Ergebnisse ausgegeben. Die Analyse beginnt im unteren Teil. Er sieht bei unserer Beispielsitzung so aus (die Samples ab Position 11 wurden aus Grnden der bersichtlichkeit entfernt): CPU SAMPLES rank self 1 53.66% 2 17.48% 3 17.07% 4 1.63% 5 1.22% 6 0.81% 7 0.81% 8 0.81% 9 0.41% 10 0.41% ... CPU SAMPLES
BEGIN (total = 246) Sun Jun 18 17:56:28 2000 accum count trace method 53.66% 132 9 java.lang.StringBuilder.expandCapacity 71.14% 43 13 java.lang.System.arraycopy 88.21% 42 11 java.lang.System.arraycopy 89.84% 4 10 java.lang.StringBuilder.toString 91.06% 3 17 java.lang.StringBuilder.append 91.87% 2 19 java.lang.StringBuilder.append 92.68% 2 24 sun.io.CharToByteSingleByte.convert 93.50% 2 12 java.lang.StringBuilder.
Die Ausgabe ist nach Aufrufhufigkeit geordnet. Von den insgesamt 246 Samples, die whrend des Programmlaufs gezogen wurden, waren 132 in der Methode expandCapacity
1270
Einsatz eines Profilers
Kapitel 50
der Klasse StringBuilder und 43 und noch einmal 42 in der Methode arraycopy der Klasse System. Damit fielen insgesamt 88,21 Prozent aller Samples in diese Methoden. Da beide Methoden nicht selbst geschrieben sind und sich damit unseren Optimierungsversuchen entziehen, kann eine Performanceverbesserung lediglich dadurch erreicht werden, dass die Anzahl ihrer Aufrufe vermindert wird. Um die Aufrufer herauszufinden, mssen wir uns die in der fnften Spalten angegebenen Stacktraces ansehen. Der Stacktrace zu expandCapacity hat die Nummer 9 und sieht so aus: TRACE 9: java.lang.StringBuilder.expandCapacity(StringBuilder.java:202) java.lang.StringBuilder.append(StringBuilder.java:401) ProfTest1A.dots(ProfTest1A.java:11) ProfTest1A.main(ProfTest1A.java:18) Er besagt, dass der Sample in Zeile 202 der Methode expandCapacity der Klasse StringBuilder erzeugt wurde. Diese wurde von append aufgerufen, das von unserer eigenen Methode dots in Zeile 11 aufgerufen wurde. In Zeile 11 steht zwar kein Aufruf von append, dort befindet sich aber der +=-Operator zur Verkettung der Strings. Dieser wird vom Compiler in entsprechende Methoden- und Konstruktorenaufrufe der Klassen String und StringBuilder bersetzt. Als erste Erkenntnis stellen wir also fest, dass offensichtlich der +=-Operator zur StringVerkettung interne StringBuilder-Objekte erzeugt, die einen erheblichen Teil der CPUZeit bençtigen, um whrend des Anfgens von Zeichen vergrçßert zu werden. Die Stacktraces 11 und 13 der nchsten beiden Kandidaten verstrken den Eindruck, dass der +=-Operator in unserem Programm CPU-intensiven Code erzeugt: TRACE 11: java.lang.System.arraycopy(System.java:Native method) java.lang.String.getChars(String.java:553) java.lang.StringBuilder.append(StringBuilder.java:402) ProfTest1A.dots(ProfTest1A.java:11) ProfTest1A.main(ProfTest1A.java:18) TRACE 13: java.lang.System.arraycopy(System.java:Native method) java.lang.StringBuilder.expandCapacity(StringBuilder.java:203) java.lang.StringBuilder.append(StringBuilder.java:401) ProfTest1A.dots(ProfTest1A.java:11) ProfTest1A.main(ProfTest1A.java:18)
1271
Teil IX
Beide Arten von Samples gehen letztlich auf Zeile 11 unseres Programms zurck und zeigen Rechenzeitverbruche, die durch die vom +=-Operator ausgelçste Verarbeitung temporrer Strings und StringBuilder verursacht werden. Obwohl die Samples in beiden Fllen in arraycopy gezogen wurden, gibt es zwei unterschiedliche Stacktraces, weil die
Kapitel 50
Performance-Tuning
Aufruferkette in beiden Fllen unterschiedlich ist. Einerseits wird arraycopy aus getChars aufgerufen (da Strings immutable sind, muss getChars bei jedem Aufruf eine Kopie des Zeichenarrays erstellen), andererseits wird arraycopy in expandCapacity bençtigt, um das bei einer Verlngerung des StringBuilders erforderliche Umkopieren der Zeichen zu erledigen. Unsere erste Vermutung hat sich also besttigt: Der harmlos aussehende Aufruf des +=-Operators in Zeile 11 unseres Programms erzeugt temporre String- und StringBuilder-Objekte, wobei ein Großteil der Rechenzeit durch das Anhngen und Kopieren von Zeichen und das Erhçhen der Kapazitt verbraucht wird.
Das Heap-Profile Einen noch deutlicheren Eindruck vermittelt ein Heap-Profile. Wir erstellen es, indem wir das Programm mit der Option heap=sites erneut unter Profiler-Kontrolle laufen lassen: java -Xint -Xrunhprof:heap=sites,depth=10 ProfTest1A Die Ausgabe besteht wie beim CPU-Profiling aus drei Teilen. Die ersten beiden entsprechen dem CPU-Profiler, der dritte enthlt Informationen zur dynamischen HeapBelegung: SITES BEGIN (ordered by live bytes) Sun Jun 18 18:37:28 2000 percent live alloc'ed stack class rank self accum bytes objs bytes objs trace name 1 48.27% 48.27% 189974 25 75074238 19950 471 [C 2 38.00% 86.27% 149524 157 149524 157 1 [I 3 4.91% 91.17% 19304 741 19364 747 1 [C 4 2.44% 93.61% 9588 153 9588 153 1 [B 5 2.29% 95.90% 9010 1550 9022 1552 1
1272
Einsatz eines Profilers
Kapitel 50
Am aufflligsten ist die oberste Zeile und die darin ersichtliche Diskrepanz zwischen aktiven und allozierten Objekten. Dort steht, dass unser Programm 19950 Zeichen-Arrays mit insgesamt 75 Mbyte Speicher alloziert hat, davon aber nur noch 25 Objekte mit kaum 200 Kbyte Speicher aktiv sind. Hier wurden also in erheblichen Umfang kurzlebige Objekte erzeugt und anschließend wieder fallengelassen. Stacktrace 471 sieht so aus: TRACE 471: java.lang.StringBuilder.expandCapacity(StringBuilder.java:202) java.lang.StringBuilder.append(StringBuilder.java:401) ProfTest1A.dots(ProfTest1A.java:11) ProfTest1A.main(ProfTest1A.java:18) Wieder liegt der Verursacher in Zeile 11 unseres Programms und wir sehen, dass der +=-Operator nicht nur viel Rechenzeit verbraucht, sondern zudem eine große Anzahl temporrer Objekte erzeugt und damit das Laufzeitsystem und den Garbage Collector belastet.
Die optimierte Version des Programms Da wir auf die Interna der Klassen String und StringBuilder keinen Einfluss haben, kann die Optimierung nur darin bestehen, die Verwendung des +=-Operators einzuschrnken oder eine besser geeignete Alternative zu whlen. Diese ist natrlich schon aus Abschnitt 50.2.1, Seite 1255 bekannt und besteht darin, direkt mit StringBuilder-Objekten zu arbeiten. Die verbesserte Version unseres Programms sieht dann so aus: /* ProfTest1B.java */ import java.util.*; public class ProfTest1B { public static String dots(int len) { StringBuilder sb = new StringBuilder(len + 10); for (int i = 0; i < len; ++i) { sb.append('.'); } return sb.toString(); }
Listing 50.10: Das verbesserte Programm nach der Profiler-Sitzung
public static void main(String[] args) { String s = dots(10000); System.out.println(s); } }
1273
Teil IX
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021
Kapitel 50
Performance-Tuning
Wird nun ein CPU-Profiling durchgefhrt, ergibt sich ein gnzlich anderes Bild: CPU SAMPLES BEGIN (total = 15) Sun Jun 18 19:03:56 2000 rank self accum count trace method 1 26.67% 26.67% 4 9 sun.io.CharToByteSingleByte.convert 2 6.67% 33.33% 1 2 java.io.InputStreamReader.
» » »
1274
JDK 1.1–6.0 In frheren JDKs wurde der Profiler nicht mit der Option -Xrunhprof, sondern mit -Xprof bzw. mit -prof aufgerufen. Zudem durfte nicht der normale Interpreter verwendet werden, sondern mit java_g musste dessen Debug-Version aufgerufen werden. Auch das Deaktivieren des Just-In-Time-Compilers nderte sich im Laufe der Versionen. Whrend es seit dem JDK 1.3 mit dem Schalter -Xint erledigt wird, musste zuvor die Umgebungsvariable JAVA_COMPILER auf den Wert NONE gesetzt werden. Soll der Profiler bei einem Applet verwendet werden, kann die Aufrufoption mit dem Schalter -J an den Appletviewer bergeben werden.
Einsatz eines Profilers
Kapitel 50
50.3.3 Ausblick Egal, ob mit dem eingebauten Profiler das Laufzeitverhalten oder der Speicherverbrauch der Anwendung untersucht werden soll, die prinzipielle Vorgehensweise ist stets gleich: " Zunchst wird das Programm mit der Option -Xrunhprof gestartet und eine Datei mit Profiling-Informationen erstellt. " Die grçßten Rechenzeit- und Speicherverbraucher werden ermittelt und ber ihre Stacktraces wird bestimmt, woher sie aufgerufen werden und in welcher Weise sie zum Programmergebnis beitragen. " Stehen gengend Erkenntnisse zur Verfgung, kann das Programm verbessert und ein erneuter Profilerlauf durchgefhrt werden. " Sind die Ergebnisse zufriedenstellend, kann der Profiler deaktiviert werden, andernfalls beginnt das Spiel von vorne. Ist der Anteil von lokalem Code am Rechenzeitverbrauch hoch, kann versucht werden, diesen zu verringern. Typische Ansatzpunkte dafr sind das Vermindern der Anzahl von Schleifendurchlufen (durch bessere Algorithmen), die Verwendung von Ganz- statt Fließkommazahlen, das Herausziehen von schleifeninvariantem Code, das Vermeiden der Doppelauswertung von gemeinsamen Teilausdrcken, das Wiederverwenden bekannter Teilergebnisse, die Verwendung alternativer Datenstrukturen, das Eliminieren von unbenutztem Code oder das Reduzieren der Strke von Ausdrcken, indem sie durch algebraisch gleichwertige, aber schnellere Ausdrcke ersetzt werden. Wird ein großer Anteil der Rechenzeit dagegen in Aufrufen von Untermethoden verbraucht, kann versucht werden, deren Aufrufhufigkeit zu vermindern, sie durch performantere Aufrufe zu ersetzen, oder – im Falle eigener Methoden – ihre Ablaufgeschwindigkeit zu erhçhen. Der zielgerichtete Einsatz dieser Techniken erfordert gute Werkzeuge, namentlich einen guten Profiler. Bei kleineren Problemen mag es ausreichend sein, die Ablaufgeschwindigkeit mit Ausgabeanweisungen und System.currentTimeMillis zu ermitteln, und auch der JDK-Profiler kann mit Erfolg eingesetzt werden. Daneben gibt es einige kommerzielle und experimentelle Produkte mit wesentlich erweiterten Fhigkeiten. Beispiele fr solche Profiler sind JProbe (http://www.quest.com/jprobe/), der auch fr Teile der Software zu diesem Buch verwendet wurde, oder JInsight (http://www.alphaWorks.ibm.com). Zu ihren Fhigkeiten zhlen beispielsweise: " Die grafische Darstellung der Aufrufhierarchie mit Laufzeitinformationen zu Methoden und Aufrufen " Das Ermitteln von Profiling-Informationen bis auf die Ebene einzelner Quelltextzeilen hinab
1275
Teil IX
" Das Erstellen dynamischer Profile, um die Vernderung wichtiger Parameter bereits whrend des laufenden Programms beobachten zu kçnnen
Kapitel 50
Performance-Tuning
" Die Rckverfolgung von alloziertem Speicher sowohl zu den Programmstellen, die den Speicher belegt haben, als auch zu den Variablen, in denen die zugehçrigen Objekte gehalten werden " Das Vergleichen von Profiling-Lufen, um die Auswirkungen von Optimierungsversuchen studieren zu kçnnen " Die Ausgabe von Reports und HTML-Dateien zu Vergleichs- und Dokumentationszwecken
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Allgemeine Bemerkungen zur Geschwindigkeit von Java-Programmen " Interpretierter Code, kompilierter Code und Just-In-Time-Compiler " Tuning von String-Zugriffen und Anwendung der Klasse StringBuilder " Die Performance von Methodenaufrufen " Hinweise zur Verwendung von Vektoren und Listen " Tuning von Dateizugriffen " Aspekte der Speicherzuordnung in Java " Anwendung des Profilers und Auswerten der Profiling-Informationen
1276
51
Hilfsprogramme des JDK
51.1
javac – der Compiler
In diesem Kapitel wollen wir die wichtigsten Hilfsprogramme des Java Development Kit bzw. Java Runtime Environment vorstellen. Die meisten Programme arbeiten kommandozeilenorientiert und werden aus einer DOS-Box oder einer Shell heraus aufgerufen. Einige von ihnen sind interaktiv und haben eine einfache grafische Oberflche. Wir wollen die Aufrufsyntax und wichtigsten Optionen der folgenden Programme vorstellen: " javac – der Compiler " java – der Interpreter " appletviewer – der Applet-Interpreter " jdb – der Debugger " javadoc – der Dokumentationsgenerator " jar – das Archivierungswerkzeug " javap – der Disassembler " serialver – Zugriff auf die serialVersionUID " keytool – Verwaltung von kryptografischen Schlsseln " policytool – Bearbeiten von Policy-Dateien " jarsigner – Signieren von Archiven " rmic – Erzeugen von RMI-Stubs und -Skeletons
Teil IX
" rmiregistry – RMI-Namensservice
Kapitel 51
Hilfsprogramme des JDK
51.1.1
Aufruf
javac [ options ] [@filelist | { filename.java }]
51.1.2
Beschreibung
Der Compiler javac bersetzt Sourcecode in Bytecode. Zu jeder Klasse, die innerhalb einer .java-Datei definiert wurde, wird eine eigene .class-Datei erzeugt. Der Compiler wacht automatisch ber die Abhngigkeiten zwischen den Quelldateien. Wird beispielsweise in einer Klasse X in der Datei X.java eine Klasse Y, die in Y.java liegt, verwendet, so wird Y.java automatisch mit bersetzt, wenn es erforderlich ist. Anstelle der Liste von Dateinamen kann nach einem @ auch eine Textdatei angegeben werden, in der die zu bersetzenden Dateien durch Whitespaces getrennt angegeben werden.
51.1.3 Tabelle 51.1: Optionen von javac
Optionen
Option
Bedeutung
-version
Ausgabe der Versionsnummer (seit der Version 5.0 verfgbar)
-classpath path
Gibt die Liste der Pfade zur Suche von Klassendateien an. Dieser Schalter bersteuert den Wert einer eventuell gesetzten Umgebungsvariable CLASSPATH. Bezglich der Auswirkungen des Klassenpfads in den unterschiedlichen JDK-Versionen lesen Sie bitte Abschnitt 13.2.2, Seite 305.
-g
Aktiviert die Erzeugung von Debug-Informationen. Dieser Schalter sollte aktiviert werden, bevor ein Programm debuggt wird.
-nowarn
Deaktiviert die Ausgabe von Warnungen.
-O
Schaltet den Code-Optimierer an. Dessen Fhigkeiten waren allerdings nie besonders ausgeprgt und beschrnkten sich bis zum JDK 1.2 vorwiegend auf das Expandieren von Methodenaufrufen. In der Dokumentation zum JDK 1.3 steht sogar die Anmerkung Note: the -O option does nothing in the current implementation of javac and oldjavac. Seit dem JDK 1.4 ist der Schalter gar nicht mehr dokumentiert.
-verbose
Aktiviert die Ausgabe von Meldungen ber geladene Quell- und Klassendateien whrend der bersetzung.
-depend
Normalerweise wird eine Quelldatei neu kompiliert, wenn das Datum der letzten nderung nach dem nderungsdatum der Klassendatei liegt oder wenn die Klassendatei ganz fehlt. Mit Hilfe dieses Schalters wird diese Entscheidung auf der Basis von Headerinformationen in der Klassendatei auf eine zuverlssigere Weise getroffen. Der bersetzungsvorgang wird aber unter Umstnden langsamer. Dieser Schalter war bis zum JDK 1.1 vorhanden, wird aber mittlerweile nicht mehr untersttzt. Die neueren Compiler erkennen die Abhngigkeiten weitgehend automatisch.
1278
java – der Interpreter
Option
Bedeutung
-deprecation
Sorgt dafr, dass bei jedem Aufruf einer als deprecated markierten Methode (@deprecated-Marke im Dokumentationskommentar) zustzliche Informa-
Kapitel 51 Tabelle 51.1: Optionen von javac (Forts.)
tionen ber mçgliche Workarounds ausgegegeben werden. Alle Methoden aus lteren JDKs, die im aktuellen JDK nicht mehr verwendet werden sollen, werden mit diesem Flag markiert. -target version
Es wird Bytecode erstellt, der zu der angegebenen Version des Laufzeitsystems kompatibel ist.
-source version
Es wird Sourcecode akzeptiert, der zu der angegebenen Version kompatibel ist. Dieser Schalter ist ab JDK-Version 1.4 verfgbar, er wird in Abschnitt 6.4.1, Seite 144 erlutert. Auch fr die sprachlichen Neuerungen der J2SE 5.0 wird diese Option bençtigt (in der Form "-source 1.5"). Steht ab der J2SE 5.0 zur Verfgung und aktiviert eine Reihe von Warnungen,
-Xlint
die anzeigen, dass der Quelltext Konstrukte enthlt, die zwar legal, aber unter Umstnden problematisch sind. Als Beispiel wird in der Dokumentation eine Klasse genannt, die zwar das Interface Serializable implementiert, aber keine eigene serialVersionUID zur Verfgung stellt.
51.2
java – der Interpreter
51.2.1
Aufruf
java [ options ] classname [{ args }] javaw [ options ] classname [{ args }]
51.2.2 Beschreibung Der Interpreter java dient zur Ausfhrung kompilierter Java-Programme, die als Bytecode in .class-Dateien vorliegen. javaw erfllt denselben Zweck, erzeugt aber kein Terminalfenster beim Start des Programms und erlaubt nicht die Verwendung der Standard-Streams System.in, System.out und System.err. Beim Aufruf beider Programme wird der Name einer Klassendatei erwartet (ohne die Erweiterung .class). Damit sie ausgefhrt werden kann, muss sie eine Klassenmethode main mit folgender Signatur enthalten: public static void main(String[] args)
1279
Teil IX
Alle Argumente, die nach dem Namen der Klassendatei an java bergeben werden, stehen nach dem Aufruf von main in args zur Verfgung. Der Java-Interpreter wird nach
Kapitel 51
Hilfsprogramme des JDK
dem Rcksprung aus main beendet, wenn keine eigenen Threads erzeugt wurden. Falls weitere Threads erzeugt wurden, wird er verlassen, nachdem der letzte VordergrundThread beendet wurde. Da whrend der Ausfhrung eines Java-Programms meist weitere Klassendateien bençtigt werden, muss der Interpreter wissen, wo diese zu finden sind. Standardmßig sucht er dabei im systemspezifischen Installationsverzeichnis und im aktuellen Verzeichnis. Die Suchstrategie kann durch Setzen der Umgebungsvariable CLASSPATH oder mit Hilfe der Option -classpath verndert werden. Sollen nur die Standardbibliotheken des JDK verwendet werden, sind weder CLASSPATH noch -classpath erforderlich. Weitere Informationen zu CLASSPATH-Einstellungen finden Sie in Abschnitt 13.2.2, Seite 305.
» » »
JDK 1.1–6.0 In der Windows-Version des JDK 1.2 ist ein Just-In-Time-Compiler (kurz JIT) enthalten, der standardmßig aktiviert ist. Der JIT bersetzt zur Laufzeit des Programms hufig bençtigte Bytecodes in Maschinencode und beschleunigt so die weitere Ausfhrung des Programms. Soll der JIT deaktiviert werden, kann die Umgebungsvariable JAVA_COMPILER oder die Systemeigenschaft java.compiler auf den Wert NONE gesetzt werden. Seit dem JDK 1.3 ist der adaptive Just-In-Time-Compiler HotSpot fester Bestandteil der Auslieferung. Er kann mit der Option -Xint aus- und mit -Xmixed angeschaltet werden. Standardmßig ist er aktiviert. Soll im JDK 1.3 anstelle von HotSpot der JIT des JDK 1.2 verwendet werden, kann dieser mit der Option -Xclassic aktiviert werden. Seit der Version 1.3.1 ist zustzlich der bis dahin nur separat erhltliche Server-Hotspot im JDK enthalten. Er fhrt weitergehende (und kostspieligere) Optimierungen aus als der Client-Hotspot und ist vorwiegend fr langlaufende Applikationen ohne direkte Benutzeroberflche gedacht. Er kann mit der Option -server aktiviert werden, whrend der Client-Hotspot auf -client reagiert.
51.2.3 Optionen Tabelle 51.2: Optionen des JavaInterpreters
Option
Bedeutung
-classpath path
Gibt die Liste der Pfade zur Suche von Klassendateien an. Alternativ kann auch die Abkrzung -cp verwendet werden.
-prof
Aktiviert in Pr-1.2-Versionen des JDK den Profiler im Interpreter, der Informationen ber das Laufzeitverhalten der Anwendung in die Datei java.prof schreibt. Ab dem JDK 1.2 wird der Profiler mit der Option -Xprof bzw. -Xrunhpof aktiviert. Genaue Informationen zur Verwendung des Profilers sind in Abschnitt 50.3, Seite 1267 zu finden.
1280
-version
Ausgabe der Versionsnummer
-help
Ausgabe eines kurzen Hilfetextes
appletviewer – der Appletviewer
Option
Bedeutung
-verbose
Gibt bei jedem Laden einer Klasse eine Meldung auf der Console aus. Seit dem JDK 1.3 kçnnen wahlweise die Schalter :class, :gc oder :jni angehngt
Kapitel 51 Tabelle 51.2: Optionen des JavaInterpreters (Forts.)
werden. :class entspricht dabei der Voreinstellung, :gc dokumentiert die Garbage-Collector-Aufrufe und :jni zeigt die Verwendung von Native Methods. -verbosegc
Veranlasst den Garbage Collector bei jedem Aufruf zur Ausgabe einer Nachricht.
-DpropName=value
Weist dem Property propName den Wert value zu.
-Xms n
Spezifiziert die Grçße des beim Start allozierten Speichers. n ist dabei eine Ganzzahl mit einer der Erweiterungen »k« oder »m«. Die Buchstaben stehen fr die Grçßenordnungen kilo und mega. Die Standardeinstellung ist versions- und betriebssystemabhngig, typische Werte sind 1m oder 2m. Spezifiziert die Grçße des maximal allozierbaren Speichers. n ist dabei eine
-Xmx n
Ganzzahl mit einer der Erweiterungen »k« oder »m«. Die Standardeinstellung ist versions- und betriebssystemabhngig, typische Werte sind 16m oder 64m. -enableassertions
Schaltet Assertions an (Abkrzung -ea). Dieser Schalter wird ausfhrlich in Abschnitt 6.4.1, Seite 144 erklrt.
-disableassertions
Schaltet Assertions aus (Abkrzung -da). Dieser Schalter wird ausfhrlich in Abschnitt 6.4.1, Seite 144 erklrt.
JDK 1.1–6.0 In den 1.1er Versionen des JDK gab es ein Programm jre, das dazu diente, den Interpreter des Laufzeitsystems zu starten (Java Runtime Environment). Dieses Programm ist in der aktuellen JDK-Version nicht mehr vorhanden, sondern wird durch das Programm java ersetzt. Auch der in frheren Versionen vorhandene debugging-fhige Interpreter java_g existiert seit dem JDK 1.2 nicht mehr.
51.3
appletviewer – der Appletviewer
51.3.1
Aufruf
» » »
appletviewer [ options ] { url }
51.3.2 Beschreibung
1281
Teil IX
appletviewer ist ein Hilfsprogramm zum Ausfhren von Applets. Er interpretiert dazu die als Argument bergebenen (und auf HTML-Dokumente zeigenden) URLs und çffnet
Kapitel 51
Hilfsprogramme des JDK
fr jedes darin gefundene APPLET-Tag ein Fenster, in dem das zugehçrige Applet gestartet wird. Alle brigen HTML-Befehle werden ignoriert. Details zur Struktur der HTMLDateien und zur Ausfhrung von Applets finden sich in Kapitel 39, Seite 923.
51.3.3 Optionen Tabelle 51.3: Optionen von appletviewer
Option
Bedeutung
-debug
Startet den Appletviewer unter Kontrolle des Debuggers und erlaubt so die Fehlersuche in Applets.
51.4
jdb – der Debugger
51.4.1 Aufruf jdb [ classfile ]
51.4.2 Beschreibung jdb ist der Debugger des JDK. Er bietet die Mçglichkeit, Programme kontrolliert ablaufen zu lassen und dabei Breakpoints zu setzen, im Einzelschrittmodus den nchsten Befehl ausfhren zu lassen oder den Inhalt von Variablen oder Objekten zu inspizieren. Man sollte allerdings nicht zu große Erwartungen an jdb stellen, denn das Programm ist ein Kommandozeilendebugger in schçnster UNIX-Tradition. Mit den grafischen Debuggern der integrierten Java-Entwicklungsumgebungen hat er nur wenig gemeinsam. Leider ist er nicht nur umstndlicher zu bedienen, sondern lsst (insbesondere in Pr-1.2-JDKs) auch einige wichtige Features moderner Debugger vermissen.
» » »
1282
JDK 1.1–6.0 Seit der Version 1.3 besitzt das JDK eine neue Debugging-Architektur. Sie wird als JPDA (Java Platform Debugger Architecture) bezeichnet und erlaubt es, Debugger komplett in Java zu schreiben. Zwar wird nach wie vor kein ausgefeilter GUI-Debugger mit dem JDK ausgeliefert. Doch befindet sich im Unterverzeichnis jpda des Demo-Verzeichnisses des JDK ein Beispielprogramm javadt, dass als Prototyp eines GUI-Debuggers angesehen werden kann. Hinweise zu seiner Verwendung finden sich in der JDK-Dokumentation. Auch integrierte Entwicklungsumgebungen verwenden diese Schnittstelle, um ihre eigenen Debugger einzubinden.
jdb – der Debugger
Kapitel 51
51.4.3 Vorbereitungen Damit ein Programm debuggt werden kann, sollte es mit der Option -g bersetzt werden. Dadurch werden symbolische Informationen in die Klassendatei geschrieben, die der Debugger zur Interpretation von lokalen Variablen bençtigt. Beim Aufruf des Debuggers kann die zu untersuchende Klassendatei als Argument angegeben werden: jdb classfile INFO
i
i
i
!
!
!
Damit jdb berhaupt startet, muss ein laufender TCP/IP-Stack vorhanden sein. Dies ist fr Anwender unangenehm, die nur eine Whlverbindung zu ihrem Provider haben, denn bei jedem Starten des Debuggers die Verbindung aufzubauen, ist nicht nur umstndlich, sondern auch kostspielig. Die bliche Empfehlung im Usenet lautet in diesem Fall, eine Datei hosts anzulegen und den folgenden Eintrag einzufgen:
127.0.0.1
localhost
Unter Windows 95 muss die Datei im Windows-Installationsverzeichnis (typischerweise c:\windows) angelegt werden, meist gibt es dort schon eine Kopiervorlage hosts.sam, die verwendet werden kann. In aktuellen JDKs kann auf das Anlegen der Datei unter Umstnden verzichtet werden. Falls der Debugger nicht starten will, kann es sinnvoll sein, zustzlich die DNS-Konfiguration zu deaktivieren. Dazu ist in der Systemsteuerung im Bereich »Netzwerk« das TCP/IP-Protokoll auszuwhlen und nach Klick auf »Eigenschaften« im Registerblatt »DNS-Konfiguration« der Button »DNS deaktivieren« anzuklicken. ACHTUNG Bei dieser Anpassung ist allerdings Vorsicht geboten, denn Vernderungen an den Netzwerkeinstellungen kçnnen die Netzwerkanbindung des Rechners unbrauchbar machen. Es empfiehlt sich in jedem Fall, vor der Vernderung der Parameter die alte Konfiguration zu notieren, um sie nçtigenfalls wieder restaurieren zu kçnnen. Vernderungen sollte sowieso nur derjenige vornehmen, der genau weiß, was er tut.
1283
Teil IX
Nachdem der Debugger gestartet wurde, meldet er sich mit seiner Kommandozeile und ist bereit, Befehle entgegenzunehmen. Die wichtigsten von ihnen werden in Tabelle 51.4, Seite 1284 vorgestellt und kurz erlutert.
Kapitel 51
Tabelle 51.4: Kommandos von jdb
Hilfsprogramme des JDK
Kommando
Bedeutung
?
Liefert eine bersicht aller Kommandos. Alternativ kann auch das Kommando help verwendet werden.
!!
Wiederholt das letzte Kommando.
load classname
Ldt eine Klassendatei in den Debugger. Falls jdb bereits mit einer Klassendatei als Argument aufgerufen wurde, muss dieses Kommando nicht mehr aufgerufen werden.
run
Startet das geladene Programm. Falls die Klassendatei mit load geladen wurde, mssen zustzlich der Klassenname und ggfs. weitere Parameter des Programms bergeben werden. Nach Ausfhrung dieses Programms luft das Programm bis zum nchsten Breakpoint oder bis es mit dem suspend-Kommando angehalten wird.
quit
Beendet den Debugger. Alternativ kann auch das Kommando exit verwendet werden.
stop in
Setzt einen Breakpoint auf den Anfang einer Methode. Das Kommando erwartet den Namen der Klasse, einen Punkt und den Namen der Methode als Argument. Beispiel: stop in JDBBeispiel.actionPerformed
stop at
Setzt einen Breakpoint auf eine vorgegebene Zeile. Dazu mssen der Name der Klasse, ein Doppelpunkt und die Zeilennummer innerhalb der Quelldatei angegeben werden. Beispiel: stop at JDBBeispiel:48
clear
Lçscht einen Breakpoint. Als Argument mssen der Klassenname, gefolgt von einem Doppelpunkt und der Zeilennummer, in der sich der Breakpoint befindet, angegeben werden. Es gibt keine Mçglichkeit, eine Liste der aktuellen Breakpoints anzeigen zu lassen.
list
Zeigt den aktuellen Ausschnitt des Quelltextes an, an dem das Programm angehalten wurde. Die als Nchstes auszufhrende Zeile wird durch einen Pfeil markiert. Alternativ kann auch der Name einer Methode oder eine Zeilennummer an das Kommando bergeben werden.
step
Nachdem ein Programm angehalten wurde, kann es mit diesem Kommando im Einzelschrittmodus fortgefhrt werden. Befindet sich an der Aufrufstelle ein Methodenaufruf, springt das Kommando in die Methode hinein und bleibt bei der ersten ausfhrbaren Anweisung stehen.
next
Wie step, springt dabei aber nicht in einen Methodenaufruf hinein, sondern fhrt die Methode als Ganzes aus und bleibt beim nchsten Kommando nach dem Methodenaufruf stehen. Dieses Kommando steht erst ab dem JDK 1.2 zur Verfgung.
step up
Fhrt die aktuelle Methode bis zum Ende aus.
cont
Fhrt das Programm nach einem Breakpoint fort. Es luft dann bis zum nchsten Breakpoint oder bis es mit dem suspend-Kommando angehalten wird.
1284
javadoc – der Dokumentationsgenerator
Kommando
Bedeutung
print
Zeigt den Inhalt der Variablen an, die als Argument bergeben wurde. print verwendet dazu die Methode toString, die in allen Objektvariablen implemen-
Kapitel 51 Tabelle 51.4: Kommandos von jdb (Forts.)
tiert ist. Damit eine Variable angezeigt werden kann, muss sie an der Aufrufstelle sichtbar sein. Es gibt leider keine Mçglichkeit, den Inhalt einer Variablen aus dem Debugger heraus zu verndern. dump
Zeigt den Inhalt der Objektvariable, die als Argument bergeben wurde, inklusive aller Membervariablen an. Damit eine Variable angezeigt werden kann, muss sie an der Aufrufstelle sichtbar sein.
locals
Gibt eine Liste aller lokalen Variablen und ihrer aktuellen Inhalte aus.
where
Zeigt einen Stacktrace an.
51.5
javadoc – der Dokumentationsgenerator
51.5.1
Aufruf
javadoc [ options ] { package | sourcefile }
51.5.2 Beschreibung javadoc ist ein Programm, das aus Java-Quelltexten Dokumentationen im HTML-Format erstellt. Dazu verwendet es die çffentlichen Klassen-, Interface- und Methodendeklarationen und fgt zustzliche Informationen aus eventuell vorhandenen Dokumentationskommentaren hinzu. Zu jeder Klassendatei xyz.java wird eine HTML-Seite xyz.html generiert, die ber verschiedene Querverweise mit den anderen Seiten desselben Projekts in Verbindung steht. Zustzlich generiert javadoc diverse Index- und Hilfsdateien, die das Navigieren in den Dokumentationsdateien erleichtern.
51.5.3 Dokumentationskommentare
1285
Teil IX
Bereits ohne zustzliche Informationen erstellt javadoc aus dem Quelltext eine brauchbare Beschreibung aller Klassen und Interfaces. Durch das Einfgen von Dokumentationskommentaren kann die Ausgabe zustzlich bereichert werden. Ein Dokumentationskommentar beginnt mit /** und endet mit */ und hnelt damit einem gewçhnlichen Kommentar. Er muss im Quelltext immer unmittelbar vor dem zu dokumentierenden Item platziert werden (einer Klassendefinition, einer Methode oder einer Instanzvariable). Er kann aus mehreren Zeilen bestehen. Die erste Zeile des Kommentars wird spter als Kurzbeschreibung verwendet.
Kapitel 51
i
Hilfsprogramme des JDK
i
i
INFO Zur Erhçhung der bersichtlichkeit darf am Anfang jeder Zeile ein Sternchen stehen, es wird spter ignoriert. Innerhalb der Dokumentationskommentare drfen neben normalem Text auch HTML-Tags vorkommen. Sie werden unverndert in die Dokumentation bernommen und erlauben es damit, bereits im Quelltext die Formatierung der spteren Dokumentation vorzugeben. Die Tags und
sollten mçglichst nicht verwendet werden, da sie von javadoc selbst zur Strukturierung der Ausgabe verwendet werden.
javadoc erkennt des Weiteren markierte Abstze innerhalb von Dokumentationskommentaren. Die Markierung muss mit dem Zeichen @ beginnen und – abgesehen von Leerzeichen – am Anfang der Zeile stehen. Jede Markierung leitet einen eigenen Abschnitt innerhalb der Beschreibung ein, alle Markierungen eines Typs mssen hintereinanderstehen. Tabelle 51.5, Seite 1286 gibt eine bersicht der wichtigsten Markierungen und beschreibt, wie sie verwendet werden. Tabelle 51.5: Markierungen in Dokumentationskommentaren
Markierung und Parameter
Dokumentation
Verwendung in
@author name
Erzeugt einen Autoreneintrag.
Klasse, Interface
@version version
Erzeugt einen Versionseintrag. Darf
Klasse, Interface
hçchstens einmal je Klasse oder Interface verwendet werden. @since jdk-version
Beschreibt, seit wann das beschriebene
Klasse, Interface
Feature existiert. @see reference
Erzeugt einen Querverweis auf eine an-
Klasse, Interface,
dere Klasse, Methode oder einen beliebi-
Instanzvariable,
gen anderen Teil der Dokumentation.
Methode
Gltige Verweise sind: " @see java.util.Vector " @see Vector " @see Vector#addElement " @see Spez @param name description
Parameterbeschreibung einer Methode
Methode
@return description
Beschreibung des Rckgabewerts einer
Methode
Methode @exception classname
Beschreibung einer Ausnahme, die von
description
dieser Methode ausgelçst wird
@deprecated description
Markiert eine veraltete Methode, die zuknftig nicht mehr verwendet werden sollte.
1286
Methode Methode
javadoc – der Dokumentationsgenerator
Kapitel 51
51.5.4 Aufruf von javadoc Um javadoc aufzurufen, sollte zunchst in das Verzeichnis gewechselt werden, in dem sich die zu dokumentierenden Quelldateien befinden. Anschließend kann durch Eingabe des folgenden Kommandos die Erzeugung der Dokumentationen fr alle Quelldateien gestartet werden: javadoc *.java Das Programm erzeugt eine Reihe von HMTL-Dateien, die die zu den jeweiligen Quellen korrespondierenden Dokumentationen enthalten. Zustzlich werden eine Reihe von Hilfsdateien zur Darstellung und Indexierung der Dokumentationsdateien erstellt. Alternativ zum Aufruf mit einer Reihe von Quelldateien kann javadoc auch mit Paketnamen als Argument aufgerufen werden. Wenn der Klassenpfad korrekt gesetzt ist, spielt es dann keine Rolle mehr, aus welchem Verzeichnis das Programm gestartet wird, denn die Klassendateien werden automatisch korrekt gefunden. Wenn nicht per Schalter -d etwas anderes angegeben wurde, erzeugt javadoc die Dokumentationsdateien im aktuellen Verzeichnis. JDK 1.1–6.0 In den JDKs 1.0 und 1.1 erzeugt javadoc zwei unterschiedliche Arten von Standardverweisen. Bei der ersten Art werden Grafiken eingebunden, um berschriften fr die verschiedenen Dokumentationsabschnitte zu generieren. Damit diese im Browser korrekt angezeigt werden, muss ein Unterverzeichnis images angelegt und die erforderlichen Grafikdateien dorthin kopiert werden (beispielsweise aus \jdk1.1.2\docs\api\images). Ab dem JDK 1.2 werden dagegen keine Grafikdateien mehr bençtigt.
» » »
Die zweite Art von Verweisen ist die auf Klassen oder Methoden der Java-Klassenbibliothek (z.B. java.lang.String). Im JDK 1.1 geht javadoc davon aus, dass sich die Dokumentationsdateien zu allen externen Klassen und Methoden im selben Verzeichnis wie die zu erstellenden Dokumentationsdateien befinden. Damit also externe Verweise funktionieren, msste man die HTML-Files der Originaldokumentation des JDK in sein eigenes Dokumentationsverzeichnis kopieren, was sicherlich nicht immer praktikabel ist. JDK 1.1–6.0 Mit dem JDK 1.2 wurde die Option -link eingefhrt, mit der ein Pfad auf die Dokumentation der Standardklassen angegeben werden kann. Der Pfad muss als URL angegeben werden und das Verzeichnis beschreiben, in dem die Datei package-list der Dokumentationsdateien liegt. In der Dokumentation zu javadoc gibt SUN folgendes Beispiel an:
» » »
javadoc -link http://java.sun.com/products/jdk/1.2/docs/api ...
1287
Teil IX
Dadurch wird bei Standardklassennamen auf die auf dem SUN-Server liegende Originaldokumentation verwiesen. Soll dagegen auf eine lokal installierte Dokumentation ver-
Kapitel 51
Hilfsprogramme des JDK
wiesen werden, kann auch ein file-URL angegeben werden. Liegt die Dokumentation des JDK beispielsweise im Verzeichnis c:\jdk1.6\docs (und somit die API-Dokumentation im Verzeichnis c:\jdk1.6\docs\api), kann javadoc wie folgt aufgerufen werden: javadoc -link file:///c:/jdk1.6/docs/api ...
51.5.5 Optionen Tabelle 51.6: Einige Optionen von javadoc
Option
Bedeutung
-classpath path
Gibt die Liste der Pfade zur Suche von Klassendateien an.
-public
Nur Elemente des Typs public werden dokumentiert.
-protected
Elemente des Typs public und protected werden dokumentiert (das ist die Voreinstellung).
-package
Elemente des Typs package, public und protected werden dokumentiert.
-private
Alle Elemente werden dokumentiert.
-version
Versionseintrag generieren
-author
Autoreneintrag generieren
-sourcepath path
Pfad mit den Quelldateien
-d directory
Verzeichnis, in dem die generierten Dokumentationsdateien abgelegt werden. Standardmßig werden sie im aktuellen Verzeichnis angelegt.
-verbose
» » »
1288
Ausgabe zustzlicher Meldungen whrend der Dokumentationserstellung
JDK 1.1–6.0 Neben den hier erwhnten Schaltern kennt javadoc (insbesondere seit dem JDK 1.2) eine ganze Reihe zustzlicher Optionen, mit denen die Codeerzeugung beeinflusst werden kann. Bemerkenswert ist dabei auf jeden Fall das Konzept der Doclets, mit denen das Verhalten von javadoc und das Aussehen der generierten Dokumentationsdateien weitgehend verndert werden kann. Doclets sind Zusatzmodule fr javadoc, deren Aufgabe es ist, auf der Basis des Doclet-APIs und der geparsten Quelltexte die Ausgabedateien zu erzeugen. Ob der generierte Code dabei im HTML-, RTF- oder einem anderen Format erzeugt wird, spielt keine Rolle. Das seit dem JDK 1.2 ausgelieferte Standard-Doclet erzeugt die Dokumentationsdateien im HTML-Format.
jar – das Archivierungswerkzeug
51.6
Kapitel 51
jar – das Archivierungswerkzeug
51.6.1 Aufruf jar [ commands ] archive { input-file }
51.6.2 Beschreibung jar ist ein Archivierungsprogramm, das Dateien und komplette Unterverzeichnisse komprimieren und in eine gemeinsame Archivdatei packen kann. Es verwendet ein Kompressionsformat, das den diversen zip-/unzip-Programmen hnelt, und wird analog dem UNIX-Tool tar bedient. Ein Vorteil von jar ist seine Portabilitt, die sowohl fr das erzeugte Dateiformat als auch fr das (in Java geschriebene) Programm selbst gilt. Wichtigster Einsatzzweck von jar ist es, alle zu einem Java-Programm gehçrenden Dateien (.class-, Image-, Sound-Dateien usw.) in einer einzigen Datei zusammenzufassen. Neben den organisatorischen Vorteilen, die diese Mçglichkeit zweifellos bietet, wurden jar-Dateien vor allem eingefhrt, um das Laden von Applets aus dem Internet zu beschleunigen. Dadurch mssen Web-Browser nmlich nicht mehr fr jede einzelne Datei, die in einem Applet bençtigt wird, eine eigene GET-Transaktion absetzen, sondern kçnnen alle erforderlichen Files in einem Schritt laden. Die Ladezeit von Applets wird dadurch drastisch verringert, insbesondere, wenn viele kleine Dateien bençtigt werden.
51.6.3 Kommandos Im Gegensatz zu den brigen Programmen, die in diesem Kapitel vorgestellt wurden, kennt jar keine Optionsparameter, sondern erwartet Kommandos an ihrer Stelle. Ein Kommando besteht aus einem Buchstaben, der ohne das Prfix - angegeben wird. Sollen mehrere Kommandos kombiniert werden, so werden die zugehçrigen Buchstaben ohne Lcken direkt hintereinander geschrieben. Diese abweichende Syntax stammt von dem Kommando tar, das auf UNIX-Rechnern zur Archivierung von Dateien eingesetzt wird. Tabelle 51.7, Seite 1289 gibt eine bersicht der verfgbaren Kommandos. Kommando
Bedeutung
c
Erzeugt eine neue Archivdatei (create). Kann nicht zusammen mit t oder x
Tabelle 51.7: Kommandos von jar
verwendet werden. t
Gibt das Inhaltsverzeichnis der Archivdatei aus (table of contents). Kann nicht zusammen mit c oder x verwendet werden.
x file
Extrahiert eine oder mehrere Dateien aus dem Archiv (extract). Kann nicht zusammen mit c oder t verwendet werden.
u
Fgt die angegebenen Dateien in die bestehende Archivdatei ein.
f
Gibt an, dass der nchste Parameter der Name der Archivdatei ist. Wird das Kommando f nicht angegeben, verwendet jar stattdessen die Standardein- und
1289
Teil IX
-ausgabe.
Kapitel 51 Tabelle 51.7: Kommandos von jar (Forts.)
Hilfsprogramme des JDK
Kommando
Bedeutung
v
Gibt zustzliche Informationen aus (verbose). Kann zustzlich zu einem der anderen Kommandos verwendet werden. Die Dateien werden ohne Kompression gespeichert.
0
Sollen beispielsweise alle .java-Dateien des aktuellen Verzeichnisses in ein Archiv mit der Bezeichnung xyz.jar gepackt werden, so kann dazu folgendes Kommando verwendet werden: jar cf xyz.jar *.java Das Inhaltsverzeichnis des Archivs kann folgendermaßen abgerufen werden: jar tf xyz.jar Etwas ausfhrlicher geht es mit: jar tvf xyz.jar Um die Datei Test.java aus dem Archiv zu extrahieren, kann das folgende Kommando verwendet werden (das natrlich auch ohne den Zusatz v funktioniert): jar xvf xyz.jar Test.java
51.6.4 Verwendung von jar-Dateien in Applets Die Verwendung von jar-Dateien in Applets erfolgt mit Hilfe des ARCHIVE-Parameters des APPLET-Tags (siehe Kapitel 39, Seite 923). Soll beispielsweise das »Hello, World«-Programm HWApplet.java aus Listing 39.7, Seite 934 aus einem jar-Archiv hello.jar ausgefhrt werden, so ist in den folgenden Schritten vorzugehen. Zunchst werden die Dateien HWApplet.class, hello.au und world.au in ein jar-Archiv gepackt: jar cvf hello.jar HWApplet.class hello.au world.au Anschließend wird die HTML-Datei HWApplet.html zum Aufruf des Applets erstellt: Listing 51.1: HTML mit ARCHIVE-Tag
1290
001 002 003 004 005 006 007 008 009 010 011
HWApplet
Kapitel 51 Listing 51.1: HTML mit ARCHIVE-Tag (Forts.)
Nun kann das Applet wie bisher gestartet werden, bençtigt aber zum Laden aller Dateien nur noch eine einzige HTTP-Transaktion.
i
INFO
i
i
Leider untersttzen noch nicht alle Browser das jar-Format, so dass seine Verwendung zum heutigen Zeitpunkt berlegt sein will. Fr die nahe Zukunft ist es aber ein wichtiger Schritt zur Verbesserung der Ladezeiten von Applets.
51.7
javap – der Disassembler
51.7.1
Aufruf
javap [ options ] classname
51.7.2 Beschreibung Der Disassembler javap liest den bersetzten Code einer Klasse und gibt Informationen darber auf der Standardausgabe aus. Dabei kçnnen entweder nur Informationen ber Variablen und Methoden oder der komplette Bytecode der Klasse ausgegeben werden. javap ist nicht in der Lage, den Java-Quellcode einer Klassendatei wieder herzustellen. Beim Aufruf ist der Name der Klasse ohne die Erweiterung .class anzugeben, also beispielsweise: javap -c java.lang.String
51.7.3 Optionen Option
Bedeutung
-classpath path
Gibt die Liste der Pfade zur Suche von Klassendateien an.
-public
Nur die Klassenelemente des Typs public werden angezeigt.
-protected
Nur die Klassenelemente des Typs public und protected werden angezeigt.
-package
Die Klassenelemente des Typs public, protected und die Elemente mit
Tabelle 51.8: Optionen von javap
Alle Klassenelemente werden angezeigt.
-c
Disassemblieren des Codes
-s
Ausgabe der Methodensignaturen
-l
Ausgabe von Zeilennummern
1291
Teil IX
Paketsichtbarkeit werden angezeigt. Das ist die Voreinstellung. -private
Kapitel 51
Hilfsprogramme des JDK
51.8
serialver – Zugriff auf die serialVersionUID
51.8.1 Aufruf serialver -show | classname
51.8.2 Beschreibung Mit serialver kann auf die serialVersionUID einer Klasse zugegriffen werden (siehe Abschnitt 41.2.1, Seite 971). Wenn das Programm mit einem Klassennamen aufgerufen wird, gibt es die serialVersionUID auf der Console aus. Wird es mit der Option -show (und ohne Klassennamen) aufgerufen, erfolgt der Aufruf mit einer einfachen grafischen Oberflche.
51.8.3 Optionen Tabelle 51.9: Optionen von serialver
Option
Bedeutung
-show
Aufruf mit grafischer Oberflche
51.9
keytool – Verwaltung von kryptografischen Schlsseln
51.9.1 Aufruf keytool [ commands ]
51.9.2 Beschreibung keytool ist ein Hilfsprogramm zum Erzeugen und Verwalten von Schlsseln fr PublicKey-Kryptosysteme. Das Programm bietet eine große Anzahl von Funktionen, von denen die wichtigsten bereits in Abschnitt 48.1.6, Seite 1206 erklrt wurden. Weitere Details kçnnen in der Tool-Dokumentation des JDK nachgelesen werden.
51.10 policytool – Bearbeiten von Policy-Dateien 51.10.1 Aufruf policytool
1292
jarsigner – Signieren von Archiven
Kapitel 51
51.10.2 Beschreibung policytool ist ein interaktives Programm zum Bearbeiten von Policy-Dateien (siehe Abschnitt 48.3.4, Seite 1222). Mit seiner Hilfe kçnnen neue Policy-Dateien erstellt oder vorhandene gendert werden. Es versucht zunchst, die benutzerbezogene Policy-Datei zu çffnen (unter Windows c:\windows\.java.policy, unter UNIX $HOME/.java.policy), kann aber auch fr beliebige andere Policy-Dateien verwendet werden. In einer Listbox zeigt das Programm alle vorhandenen Eintrge an. Sie kçnnen editiert oder gelçscht oder es kçnnen neue hinzugefgt werden. Wenn ein Policy-Eintrag bearbeitet wird, werden alle Berechtigungen auf dem Bildschirm angezeigt. Auch sie kçnnen bearbeitet, gelçscht oder hinzugefgt werden. Beim Hinzufgen kçnnen die mçglichen Varianten – ohne die Gefahr von Tippfehlern, wie sie beim manuellen Editieren leicht entstehen kçnnen – bequem im Dialog ausgewhlt werden. Nach dem Bearbeiten kçnnen die nderungen in die ursprngliche oder eine andere Policy-Datei geschrieben werden.
51.11 jarsigner – Signieren von Archiven 51.11.1 Aufruf jarsigner [ options ] jarfile alias
51.11.2 Beschreibung jarsigner dient zum Zugriff auf die Signatur von jar-Archiven. Dazu wird der Schlssel verwendet, der unter dem als Argument angegebenen Alias in der Schlsseldatenbank gespeichert ist. Seine wichtigste Anwendung, das Signieren von Archiven, wurde bereits in Abschnitt 48.3.2, Seite 1219 erlutert.
51.11.3 Optionen Option
Bedeutung
-signedjar file
Name des beim Signieren erzeugten Archivs
-keystore url
Name der Schlsseldatenbank
-storetype type
Typ der Schlsseldatenbank
-storepass pass
Passwort der Schlsseldatenbank (falls nicht angegeben, wird es interaktiv
Tabelle 51.10: Optionen von jarsigner
abgefragt) -keypass pass
Passwort des Schlssels (falls nicht angegeben, wird es interaktiv abgefragt)
-verify
Wird diese Option angegeben, so wird das Archiv nicht signiert, sondern
1293
Teil IX
verifiziert
Kapitel 51
Hilfsprogramme des JDK
51.12 rmic – Erzeugen von RMI-Stubs und -Skeletons 51.12.1 Aufruf rmic [ options ] classname
51.12.2 Beschreibung rmic dient dazu, aus der Implementierung eines Remote-Objekts die zugehçrigen RMIStubs und -Skeletons zu erzeugen. Seine Anwendung wurde in Abschnitt 47.2.3, Seite 1184 erlutert.
51.12.3 Optionen Tabelle 51.11: Optionen von rmic
Option
Bedeutung
-classpath path
Klassenpfad zur Suche der angegebenen Klasse
-d directory
Wurzel des Zielverzeichnisses fr die zu erzeugenden Klassen
-g
Erzeugen von Debug-Code
-keepgenerated
Die temporren .java-Dateien werden nicht gelçscht.
-vcompat
Erzeugt Stubs und Skeletons, die zu den Stub-Protokollen 1.1 und 1.2 kompatibel sind (Voreinstellung).
-v1.1
Erzeugt Stubs und Skeletons, die zum Stub-Protokoll 1.1 kompatibel sind.
-v1.2
Erzeugt Stubs und Skeletons, die zum Stub-Protokoll 1.2 kompatibel sind.
51.13 rmiregistry – der RMI-Namensservice 51.13.1 Aufruf rmiregistry [port]
51.13.2 Beschreibung rmiregistry ist der Standard-Namensservice fr RMI. Er dient als Hintergrund dazu, RMI-Objekte zu registrieren und auf Anfrage Clients zur Verfgung zu stellen. rmiregistry wurde in Abschnitt 47.2.4, Seite 1186 erlutert. Seine einzige Option ist die TCP-PortNummer. Wird sie nicht angegeben, gilt 1099 als Voreinstellung.
1294
Zusammenfassung
Kapitel 51
Zusammenfassung In diesem Kapitel wurden folgende Themen behandelt: " Aufruf des Java-Compilers javac zum bersetzen von .java- in .class-Dateien " Aufruf des Java-Interpreters java zum Ausfhren von Java-Applikationen " Die Bedeutung der CLASSPATH-Umgebungsvariable " Aufruf des Applet-Viewers appletviewer zum Ausfhren von Java-Applets " Vorbereiten eines Programms zum Debuggen und Aufruf des Debuggers jdb " Die wichtigsten Kommandos des Debuggers " Erzeugen von Quelltextdokumentationen mit Hilfe von javadoc " Die Struktur von Dokumentationskommentaren und die Markierungen @author, @version, @since, @see, @param, @return, @exception und @deprecated " Die Bedienung des Archivierungsprogramms jar " Verwendung von jar-Dateien in Applets " Aufruf des Disassemblers javap " Zugriff auf die serialVersionUID mit serialver " Verwaltung von kryptografischen Schlsseln mit keytool " Verwendung von policytool zum Bearbeiten von Policy-Dateien " Signieren von Archiven mit jarsigner " Erzeugen von RMI-Stubs und -Skeletons mit rmic
1295
Teil IX
" Der RMI-Namensservice rmiregistry
J2SE Software License
Sun Microsystems, Inc. Binary Code License Agreement for the JAVA VERSION 6
SE
DEVELOPMENT
KIT
(JDK),
SUN MICROSYSTEMS, INC. ("SUN") IS WILLING TO LICENSE THE SOFTWARE IDENTIFIED BELOW TO YOU ONLY UPON THE CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS BINARY CODE LICENSE AGREEMENT AND SUPPLEMENTAL LICENSE TERMS (COLLECTIVELY "AGREEMENT"). PLEASE READ THE AGREEMENT CAREFULLY. BY DOWNLOADING OR INSTALLING THIS SOFTWARE, YOU ACCEPT THE TERMS OF THE AGREEMENT. INDICATE ACCEPTANCE BY SELECTING THE "ACCEPT" BUTTON AT THE BOTTOM OF THE AGREEMENT. IF YOU ARE NOT WILLING TO BE BOUND BY ALL THE TERMS, SELECT THE "DECLINE" BUTTON AT THE BOTTOM OF THE AGREEMENT AND THE DOWNLOAD OR INSTALL PROCESS WILL NOT CONTINUE. 1. DEFINITIONS. "Software" means the identified above in binary form, any other machine readable materials (including, but not limited to, libraries, source files, header files, and data files), any updates or error corrections provided by Sun, and any user manuals, programming guides and other documentation provided to you by Sun under this Agreement. "Programs" mean Java applets and applications intended to run on the Java Platform, Standard Edition (Java SE) on Java-enabled general purpose desktop computers and servers. 2. LICENSE TO USE. Subject to the terms and conditions of this Agreement, including, but not limited to the Java
J2SE Software License
Technology Restrictions of the Supplemental License Terms, Sun grants you a non-exclusive, non-transferable, limited license without license fees to reproduce and use internally Software complete and unmodified for the sole purpose of running Programs. Additional licenses for developers and/or publishers are granted in the Supplemental License Terms. 3. RESTRICTIONS. Software is confidential and copyrighted. Title to Software and all associated intellectual property rights is retained by Sun and/or its licensors. Unless enforcement is prohibited by applicable law, you may not modify, decompile, or reverse engineer Software. You acknowledge that Licensed Software is not designed or intended for use in the design, construction, operation or maintenance of any nuclear facility. Sun Microsystems, Inc. disclaims any express or implied warranty of fitness for such uses. No right, title or interest in or to any trademark, service mark, logo or trade name of Sun or its licensors is granted under this Agreement. Additional restrictions for developers and/or publishers licenses are set forth in the Supplemental License Terms. 4. LIMITED WARRANTY. Sun warrants to you that for a period of ninety (90) days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foregoing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software. Any implied warranties on the Software are limited to 90 days. Some states do not allow limitations on duration of an implied warranty, so the above may not apply to you. This limited warranty gives you specific legal rights. You may have others, which vary from state to state. 5. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. 6. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential
1298
J2SE Software License
purpose. Some states do not allow the exclusion of incidental or consequential damages, so some of the terms above may not be applicable to you. 7. TERMINATION. This Agreement is effective until terminated. You may terminate this Agreement at any time by destroying all copies of Software. This Agreement will terminate immediately without notice from Sun if you fail to comply with any provision of this Agreement. Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right. Upon Termination, you must destroy all copies of Software. 8. EXPORT REGULATIONS. All Software and technical data delivered under this Agreement are subject to US export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with all such laws and regulations and acknowledge that you have the responsibility to obtain such licenses to export, re-export, or import as may be required after delivery to you. 9. TRADEMARKS AND LOGOS. You acknowledge and agree as between you and Sun that Sun owns the SUN, SOLARIS, JAVA, JINI, FORTE, and iPLANET trademarks and all SUN, SOLARIS, JAVA, JINI, FORTE, and iPLANET-related trademarks, service marks, logos and other brand designations ("Sun Marks"), and you agree to comply with the Sun Trademark and Logo Usage Requirements currently located at http://www.sun.com/ policies/trademarks. Any use you make of the Sun Marks inures to Sun's benefit. 10. U.S. GOVERNMENT RESTRICTED RIGHTS. If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreement; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions). 11. GOVERNING LAW. Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply. 12. SEVERABILITY. If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate. 13. INTEGRATION. This Agreement is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement.
1299
J2SE Software License
No modification of this Agreement will be binding, unless in writing and signed by an authorized representative of each party. SUPPLEMENTAL LICENSE TERMS These Supplemental License Terms add to or modify the terms of the Binary Code License Agreement. Capitalized terms not defined in these Supplemental Terms shall have the same meanings ascribed to them in the Binary Code License Agreement.
These Supplemental Terms shall supersede any inconsistent or conflicting terms in the Binary Code License Agreement, or in any license contained within the Software. A. Software Internal Use and Development License Grant. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software "README" file incorporated herein by reference, including, but not limited to the Java Technology Restrictions of these Supplemental Terms, Sun grants you a non-exclusive, non-transferable, limited license without fees to reproduce internally and use internally the Software complete and unmodified for the purpose of designing, developing, and testing your Programs. B. License to Distribute Software. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software README file, including, but not limited to the Java Technology Restrictions of these Supplemental Terms, Sun grants you a non-exclusive, non-transferable, limited license without fees to reproduce and distribute the Software, provided that (i) you distribute the Software complete and unmodified and only bundled as part of, and for the sole purpose of running, your Programs, (ii) the Programs add significant and primary functionality to the Software, (iii) you do not distribute additional software intended to replace any component(s) of the Software, (iv) you do not remove or alter any proprietary legends or notices contained in the Software, (v) you only distribute the Software subject to a license agreement that protects Sun's interests consistent with the terms contained in this Agreement, and (vi) you agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software. C. License to Distribute Redistributables. Subject to the terms and conditions of this Agreement and restrictions and exceptions set forth in the Software README file, including but not limited to the Java Technology Restrictions of these Supplemental Terms, Sun grants you a non-exclusive, non-transferable, limited license without fees to reproduce and distribute those files specifically identified as redistributable in the Software "README" file ("Redistributables") provided that: (i) you distribute the Redistribut-
1300
J2SE Software License
ables complete and unmodified, and only bundled as part of Programs, (ii) the Programs add significant and primary functionality to the Redistributables, (iii) you do not distribute additional software intended to supersede any component(s) of the Redistributables (unless otherwise specified in the applicable README file), (iv) you do not remove or alter any proprietary legends or notices contained in or on the Redistributables, (v) you only distribute the Redistributables pursuant to a license agreement that protects Sun's interests consistent with the terms contained in the Agreement, (vi) you agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settlement amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software. D. Java Technology Restrictions. You may not create, modify, or change the behavior of, or authorize your licensees to create, modify, or change the behavior of, classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" or similar convention as specified by Sun in any naming convention designation. E. Distribution by Publishers. This section pertains to your distribution of the Software with your printed book or magazine (as those terms are commonly used in the industry) relating to Java technology ("Publication"). Subject to and conditioned upon your compliance with the restrictions and obligations contained in the Agreement, in addition to the license granted in Paragraph 1 above, Sun hereby grants to you a non-exclusive, nontransferable limited right to reproduce complete and unmodified copies of the Software on electronic media (the "Media") for the sole purpose of inclusion and distribution with your Publication(s), subject to the following terms: (i) You may not distribute the Software on a stand-alone basis; it must be distributed with your Publication(s); (ii) You are responsible for downloading the Software from the applicable Sun web site; (iii) You must refer to the Software as JavaTM SE Development Kit 6; (iv) The Software must be reproduced in its entirety and without any modification whatsoever (including, without limitation, the Binary Code License and Supplemental License Terms accompanying the Software and proprietary rights notices contained in the Software); (v) The Media label shall include the following information: Copyright 2006, Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Sun, Sun Microsystems, the Sun logo, Solaris, Java, the Java Coffee Cup logo, J2SE, and all trademarks and logos based on Java are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This information must be placed on the Media label in such a manner as to only apply to the Sun Software; (vi) You must clearly identify the Software as Sun's product on the Media holder or Media label, and you may not state or imply that Sun is responsible for any third-party software contained on the Media; (vii) You may not include any third party software on the Media which is intended to be a replacement or substitute for the Software; (viii) You shall indemnify Sun for all damages arising from your failure to comply with the requirements of this Agreement. In addition, you shall defend, at your expense, any and all claims brought against Sun by third parties, and shall pay all
1301
J2SE Software License
damages awarded by a court of competent jurisdiction, or such settlement amount negotiated by you, arising out of or in connection with your use, reproduction or distribution of the Software and/or the Publication. Your obligation to provide indemnification under this section shall arise provided that Sun: (a) provides you prompt notice of the claim; (b) gives you sole control of the defense and settlement of the claim; (c) provides you, at your expense, with all available information, assistance and authority to defend; and (d) has not compromised or settled such claim without your prior written consent; and (ix) You shall provide Sun with a written notice for each Publication; such notice shall include the following information: (1) title of Publication, (2) author(s), (3) date of Publication, and (4) ISBN or ISSN numbers. Such notice shall be sent to Sun Microsystems, Inc., 4150 Network Circle, M/S USCA12-110, Santa Clara, California 95054, U.S.A, Attention: Contracts Administration. F. Source Code. Software may contain source code that, unless expressly licensed for other purposes, is provided solely for reference purposes pursuant to the terms of this Agreement. Source code may not be redistributed unless expressly provided for in this Agreement. G. Third Party Code. Additional copyright notices and license terms applicable to portions of the Software are set forth in the THIRDPARTYLICENSEREADME.txt file. In addition to any terms and conditions of any third party opensource/freeware license identified in the THIRDPARTYLICENSEREADME.txt file, the disclaimer of warranty and limitation of liability provisions in paragraphs 5 and 6 of the Binary Code License Agreement shall apply to all Software in this distribution. H. Termination for Infringement. Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right. I. Installation and Auto-Update. The Software's installation and auto-update processes transmit a limited amount of data to Sun (or its service provider) about those specific processes to help Sun understand and optimize them. Sun does not associate the data with personally identifiable information. You can find more information about the data Sun collects at http://java.com/data/. For inquiries please contact: Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, California 95054, U.S.A.
1302
Abbildungsverzeichnis
Abbildung 2.1 Abbildung 2.2 Abbildung 2.3 Abbildung 2.4 Abbildung 2.5 Abbildung 3.1 Abbildung 3.2 Abbildung 3.3 Abbildung 3.4 Abbildung 4.1 Abbildung 7.1 Abbildung 10.1 Abbildung 10.2 Abbildung 10.3 Abbildung 10.4 Abbildung 10.5 Abbildung 10.6 Abbildung 10.7 Abbildung 10.8 Abbildung 11.1 Abbildung 11.2 Abbildung 11.3
Ist das JDK korrekt installiert? . . . . 59 Hello.java im Windows-Notepad . 61 bersetzen von Hello.java . . . . . . . . 62 Ausfhren von Hello . . . . . . . . . . . . . . 63 Eine Verknpfung auf dem Windows-Desktop . . . . . . . . . . . . . . . . . . . . . 71 Die API-Dokumentation des JDK . 83 Die HTML-Ausgabe des Buchs . . . 88 UML-Notation fr Klassen und Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 UML-Notation fr Beziehungen zwischen Klassen und Interfaces . 91 Konvertierungen auf primitiven Datentypen . . . . . . . . . . . . . . . . . . . . . . . . 110 Vererbungshierarchie fr Transportmittel . . . . . . . . . . . . . . . . . . . 159 Klassendiagramm einer FactoryMethode . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Klassendiagramm einer FactoryKlasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Klassendiagramm einer abstrakten Factory . . . . . . . . . . . . . . . . 241 Klassendiagramm eines Iterators 245 Klassendiagramm eines Delegate 248 Klassendiagramm eines Composite . . . . . . . . . . . . . . . . . . . . . . . . . 251 Klassendiagramm eines Visitors . 254 Klassendiagramm eines Observer 258 Ein Aufruf von substring(begin, end) . . . . . . . . . . . . . 267 Der Aufruf von regionMatches . . 270 Das Interface CharSequence . . . . . 277
Abbildungsverzeichnis
Abbildung 13.1 Abbildung 13.2 Abbildung 13.3 Abbildung 13.4 Abbildung 23.1 Abbildung 23.2 Abbildung 23.3 Abbildung 23.4 Abbildung 23.5 Abbildung 23.6 Abbildung 23.7 Abbildung 23.8 Abbildung 23.9 Abbildung 23.10 Abbildung 23.11 Abbildung 24.1 Abbildung 24.2 Abbildung 24.3 Abbildung 24.4 Abbildung 24.5 Abbildung 24.6 Abbildung 24.7 Abbildung 25.1 Abbildung 25.2 Abbildung 26.1 Abbildung 26.2 Abbildung 26.3 Abbildung 27.1 Abbildung 27.2 Abbildung 27.3 Abbildung 27.4 Abbildung 28.1 Abbildung 28.2 Abbildung 28.3 Abbildung 29.1 Abbildung 29.2 Abbildung 29.3 Abbildung 29.4 Abbildung 29.5 Abbildung 30.1 Abbildung 30.2 Abbildung 30.3
1304
Der Entwicklungszyklus in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Plattformbergreifende Entwicklung in Java . . . . . . . . . . . . . . . . . . . . . . . . Die Startdatei der WebStart-Anwendung im Browser . . . . . . . . . . . . . . . Der WebStart-Applikationsmanager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Koordinatensystem von Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfaches Fenster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Linien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Rechtecken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe eines Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Kreisen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Kreisbçgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von gefllten Flchen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe des Java-Logos als Liniengrafik . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kopieren von Grafiken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Clipping-Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einfache Textausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Randelemente eines Fensters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe verschiedener Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste der Standardschriften . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Grçßenmaßzahlen fr Fonts in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anzeige von Font-Metriken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zentrierte Textausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der Farbenkreis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Systemfarben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Programm zur Druckausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der Dialog zur Druckseitenkonfiguration unter Windows . . . . . . . . . . Der Dialog zur Druckjobkonfiguration unter Windows . . . . . . . . . . . . . Hierarchie der Fensterklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher Bildschirmschoner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Beispiel-Icon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Programm mit vernderten Fensterelementen . . . . . . . . . . . . . . . . . . Die Hierarchie der Ereignisklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Hierarchie der EventListener-Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . Das Programm fr den Nachrichtentransfer . . . . . . . . . . . . . . . . . . . . . . . . . Das Fenster sieht sich selbst aus der Vogelperspektive . . . . . . . . . . . . . Die Ausgabe des Mausklickprogramms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Ausgabe des Mausbewegungsprogramms . . . . . . . . . . . . . . . . . . . . . . Programm nach Erhalt des Eingabefokus . . . . . . . . . . . . . . . . . . . . . . . . . . . . Darstellung von Tastaturereignissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen von Mens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Geschachtelte Mens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Programm, das auf Action-Events reagiert . . . . . . . . . . . . . . . . . . . . . .
313 313 327 328 535 538 539 541 542 543 544 546 546 548 550 552 553 555 557 559 561 562 567 569 577 581 581 595 601 603 606 611 613 620 638 642 646 649 654 663 668 672
Abbildungsverzeichnis
Abbildung 30.4 Abbildung 31.1 Abbildung 31.2 Abbildung 31.3 Abbildung 31.4 Abbildung 31.5 Abbildung 31.6 Abbildung 31.7 Abbildung 31.8 Abbildung 31.9 Abbildung 31.10 Abbildung 31.11 Abbildung 31.12 Abbildung 31.13 Abbildung 31.14 Abbildung 31.15 Abbildung 31.16 Abbildung 31.17 Abbildung 31.18 Abbildung 32.1 Abbildung 32.2 Abbildung 32.3 Abbildung 32.4 Abbildung 32.5 Abbildung 32.6 Abbildung 32.7 Abbildung 32.8 Abbildung 32.9 Abbildung 32.10 Abbildung 32.11 Abbildung 32.12 Abbildung 33.1 Abbildung 33.2 Abbildung 34.1 Abbildung 34.2 Abbildung 34.3 Abbildung 34.4 Abbildung 34.5 Abbildung 34.6 Abbildung 34.7 Abbildung 34.8 Abbildung 34.9
Aufruf eines Kontextmens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit zwei Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse FlowLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse GridLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das FlowLayout in einem grçßeren Fenster . . . . . . . . . . . . . . . . . . . . . . . . . Das GridLayout in einem grçßeren Fenster . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse BorderLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein BorderLayout mit Lcken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Beispiel fr GridBagLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zellenschema fr GridBagLayout-Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . Das GridBagLayout-Beispiel nach dem Skalieren . . . . . . . . . . . . . . . . . . . Verwendung des Null-Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung eines geschachtelten Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . Ein weiteres Beispiel fr geschachtelte Layouts . . . . . . . . . . . . . . . . . . . . . Das Vaterfenster fr den modalen Dialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher Ja-/Nein-Dialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Aufruf von OKDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Aufruf von YesNoDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Aufruf von YesNoCancelDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Beispielprogramm zum Aufruf der Beispieldialoge . . . . . . . . . . . . Der noch leere Beispieldialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit Label-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit Checkbox-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit CheckboxGroup-Elementen . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit beschrifteten Textfeldern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit einem TextArea-Objekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit einer Choice-Komponente . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit einer Listbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit zwei Schiebereglern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ViewPort und virtueller Ausgabebereich beim ScrollPane . . . . . . . . . . Verwendung von ScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der Aufbau der 7-Segment-Anzeige . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Beispiel fr die Anwendung der 7-Segment-Anzeige . . . . . . . . . . . Laden und Anzeigen einer Bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von BitmapComponent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein animierter Zhler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Ausgabe whrend des Ladevorgangs . . . . . . . . . . . . . . . . . . . . . . . . . . . . Animation eines Schriftzugs, Schnappschuss 1 . . . . . . . . . . . . . . . . . . . . . . Animation eines Schriftzugs, Schnappschuss 2 . . . . . . . . . . . . . . . . . . . . . . Animation eines Schriftzugs, Schnappschuss 3 . . . . . . . . . . . . . . . . . . . . . . Die animierte Schlange, Schnappschuss 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die animierte Schlange, Schnappschuss 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
675 684 686 688 688 689 691 691 694 695 697 698 700 701 705 706 709 709 709 712 712 715 718 720 723 725 728 730 733 735 740 743 751 755 759 761 764 766 766 766 771 771
1305
Abbildungsverzeichnis
Abbildung 34.10 Abbildung 34.11 Abbildung 34.12 Abbildung 35.1 Abbildung 35.2 Abbildung 35.3 Abbildung 36.1 Abbildung 36.2 Abbildung 36.3 Abbildung 36.4 Abbildung 36.5 Abbildung 36.6 Abbildung 36.7 Abbildung 36.8 Abbildung 36.9 Abbildung 36.10 Abbildung 36.11 Abbildung 36.12 Abbildung 37.1 Abbildung 37.2 Abbildung 37.3 Abbildung 37.4 Abbildung 37.5 Abbildung 37.6 Abbildung 37.7 Abbildung 37.8 Abbildung 37.9 Abbildung 37.10 Abbildung 37.11 Abbildung 37.12 Abbildung 38.1 Abbildung 38.2 Abbildung 38.3 Abbildung 38.4 Abbildung 38.5 Abbildung 38.6 Abbildung 38.7 Abbildung 38.8 Abbildung 38.9 Abbildung 38.10 Abbildung 39.1 Abbildung 39.2
1306
Die animierte Schlange, Schnappschuss 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Lauflicht-Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Animation mit Doppelpufferung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Beispielprogramm im Metal-Look-and-Feel . . . . . . . . . . . . . . . . . . . . Das Beispielprogramm im Motif-Look-and-Feel . . . . . . . . . . . . . . . . . . . . . Das Beispielprogramm im Windows-Look-and-Feel . . . . . . . . . . . . . . . . Ein einfaches JFrame-Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Struktur einer RootPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Hauptfenster mit Dialogelementen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher SplashScreen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Standard-Icons bei JOptionPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Button-Kombinationen bei showConfirmDialog . . . . . . . . . . . . . . . . . . . . . Die Methode showInputDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JInternalFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Swing-Programm mit einem einfachen Men . . . . . . . . . . . . . . . . . . . Ein Swing-Programm mit einem umfangreichen Men . . . . . . . . . . . . . Die wichtigsten Umrandungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Programm mit einem transparenten Button . . . . . . . . . . . . . . . . . . . . . Die Klasse JLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTextField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTextArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSpinner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JCheckBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JRadioButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JComboBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JScrollBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSlider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Anatomie einer JScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSplitPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTabbedPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine einfache Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine JTable mit einer Million Zellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine JTable mit eigenem Spaltenmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Tabelle mit einem eigenen Zellrenderer . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher JTree im Metal- und Windows-Look-and-Feel . . . . . . . Ein vernderbarer JTree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ableitungsbaum der Applet-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Darstellung des Schranken-Applets im Netscape Navigator . . . . . . . .
771 774 781 790 791 791 800 801 803 805 807 809 811 816 821 826 830 834 843 846 849 851 854 856 858 863 865 868 872 874 879 881 885 888 890 900 902 906 911 918 924 932
Abbildungsverzeichnis
Abbildung 39.3 Abbildung 39.4 Abbildung 40.1 Abbildung 40.2 Abbildung 40.3 Abbildung 41.1 Abbildung 41.2 Abbildung 42.1 Abbildung 44.1 Abbildung 44.2 Abbildung 44.3 Abbildung 44.4 Abbildung 44.5 Abbildung 44.6 Abbildung 44.7 Abbildung 44.8 Abbildung 44.9 Abbildung 44.10 Abbildung 44.11 Abbildung 45.1 Abbildung 45.2 Abbildung 46.1 Abbildung 46.2 Abbildung 47.1 Abbildung 47.2 Abbildung 47.3 Abbildung 48.1 Abbildung 49.1 Abbildung 49.2
Das sprechende Hello, World-Programm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934 Das Wolkenkratzer-Beispielprogramm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937 Darstellung von URLLaden im Netscape Navigator . . . . . . . . . . . . . . . . 949 Die drei kommunizierenden Applets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952 Die Calculator-Applikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953 Das Programm serialver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 972 Eltern-Kind-Graph fr Serialisierungsbeispiel . . . . . . . . . . . . . . . . . . . . . . . 975 E/R-Diagramm fr DirDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 997 Die Glhlampen-Bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1066 Die Beanbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068 Die Glhlampe in der BeanBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1072 Die deserialisierte Glhlampen-Bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074 LightedPushButton und VetoSwitch in der Beanbox . . . . . . . . . . . . . . . 1084 Testprogramm fr Eigenschaftennderungen . . . . . . . . . . . . . . . . . . . . . . 1085 Das ButtonPanel in der BeanBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1090 LightBulbLightOnEditor1 in der Beanbox . . . . . . . . . . . . . . . . . . . . . . . . . . 1096 LightBulbLightOnEditor2 in der Beanbox . . . . . . . . . . . . . . . . . . . . . . . . . . 1097 LightBulbLightOnEditor3 in der Beanbox . . . . . . . . . . . . . . . . . . . . . . . . . . 1100 LightBulbLightOnEditor3 in der Eigenschaftenliste . . . . . . . . . . . . . . . . 1100 Datenbankzugriff mit JDBC und ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1104 E/R-Diagramm fr DirDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1119 Das ISO/OSI-7-Schichten-Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1144 Das vereinfachte 4-Ebenen-Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145 Prinzipielle Arbeitsweise von RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1180 Stubs und Skeletons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1181 Kommunikation im RMI-Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1192 Verschlsseln einer Nachricht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196 Samplen eines Audio-Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 Ein gesampeltes Audio-Signal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231
1307
Tabellenverzeichnis
Tabelle 3.1 Tabelle 3.2 Tabelle 4.1 Tabelle 4.2 Tabelle 4.3 Tabelle 4.4 Tabelle 5.1 Tabelle 5.2 Tabelle 5.3 Tabelle 5.4 Tabelle 5.5 Tabelle 5.6 Tabelle 10.1 Tabelle 13.1 Tabelle 13.2 Tabelle 16.1 Tabelle 16.2 Tabelle 17.1 Tabelle 17.2 Tabelle 18.1 Tabelle 18.2 Tabelle 19.1 Tabelle 24.1 Tabelle 25.1 Tabelle 25.2 Tabelle 27.1 Tabelle 28.1 Tabelle 28.2
Inhalt der JDK-Dokumentation . . . . . . . 82 Die comp.lang. java-Hierarchie im Usenet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Primitive Datentypen . . . . . . . . . . . . . . . . . 98 Standard-Escape-Sequenzen . . . . . . . . . 99 Symbolische Ganzzahlliterale . . . . . . . 101 Symbolische Fließkommaliterale . . . . 101 Arithmetische Operatoren . . . . . . . . . . 118 Relationale Operatoren . . . . . . . . . . . . . . 118 Logische Operatoren . . . . . . . . . . . . . . . . 119 Bitweise Operatoren . . . . . . . . . . . . . . . . . 120 Zuweisungsoperatoren . . . . . . . . . . . . . . 121 Operator-Vorrangregeln . . . . . . . . . . . . . 127 Die Wrapper-Klassen . . . . . . . . . . . . . . . . 223 Wichtige Standardpakete des JDK . . 304 Wichtige Standarderweiterungen des JDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Feldbezeichner der Klasse Calendar 389 Standard-Properties . . . . . . . . . . . . . . . . . 397 Hufige Elemente fr regulre Ausdrcke in Java . . . . . . . . . . . . . . . . . . . . 414 Formatzeichen fr DecimalFormat . . 428 Aus Writer abgeleitete Klassen . . . . . 442 Aus Reader abgeleitete Klassen . . . . . 453 Die UTF-8-Kodierung . . . . . . . . . . . . . . . 466 Style-Parameter . . . . . . . . . . . . . . . . . . . . . . 555 Gebruchliche Farbwerte . . . . . . . . . . . . 563 Liste der vordefinierten Systemfarben . . . . . . . . . . . . . . . . . . . . . . . . . 567 Konstanten zur Cursorauswahl . . . . . 604 Focus-Ereignisse . . . . . . . . . . . . . . . . . . . . . 614 Methoden fr Focus-Ereignisse . . . . . 615
Tabellenverzeichnis
Tabelle 28.3 Tabelle 28.4 Tabelle 28.5 Tabelle 28.6 Tabelle 28.7 Tabelle 28.8 Tabelle 28.9 Tabelle 28.10 Tabelle 28.11 Tabelle 28.12 Tabelle 28.13 Tabelle 28.14 Tabelle 28.15 Tabelle 28.16 Tabelle 28.17 Tabelle 28.18 Tabelle 28.19 Tabelle 28.20 Tabelle 28.21 Tabelle 28.22 Tabelle 29.1 Tabelle 29.2 Tabelle 29.3 Tabelle 29.4 Tabelle 29.5 Tabelle 32.1 Tabelle 32.2 Tabelle 36.1 Tabelle 36.2 Tabelle 36.3 Tabelle 36.4 Tabelle 36.5 Tabelle 36.6 Tabelle 38.1 Tabelle 38.2 Tabelle 39.1 Tabelle 42.1 Tabelle 42.2 Tabelle 42.3 Tabelle 42.4 Tabelle 42.5 Tabelle 43.1
1310
Key-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 Methoden fr Key-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 Mouse-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 Methoden fr Mouse-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615 MouseMotion-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 Methoden fr MouseMotion-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 Komponenten-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 Methoden fr Komponenten-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 Container-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616 Methoden fr Container-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 Window-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 Methoden fr Window-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 Action-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 Methoden fr Action-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617 Adjustment-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Methoden fr Adjustment-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Item-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Methoden fr Item-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Text-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Methoden fr Text-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618 Methoden von WindowListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634 Methoden von ComponentListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636 Methoden von MouseListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 Virtuelle Keycodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651 Rckgabecodes bei Tastaturereignissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652 Konstanten fr Schieberegler-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 Konstanten zur Anzeige der Schieberegler in ScrollPane . . . . . . . . . . . . . . 734 Rckgabewerte des showConfirmDialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 809 Konstanten fr Umschalttasten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819 Die Konstanten der Klasse SwingConstants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822 Border-Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829 DebugGraphics-Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 832 Bedingungen zur Registrierung von Tastaturkommandos . . . . . . . . . . . . . 837 Anzeige der Schieberegler bei JScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878 Parameter fr setAutoResizeMode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892 Optionale Parameter des APPLET-Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 929 get-Methoden von ResultSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 994 Die Struktur der dir-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996 Die Struktur der file-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 997 SQL-Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1018 SQL-Aggregatfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1020 Klassenobjekte fr die primitiven Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029
Tabellenverzeichnis
Tabelle 43.2 Tabelle 45.1 Tabelle 45.2 Tabelle 45.3 Tabelle 45.4 Tabelle 45.5 Tabelle 45.6 Tabelle 45.7 Tabelle 46.1 Tabelle 46.2 Tabelle 46.3 Tabelle 48.1 Tabelle 50.1 Tabelle 50.2 Tabelle 51.1 Tabelle 51.2 Tabelle 51.3 Tabelle 51.4 Tabelle 51.5 Tabelle 51.6 Tabelle 51.7 Tabelle 51.8 Tabelle 51.9 Tabelle 51.10 Tabelle 51.11
Sichtbarkeitsattribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Struktur der dir-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . JPA Basis-Annotationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Attribute der Annotation @Column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anpassen der Konfigurationsdatei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kardinalitten fr Datenbankbeziehungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Annotationen zur Modellierung von Datenbankreferenzen . . . . . . . . . . . Attribute der Annotationen fr Datenbankreferenzen . . . . . . . . . . . . . . . . . Klassen von IP-Adressen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Standard-Port-Nummern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste wichtiger RFCs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wichtige Permission-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Geschwindigkeit von Methodenaufrufen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameter von hprof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von javac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen des Java-Interpreters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von appletviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kommandos von jdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Markierungen in Dokumentationskommentaren . . . . . . . . . . . . . . . . . . . . . . Einige Optionen von javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kommandos von jar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von javap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von serialver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von jarsigner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Optionen von rmic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1053 1105 1110 1110 1112 1128 1131 1131 1146 1148 1149 1224 1260 1269 1278 1280 1282 1284 1286 1288 1289 1291 1292 1293 1294
1311
Listingverzeichnis
Listing 2.1 Listing 2.2 Listing 2.3 Listing 2.4 Listing 2.5 Listing 2.6 Listing 2.7 Listing 4.1 Listing 4.2 Listing 4.3 Listing 4.4 Listing 4.5 Listing 4.6 Listing 4.7 Listing 4.8 Listing 4.9 Listing 4.10 Listing 4.11 Listing 4.12 Listing 4.13 Listing 5.1 Listing 5.2 Listing 5.3 Listing 5.4
Hello, world . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Einfache Ausgaben . . . . . . . . . . . . . . . . . . . . 66 Einfache Eingaben . . . . . . . . . . . . . . . . . . . . . 67 Einrcken von Klassen und Methoden 68 Einrcken von Kontrollanweisungen 69 Einrcken fortgesetzter Anweisungen 69 Einrcken langer Methodenaufrufe . . 69 Verwendung eines Dokumentationskommentars im Java-API . . . . . . . . . . . . . 96 Einfache Variablen ausgeben . . . . . . . . 103 Initialisieren von Variablen . . . . . . . . . . 103 Deklaration von Arrays . . . . . . . . . . . . . . 104 Erzeugen von Arrays . . . . . . . . . . . . . . . . . 105 Deklaration und Initialisierung von Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Initialisierung mit literalen Arrays . . 105 Deklaration und Zugriff auf Arrays . 105 Zugriff auf mehrdimensionale Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Ein nichtrechteckiges Array . . . . . . . . . 107 Erzeugen eines Objekts mit dem new-Operator . . . . . . . . . . . . . . . . . . . . . . . . . 109 Umwandlung zwischen int, byte und char . . . . . . . . . . . . . . . . . . . . . . . . . 112 Anwendung der Klasse ByteKit . . . . . 113 Fehler beim Kompilieren durch unvollstndige Initialisierung . . . . . . . 116 Fehler beim Kompilieren durch unvollstndige Datenflussanalyse . . . 117 String-Verkettung . . . . . . . . . . . . . . . . . . . . 123 Vorsicht bei der String-Verkettung! . 124
Listingverzeichnis
Listing 5.5 Listing 5.6 Listing 5.7 Listing 5.8 Listing 5.9 Listing 6.1 Listing 6.2 Listing 6.3 Listing 6.4 Listing 6.5 Listing 6.6 Listing 6.7 Listing 6.8 Listing 6.9 Listing 6.10 Listing 6.11 Listing 7.1 Listing 7.2 Listing 7.3 Listing 7.4 Listing 7.5 Listing 7.6 Listing 7.7 Listing 7.8 Listing 7.9 Listing 7.10 Listing 7.11 Listing 7.12 Listing 7.13 Listing 7.14 Listing 7.15 Listing 7.16 Listing 7.17 Listing 7.18 Listing 7.19 Listing 8.1 Listing 8.2 Listing 8.3 Listing 8.4 Listing 8.5 Listing 8.6 Listing 8.7
1314
Korrekte String-Verkettung bei gemischten Ausdrcken . . . . . . . . . . . . . . . Vergleichen von Referenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergleichen von Strings mit equals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bindungsprobleme bei den bitweisen Operatoren . . . . . . . . . . . . . . . . . . . . . . Korrekte Klammerung von bitweisen Operatoren . . . . . . . . . . . . . . . . . . . . . . Verdecken von Klassen- oder Instanzvariablen . . . . . . . . . . . . . . . . . . . . . . . . . Dangling else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dangling else, ausgeschaltet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bedingtes Kompilieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Duff's Device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das gelabelte break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der erweiterten for-Schleife auf Collections . . . . . . . . . . . . . . . Anwendung der erweiterten for-Schleife auf Arrays . . . . . . . . . . . . . . . . . . . . Anwendung von Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung einer IllegalArgumentException . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung von Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine einfache Klassendefinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen eines Objekts mit new . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kombinierte Deklaration und Initialisierung einer Objektvariablen . . . . Zuweisen von Werten an die Variablen eines Objekts . . . . . . . . . . . . . . . . . . Lesender Zugriff auf die Variablen eines Objekts . . . . . . . . . . . . . . . . . . . . . . . Eine einfache Methode zur Altersberechnung . . . . . . . . . . . . . . . . . . . . . . . . . . . Aufruf einer Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Methode zur Ausgabe des Alters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wiederholter Aufruf der Methode zur Ausgabe des Alters . . . . . . . . . . . . Eine Methode mit einer variablen Parameterliste . . . . . . . . . . . . . . . . . . . . . . . Die Anwendung von Object... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . berladen einer Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Definition eines parametrisierten Konstruktors . . . . . . . . . . . . . . . . . . . . . . . . . Aufruf eines parametrisierten Konstruktors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Klasse mit mehreren Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verkettung von Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Initialisierungsreihenfolge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die finalize-Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfaches Beispiel fr Vererbung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf geerbte Membervariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ableitung einer abgeleiteten Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf mehrfach vererbte Membervariablen . . . . . . . . . . . . . . . . . . . . . . . . berlagern einer Methode in einer abgeleiteten Klasse . . . . . . . . . . . . . . . . . Zugriff auf fremde private Membervariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . Realisierung eines Instanzenzhlers mit Klassenvariablen . . . . . . . . . . . . . .
124 125 125 130 130 134 136 136 137 138 141 143 143 145 147 148 163 163 164 164 164 165 165 166 166 166 167 168 170 171 171 172 172 173 174 178 178 178 178 180 184 187
Listingverzeichnis
Listing 8.8 Listing 8.9 Listing 8.10 Listing 8.11 Listing 8.12 Listing 8.13 Listing 9.1 Listing 9.2 Listing 9.3 Listing 9.4 Listing 9.5 Listing 9.6 Listing 9.7 Listing 9.8 Listing 9.9 Listing 9.10 Listing 9.11 Listing 9.12 Listing 9.13 Listing 9.14 Listing 9.15 Listing 9.16 Listing 9.17 Listing 9.18 Listing 10.1 Listing 10.2 Listing 10.3 Listing 10.4 Listing 10.5 Listing 10.6 Listing 10.7 Listing 10.8 Listing 10.9 Listing 10.10 Listing 10.11 Listing 10.12 Listing 10.13 Listing 10.14 Listing 10.15 Listing 10.16 Listing 10.17 Listing 10.18
Verwendung von Klassenvariablen zur Definition von Konstanten . . . Verwendung von Math.sqrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Definition eines statischen Initialisierers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abstrakte Klassen und Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einfgen einer neuen Mitarbeiterklasse in die Gehaltsberechnung . . . . Polymorphe Methodenaufrufe im Konstruktor . . . . . . . . . . . . . . . . . . . . . . . . . . Definition eines Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung eines Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse FussballPlatz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse PapierBlatt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung eines Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der instanceof-Operator auf Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Interface Comparable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung mehrerer Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erben von Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ableiten von Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Konstanten in Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung einer tiefen Kopie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Interface DoubleMethod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Funktionszeiger mit Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das SimpleTreeNode-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Default-Implementierung des SimpleTreeNode-Interfaces . . . . . . . . . . . . . Implementierung des SimpleTreeNode-Interface durch Delegation . . . Eine nichtstatische lokale Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Definition einer lokalen Klasse in einer Methode . . . . . . . . . . . . . . . . . . . . . . . Anwendung anonymer Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung statischer lokaler Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Wrapper-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Call by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Autoboxing und Autounboxing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung von Aufzhlungstypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erweiterung von Aufzhlungstypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung eines Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung eines Immutable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Klasse mit einer Factory-Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Factory-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine abstrakte Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung eines Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Delegate-/Delegator-Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Composite-Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Visitor-Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
188 189 190 192 194 195 197 198 199 199 201 202 203 204 205 206 207 208 209 211 211 213 213 215 218 220 221 222 225 227 228 230 232 235 236 238 239 241 245 248 251 254
1315
Listingverzeichnis
Listing 10.19 Listing 11.1 Listing 11.2 Listing 11.3 Listing 11.4 Listing 11.5 Listing 11.6 Listing 11.7 Listing 12.1 Listing 12.2 Listing 12.3 Listing 12.4 Listing 12.5 Listing 12.6 Listing 12.7 Listing 12.8 Listing 12.9 Listing 13.1 Listing 13.2 Listing 13.3 Listing 13.4 Listing 13.5 Listing 13.6 Listing 13.7 Listing 13.8 Listing 13.9 Listing 13.10 Listing 13.11 Listing 13.12 Listing 14.1 Listing 14.2 Listing 14.3 Listing 14.4 Listing 15.1 Listing 15.2 Listing 15.3 Listing 15.4 Listing 15.5 Listing 15.6 Listing 15.7 Listing 15.8 Listing 15.9
1316
Das Observer-Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . String-Verkettung und die Methode substring . . . . . . . . . . . . . . . . . . . . . . . . . . Die Methode regionMatches der Klasse String . . . . . . . . . . . . . . . . . . . . . . . . . . Zerlegen von Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung der String-Verkettung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von beliebigen Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Formatierte Zahlenausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Formatierte Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die try-catch-Anweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Programm mit einem Laufzeitfehler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abfangen des Laufzeitfehlers mit einer try-catch-Anweisung . . . . . . . . . . Verwendung des Fehlerobjekts nach einem Laufzeitfehler . . . . . . . . . . . . . Fortfahren nach Laufzeitfehlern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mehr als eine catch-Klausel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der finally-Klausel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der throws-Klausel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Auslçsen einer Ausnahme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf verdeckte Membervariablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Versehentliches Verdecken einer Membervariable . . . . . . . . . . . . . . . . . . . . . . Die Klasse A des Pakets demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse B des Pakets demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse C des Pakets demo.tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klassen aus selbst definierten Paketen . . . . . . . . . . . . . . . Einen InputStream zu einer Ressourcen-Datei beschaffen . . . . . . . . . . . . . . Laden einer Textressource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laden einer Image-Ressource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine WebStart-Deskriptordatei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die HTML-Datei zum Aufruf der WebStart-Applikation . . . . . . . . . . . . . . . Ein Beispielprogramm fr das jnlp-API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Methode elements der Klasse Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung eines Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Klasse Hashtable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Konstruktion von Primzahlen mit der Klasse BitSet . . . . . . . . . . . . . . . . . . . . Anlegen und Bearbeiten zweier Listen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf eine Collection mit einem Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . Generierung eines Lottotipps mit HashSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Klasse HashMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse TreeSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rckwrts sortieren mit einem Comparator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sortieren einer Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine untypisierte Sortiermethode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die typsichere Version der Sortiermethode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
259 268 269 271 274 278 279 281 286 286 287 288 290 291 292 293 295 298 299 310 310 310 311 320 320 321 324 327 332 338 340 343 346 354 356 359 362 366 367 369 372 372
Listingverzeichnis
Listing 15.10 Listing 15.11 Listing 15.12 Listing 15.13 Listing 15.14 Listing 15.15 Listing 15.16 Listing 15.17 Listing 15.18 Listing 16.1 Listing 16.2 Listing 16.3 Listing 16.4 Listing 16.5 Listing 16.6 Listing 16.7 Listing 16.8 Listing 16.9 Listing 16.10 Listing 17.1 Listing 17.2 Listing 17.3 Listing 17.4 Listing 17.5 Listing 17.6 Listing 17.7 Listing 17.8 Listing 17.9 Listing 17.10 Listing 17.11 Listing 17.12 Listing 17.13 Listing 17.14 Listing 17.15 Listing 18.1 Listing 18.2 Listing 18.3 Listing 18.4 Listing 18.5 Listing 18.6 Listing 18.7 Listing 18.8
Die vereinfachte Version der typsicheren Variante . . . . . . . . . . . . . . . . . . . . . . Ein untypisierter Wortzhler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die 5.0-Wortzhlervariante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine eigene typisierte Listenklasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Funktionierendes Zusammenspiel von Ober- und Unterklassen . . . . . . . Nicht funktionierendes Zusammenspiel von Ober- und Unterklassen . Nicht funktionierende Ausgabe der Zahlenliste . . . . . . . . . . . . . . . . . . . . . . . . . Funktionierende Ausgabe der Zahlenliste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verbesserte funktionierende Ausgabe der Zahlenliste . . . . . . . . . . . . . . . . . . Zufallszahlen zur Generierung eines Lottotipps . . . . . . . . . . . . . . . . . . . . . . . . Die Felder der Klasse Calendar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Datumsarithmetik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgeben der System-Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Auflçsung des System-Timers bestimmen . . . . . . . . . . . . . . . . . . . . . . . . . . Die Auflçsung von Thread.sleep bestimmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von System.arraycopy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Starten von notepad.exe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Starten externer Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sortieren eines Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Regulre Ausdrcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kurzer Zeichenketten-Vergleich mit regulren Ausdrcken . . . . . . . . . . . Strings und regulre Ausdrcke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zerlegen von Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Klasse BigInteger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Klasse BigDecimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Darstellung einiger Locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung von DecimalFormat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung von DateFormat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse SimpleTextResource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Basisvariante MyTextResource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die deutschsprachige Variante MyTextResource_de . . . . . . . . . . . . . . . . . . . . Die schweizerische Variante MyTextResource_de_CH . . . . . . . . . . . . . . . . . Test von MyTextResource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die englische Variante MyTextResource_en . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erstellen einer Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Gepufferte Ausgabe in eine Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Schachteln von Writer-Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse PrintWriter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Konstruktion einer eigenen FilterWriter-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Klasse FileReader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse StringReader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eingabepufferung beim Lesen aus Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
373 374 374 375 379 380 381 381 382 386 390 394 398 400 402 404 405 407 410 414 415 416 416 420 423 426 428 431 433 434 434 435 435 437 443 446 446 448 449 454 455 457
1317
Listingverzeichnis
Listing 18.9 Listing 19.1 Listing 19.2 Listing 19.3 Listing 19.4 Listing 19.5 Listing 19.6 Listing 19.7 Listing 20.1 Listing 20.2 Listing 21.1 Listing 21.2 Listing 21.3 Listing 21.4 Listing 21.5 Listing 21.6 Listing 21.7 Listing 22.1 Listing 22.2 Listing 22.3 Listing 22.4 Listing 22.5 Listing 22.6 Listing 22.7 Listing 22.8 Listing 22.9 Listing 22.10 Listing 22.11 Listing 22.12 Listing 22.13 Listing 22.14 Listing 23.1 Listing 23.2 Listing 23.3 Listing 23.4 Listing 23.5 Listing 23.6 Listing 23.7 Listing 23.8 Listing 23.9 Listing 23.10 Listing 23.11
1318
Die Klasse LineNumberReader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung eines FileOutputStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse DataOutputStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erstellen eines ZIP-Archivs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kopieren einer Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse DataInputStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Berechnung der Adler-32-Prfsumme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Entpacken eines ZIP-Archivs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lesen einer .class-Datei mit der Klasse RandomAccessFile . . . . . . . . . . . . . Spiegeln einer Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modifikationsdatum einer Datei ausgeben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Interface DirectoryVisitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein DirectoryVisitor zum Ausdrucken eines Verzeichnisses . . . . . . . . . . . Die Klasse DirectorySizeVisitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rekursiver Durchlauf von Verzeichnissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anlegen einer temporren Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher Thread mit einem Zhler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Beenden des Thread durch Aufruf von stop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendung der Methoden interrupt und isInterrupted . . . . . . . . . . . . . . . . Implementieren von Runnable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Klasse zur Primfaktorzerlegung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse zur Primfaktorzerlegung . . . . . . . . . . . . . . . . . . . . . . Primfaktorzerlegung mit Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse zur Primfaktorzerlegung mit Threads . . . . . . . . Zwei Zhlerthreads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Synchronisation von Threads mit Klassenobjekten . . . . . . . . . . . . . . . . . . . . . . Eine unzureichend synchronisierte Zhlerklasse . . . . . . . . . . . . . . . . . . . . . . . . Synchronisieren der Zhlermethode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Producer-/Consumer-Beispiel mit wait und notify . . . . . . . . . . . . . . . . . Das Producer-/Consumer-Beispiel mit einer Pipe . . . . . . . . . . . . . . . . . . . . . . Ein einfaches Fenster erzeugen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse WindowClosingAdapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Schließen des Fensters ermçglichen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rahmenprogramm fr nachfolgende Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Linien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Rechtecken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe eines Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Kreisen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von Kreisbçgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe von gefllten Flchen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kopieren von Flchen mit copyArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
458 463 466 468 471 475 476 476 483 485 489 490 491 491 492 494 497 501 502 504 508 509 510 511 512 513 516 517 519 520 523 533 535 536 537 539 540 542 543 544 545 547
Listingverzeichnis
Listing 23.12 Listing 24.1 Listing 24.2 Listing 24.3 Listing 24.4 Listing 24.5 Listing 24.6 Listing 24.7 Listing 25.1 Listing 25.2 Listing 26.1 Listing 26.2 Listing 26.3 Listing 26.4 Listing 27.1 Listing 27.2 Listing 27.3 Listing 27.4 Listing 28.1 Listing 28.2 Listing 28.3 Listing 28.4 Listing 28.5 Listing 28.6 Listing 29.1 Listing 29.2 Listing 29.3 Listing 29.4 Listing 29.5 Listing 29.6 Listing 30.1 Listing 30.2 Listing 30.3 Listing 30.4 Listing 30.5 Listing 30.6 Listing 30.7 Listing 31.1 Listing 31.2 Listing 31.3 Listing 31.4 Listing 31.5
Verwendung der Clipping-Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einfache Textausgabe im Grafikfenster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgabe verschiedener Schriften . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Auflistung aller Standardschriften . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Auflistung der Standardschriften . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergrçßern der Schriftart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anzeige von Font-Metriken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zentrierte Textausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Darstellung des Farbenkreises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Systemfarben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausdruck einer Testseite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse FilePrintHelper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse SimpleFilePrinter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Druckausgabe an LPT1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anzeigen und Entfernen eines Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher Bildschirmschoner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anzeigezustand eines Fensters umschalten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Programm mit vernderten Fensterelementen . . . . . . . . . . . . . . . . . . . . . . Basisprogramm fr den Nachrichtentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementieren eines Listener-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung lokaler Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung einer anonymen Klasse als Ereignishandler . . . . . . . . . . . . . . Trennung von GUI- und Anwendungslogik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . berlagern der Komponenten-Event-Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse CloseableFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das eigene Fenster aus der Vogelperspektive . . . . . . . . . . . . . . . . . . . . . . . . . . . Reaktion auf Mausklicks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zeichnen von Rechtecken durch Ziehen der Maus . . . . . . . . . . . . . . . . . . . . . . Behandlung von Fokus-Ereignissen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Reaktion auf Tastaturereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen von Mens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen eines Meneintrags mit Beschleuniger . . . . . . . . . . . . . . . . . . . . . . . . Menleisten mit zwei Mens und Beschleunigertasten . . . . . . . . . . . . . . . . . Geschachtelte Mens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Reaktion auf Action-Events aus einem Men . . . . . . . . . . . . . . . . . . . . . . . . . . . Einbinden eines Kontextmens im AWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kommunikation mit der Zwischenablage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Dialog mit zwei Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse FlowLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse GridLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das BorderLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Umgang mit GridBagLayout und GridBagConstraints . . . . . . . . . . . . . . . . .
549 552 555 556 557 558 560 561 565 568 575 584 586 591 598 600 601 605 619 620 623 624 626 628 634 636 641 643 647 652 661 664 665 666 669 674 678 683 686 687 690 692
1319
Listingverzeichnis
Listing 31.6 Listing 31.7 Listing 31.8 Listing 31.9 Listing 31.10 Listing 31.11 Listing 32.1 Listing 32.2 Listing 32.3 Listing 32.4 Listing 32.5 Listing 32.6 Listing 32.7 Listing 32.8 Listing 32.9 Listing 32.10 Listing 32.11 Listing 32.12 Listing 32.13 Listing 32.14 Listing 32.15 Listing 32.16 Listing 33.1 Listing 33.2 Listing 34.1 Listing 34.2 Listing 34.3 Listing 34.4 Listing 34.5 Listing 34.6 Listing 34.7 Listing 34.8 Listing 34.9 Listing 34.10 Listing 34.11 Listing 34.12 Listing 34.13 Listing 34.14 Listing 34.15 Listing 35.1 Listing 36.1 Listing 36.2
1320
Beispiel fr GridBagLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anordnen von Dialogelementen ohne Layoutmanager . . . . . . . . . . . . . . . . . Schachteln von Layoutmanagern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine weitere Anwendung fr geschachtelte Layoutmanager . . . . . . . . . . . Konstruktion modaler Dialoge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Drei modale Standarddialoge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rahmenprogramm fr Dialogelemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Label-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Checkbox-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Behandlung von Item-Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung einer CheckboxGroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Textfeldern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Behandlung von Text-Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Textfelder mit Beschriftung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Behandlung von Text-Events bei der Komponente TextArea . . . . . . . . . . . Verwendung einer TextArea-Komponente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Behandlung der Ereignisse einer Choice-Komponente . . . . . . . . . . . . . . . . . . Verwendung einer Choice-Komponente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Behandlung der Ereignisse einer List-Komponente . . . . . . . . . . . . . . . . . . . . . Verwendung einer List-Komponente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Scrollbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse ScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine 7-Segment-Anzeige . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einbinden der 7-Segment-Anzeige . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laden einer Bitmap-Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laden und Anzeigen einer Bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Programm zum Laden und Anzeigen einer Bitmap . . . . . . . . . . . . . . . . . . . . . Eine Komponente zum Anzeigen einer Bitmap . . . . . . . . . . . . . . . . . . . . . . . . . Verwenden der Bitmap-Komponente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein animierter Zhler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von Threads zur Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abspielen einer Folge von Bitmaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die animierte Schlange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bildschirmflackern reduzieren bei stehenden Animationen . . . . . . . . . . . . Standard-Implementierung von update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modifizierte Version von update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modifizierte Schlangenanimation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . update-Methode mit Doppelpufferung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Animation mit Doppelpufferung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfaches Swing-Beispielprogramm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Klasse JFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anordnen von Dialogelementen in einem Hauptfenster . . . . . . . . . . . . . . . .
695 698 699 700 703 706 712 715 717 718 719 722 722 723 724 725 727 727 729 730 732 736 745 749 754 754 756 757 758 760 762 764 767 772 774 775 775 778 778 791 799 802
Listingverzeichnis
Listing 36.3 Listing 36.4 Listing 36.5 Listing 36.6 Listing 36.7 Listing 36.8 Listing 36.9 Listing 36.10 Listing 36.11 Listing 36.12 Listing 36.13 Listing 37.1 Listing 37.2 Listing 37.3 Listing 37.4 Listing 37.5 Listing 37.6 Listing 37.7 Listing 37.8 Listing 37.9 Listing 37.10 Listing 37.11 Listing 37.12 Listing 37.13 Listing 37.14 Listing 38.1 Listing 38.2 Listing 38.3 Listing 38.4 Listing 38.5 Listing 38.6 Listing 38.7 Listing 38.8 Listing 38.9 Listing 38.10 Listing 38.11 Listing 38.12 Listing 38.13 Listing 39.1 Listing 39.2 Listing 39.3 Listing 39.4
Ein einfacher SplashScreen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendungsbeispiel fr JOptionPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anwendungsbeispiel fr JApplet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . HTML-Datei fr JApplet-Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JInternalFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Swing-Programm mit einem einfachen Men . . . . . . . . . . . . . . . . . . . . . . . Weitere Mçglichkeiten von Swing-Mens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anzeigen eines Kontextmens in Swing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Debug-Grafik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein transparenter Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Registrieren von Tastaturkommandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JLabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTextField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTextArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSpinner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse DefaultButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse CancelButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JCheckbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JRadioButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JComboBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JScrollBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSlider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JScrollPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JSplitPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse JTabbedPane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine einfache Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Interface TableData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Modell fr schwach besetzte Tabellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine JTable mit einer Million Zellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine JTable mit einem eigenen Spaltenmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein eigener Zellrenderer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Tabelle mit einem eigenen Zellrenderer . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfacher JTree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein JTree mit TreeSelectionListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einfgen, ndern und Lçschen in einem Baum . . . . . . . . . . . . . . . . . . . . . . . . . Ein einfaches Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung von getParameterInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Methode getAppletInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das APPLET-Tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
804 810 812 812 815 820 824 827 832 833 837 842 845 848 850 852 853 853 855 857 861 864 867 870 873 879 883 887 889 890 897 899 901 904 905 910 913 916 927 927 928 928
1321
Listingverzeichnis
Listing 39.5 Listing 39.6 Listing 39.7 Listing 39.8 Listing 39.9 Listing 39.10 Listing 40.1 Listing 40.2 Listing 40.3 Listing 40.4 Listing 40.5 Listing 40.6 Listing 40.7 Listing 40.8 Listing 40.9 Listing 41.1 Listing 41.2 Listing 41.3 Listing 41.4 Listing 41.5 Listing 41.6 Listing 41.7 Listing 41.8 Listing 41.9 Listing 41.10 Listing 41.11 Listing 42.1 Listing 42.2 Listing 42.3 Listing 42.4 Listing 42.5 Listing 42.6 Listing 42.7 Listing 42.8 Listing 42.9 Listing 42.10 Listing 42.11 Listing 42.12 Listing 43.1 Listing 43.2 Listing 43.3 Listing 43.4
1322
Ein parametrisiertes Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930 Die HTML-Datei zum Schranken-Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931 Das sprechende Hello, World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934 Soundausgabe aus einer Applikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935 Das Wolkenkratzer-Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938 Die HTML-Datei zum Aufrufen des Wolkenkratzer-Applets . . . . . . . . . . . 942 Laden von Webseiten aus einem Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946 Die HTML-Datei zum Laden der Webseiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948 Die Klasse ChgNextApplet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950 Die HTML-Datei mit den drei kommunizierenden Applets . . . . . . . . . . . . 951 Die Calculator-Applikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952 Ein Applikations-Applet im Popup-Fenster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954 HTML-Datei zum Aufruf des Beispiel-Applets . . . . . . . . . . . . . . . . . . . . . . . . . . 954 Das gleichwertige Calculator-Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 956 HTML-Datei zum Aufruf des Beispiel-Applets . . . . . . . . . . . . . . . . . . . . . . . . . . 956 Eine serialisierbare Uhrzeitklasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965 Serialisieren eines Time-Objekts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 966 Serialisieren mehrerer Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 967 Deserialisieren eines Time-Objekts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 968 Deserialisieren mehrerer Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 970 Die Uhrzeitklasse mit serialVersionUID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 Die Klasse Person . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 Serialisieren von Objekten und Referenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 Ein einfacher Objektspeicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 979 Beispielanwendung fr den einfachen Objektspeicher . . . . . . . . . . . . . . . . . . 980 Kopieren von Objekten durch Serialisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 Behandeln einer SQLException . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996 Das Rahmenprogramm der DirDB-Datenbank . . . . . . . . . . . . . . . . . . . . . . . . . . 998 ffnen und Schließen der DirDB-Datenbank . . . . . . . . . . . . . . . . . . . . . . . . . . . 1000 Anlegen der DirDB-Tabellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1002 Fllen der DirDB-Tabellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004 Anzahl der Stze in der DirDB-Datenbank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1006 Suchen nach Dateien in der DirDB-Datenbank . . . . . . . . . . . . . . . . . . . . . . . . . 1007 Suchen nach Verzeichnissen in der DirDB-Datenbank . . . . . . . . . . . . . . . . . 1008 Sortieren der Ergebnismenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1009 Cluster-Berechnung mit der DirDB-Datenbank . . . . . . . . . . . . . . . . . . . . . . . . 1010 Die Klasse CachedConnection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1014 Verwenden eines PreparedStatement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1017 Dynamisches Laden von Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1025 Testcode in der main-Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1027 Die Klasse Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1030 Die Klasse TestQueue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032
Listingverzeichnis
Listing 43.5 Listing 43.6 Listing 43.7 Listing 43.8 Listing 43.9 Listing 43.10 Listing 43.11 Listing 43.12 Listing 43.13 Listing 43.14 Listing 43.15 Listing 43.16 Listing 43.17 Listing 43.18 Listing 43.19 Listing 44.1 Listing 44.2 Listing 44.3 Listing 44.4 Listing 44.5 Listing 44.6 Listing 44.7 Listing 44.8 Listing 44.9 Listing 44.10 Listing 44.11 Listing 44.12 Listing 44.13 Listing 45.1 Listing 45.2 Listing 45.3 Listing 45.4 Listing 45.5 Listing 45.6 Listing 45.7 Listing 45.8 Listing 45.9 Listing 45.10 Listing 45.11 Listing 45.12 Listing 45.13 Listing 45.14
Funktionszeiger mit Reflection nachbilden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parametrisierte Konstruktoren mit Reflection aufrufen . . . . . . . . . . . . . . . . Die Klasse PrintableObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen von Arrays per Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf Array-Elemente per Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine einfache Annotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verwendung der Annotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Annotation mit einer Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zuweisen von annotierten Werten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zuweisen von annotierten Werten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Komplexe Annotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zuweisen von annotierten Werten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Komplexe Annotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einschrnken der Verwendbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vollstndige Annotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Deklaration der Klasse LightBulb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laden einer Image-Ressource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Bean zur Anzeige einer Glhbirne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einbinden einer einfachen Bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einbinden einer serialisierten Bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein beleuchteter Taster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein Veto-Schalter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eigenschaftennderungen von Beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse ButtonPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse LightBulbBeanInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse LightBulbLightOnEditor1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse LightBulbLightOnEditor2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse LightBulbLightOnEditor3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine Klasse fr die dir-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Annotierte Klasse fr die dir-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Konfigurationsdatei fr das Java Persistenz API . . . . . . . . . . . . . . . . . . . . . . . Zugriff auf den EntityManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Transaktionen im EntityManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anlegen eines Datensatzes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Laden eines Datensatzes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lçschen eines Datensatzes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Zweite Java Bean zum Abbilden der Tabelle dir . . . . . . . . . . . . . . . . . . . . . . . Mit Annotationen angereicherte Java Bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Java Bean zur Abbildung der Tabelle file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Konfigurationsdatei fr das Java Persistenz API . . . . . . . . . . . . . . . . . . . . . . . Anlegen eines Datensatzes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modellieren von 1:N-Referenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1033 1037 1039 1042 1046 1048 1049 1049 1049 1050 1050 1051 1051 1052 1053 1059 1060 1062 1065 1073 1076 1081 1084 1086 1092 1095 1096 1098 1106 1108 1111 1113 1114 1116 1117 1118 1119 1122 1123 1125 1126 1128
1323
Listingverzeichnis
Listing 45.15 Listing 45.16 Listing 45.17 Listing 45.18 Listing 45.19 Listing 45.20 Listing 46.1 Listing 46.2 Listing 46.3 Listing 46.4 Listing 46.5 Listing 46.6 Listing 46.7 Listing 46.8 Listing 46.9 Listing 46.10 Listing 47.1 Listing 47.2 Listing 47.3 Listing 47.4 Listing 47.5 Listing 47.6 Listing 48.1 Listing 48.2 Listing 48.3 Listing 48.4 Listing 48.5 Listing 48.6 Listing 48.7 Listing 48.8 Listing 48.9 Listing 48.10 Listing 49.1 Listing 49.2 Listing 49.3 Listing 49.4 Listing 50.1 Listing 50.2 Listing 50.3 Listing 50.4 Listing 50.5 Listing 50.6
1324
Modellieren von 1:N-Referenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anlegen mehrerer verknpfter Datenstze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Suche nach Datenstzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Suche nach Datenstzen mit einer Where-Klausel . . . . . . . . . . . . . . . . . . . . . Suche nach Datenstzen mit einer Where-Klausel . . . . . . . . . . . . . . . . . . . . . Suche nach Datenstzen mit benannten Anfragen . . . . . . . . . . . . . . . . . . . . . IP-Adressenauflçsung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abfrage des DayTime-Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lesender und schreibender Zugriff auf einen Socket . . . . . . . . . . . . . . . . . . Laden einer Seite von einem Web-Server (HTTP 1.0) . . . . . . . . . . . . . . . . . . Laden einer Seite von einem Web-Server (HTTP 1.1) . . . . . . . . . . . . . . . . . . Laden einer Seite von einem Web-Server ber java.net.URL . . . . . . . . . . Ein ECHO-Server fr Port 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine verbesserte Version des Echo-Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein experimenteller Web-Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Daten von einem URL lesen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Remote-Interface fr den Uhrzeit-Service . . . . . . . . . . . . . . . . . . . . . . . . . . Das TimeStore-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementierung des Uhrzeit-Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Registrierung von Remote-Objekten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der TimeService-Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Klasse MyTimeStore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verschlsselung durch Substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verschlsselung mit Exklusiv-ODER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erstellen eines Message Digest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erzeugen kryptografischer Zufallszahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Erstellen einer digitalen Unterschrift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Verifizieren einer digitalen Unterschrift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ein unerlaubtes Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vorlufige HTML-Datei zum Aufruf des unerlaubten Applets . . . . . . . Aufruf des signierten Applets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ausgeben des System-Property user.name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abspielen einer Sample-Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Alle meine Entchen – erster Versuch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Alle meine Entchen mit dem Sequenzer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Abspielen einer Midi-Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Langsame String-Verkettung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wie der Java-Compiler String-Verkettungen bersetzt . . . . . . . . . . . . . . . . Performante String-Verkettungen mit StringBuilder.append . . . . . . . . . . Langsames Einfgen in einen String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Schnelles Einfgen in einen String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergleich von Listen und Vektoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1131 1134 1135 1137 1138 1140 1151 1154 1155 1159 1161 1162 1164 1165 1167 1175 1183 1183 1184 1186 1189 1190 1197 1197 1200 1204 1211 1212 1217 1219 1220 1226 1235 1241 1245 1247 1255 1255 1256 1257 1257 1262
Listingverzeichnis
Listing 50.7 Listing 50.8 Listing 50.9 Listing 50.10 Listing 51.1
Performance von Writer und OutputStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . Gepufferter Zugriff auf Random-Access-Dateien . . . . . . . . . . . . . . . . . . . . . . Ein Beispielprogramm zum Testen des Profilers . . . . . . . . . . . . . . . . . . . . . . . Das verbesserte Programm nach der Profiler-Sitzung . . . . . . . . . . . . . . . . . . HTML mit ARCHIVE-Tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1264 1265 1268 1273 1290
1325
Stichwortverzeichnis
! <APPLET> 928 /* 96 /** 96, 1285 // 96 2D-API 553, 789 7-Segment-Anzeige 742 100 % Pure Java Initiative 38 ?-Wildcard 380 @author 96, 1286 @Column 1110 @deprecated 1279, 1286 @Entity 1110, 1123 @exception 96, 1286 @GeneratedValue 1123 @Id 1110, 1123 @ManyToMany 1131 @ManyToOne 1131–1131 @NamedQuery 1140 @OneToMany 1130–1131 @OneToOne 1131 @OrderBy 1130 @param 96, 1286 @return 96, 1286 @see 96, 1286 @since 1286 @Table 1110, 1123 @version 96, 1286
A Abgeleitete Klasse 158 Abhngigkeiten zwischen den Quelldateien 1278 Ableiten einer Klasse 177 Ableitungsbume 159 abs 386, 418–419 absbottom 930 absmiddle 930 abstract 191, 200
Stichwortverzeichnis Abstract Windowing Toolkit 46, 531 AbstractButton 796, 852 AbstractList 350, 353 AbstractMap 362 AbstractSet 359 AbstractSpinnerModel 850 AbstractTableModel 897 Abstrakte Factory 240 Abstrakte Klassen und Polymorphismus 191 Abstraktion 156 Accelerator-Taste 819 accept 490, 1163 Accessibility-API 789 acos 417 action 610 Action-Ereignisse 617 ActionEvent 611, 617, 669, 716 ACTION_EVENT_MASK 628 Action-Events 668 ActionListener 617, 658, 669, 716 actionPerformed 617, 669, 716 activeCaption 567 activeCaptionBorder 567 activeCaptionText 567 activeCount 527 Adapterklasse 610, 614 add 352, 358, 394, 419, 658–659, 682, 685, 711, 725, 817–817, 823, 826, 909, 1244 addActionListener 617, 669, 716, 819 addAdjustmentListener 618, 732, 866 addAll 352 addChangeListener 870 addColumnSelectionInterval 894 addComponentListener 616, 636 addContainerListener 616 addElement 337 addFocusListener 614, 647 addImage 755 addItem 726, 864 addItemListener 618, 717, 726 Addition 117 addJMenuBar 817 addKeyListener 601, 615, 621, 649 addListSelectionListener 861 addMouseListener 615 addMouseMotionListener 616 addPoint 541 addPropertyChangeListener 1075 addRowSelectionInterval 894
1328
addSelectionInterval 860 addSelectionPath 914 addSelectionPaths 914 addSeparator 659, 817, 826 addTab 885 addTableModelListener 896 addTextListener 618, 722 addTreeSelectionListener 912 addVetoableChangeListener 1080 addWindowListener 536, 538, 617, 633 Adjustable 731, 735 Adjustment-Ereignisse 618, 732 AdjustmentEvent 611, 618, 732 ADJUSTMENT_EVENT_MASK 628 AdjustmentListener 618, 732 adjustmentValueChanged 618, 732 Adler32 475 after 394 Aggregation 160 aiff-Format 47, 933, 1231 ALAW 1237 Alexander, Christopher 233 Aliasing 1258 ALIGN 930 ALL 1021 AllPermission 1224 ALT 929 ALTER TABLE 1018 AM_PM 389 anchor 693 and 346, 1020 andNot 346 Andreessen, Marc 37 Anhalten eines Threads 505 Animation 759, 936 Anlegen eines Fensters 533 Annotation 1047, 1108, 1110 Anonyme Klassen 624 ant 315 Anweisungen 93, 133, 297 Anweisungsobjekt 992 Anwendungsprotokolle 1144 ANY 1021 Apache-Server 1160 API 82 append 276, 584, 724, 1256 Applet 302, 595, 923, 1282 AppletContext 329, 945 Applet-Kontext 944
Stichwortverzeichnis Applets 45, 302, 921, 921, 923, 925–926, 943 AppletSecurityException 955 APPLET-Tag 45, 928, 1290 appletviewer 64, 302, 932, 944, 1281, 1281 Application Programming Interface 82 application/octet-stream 1173 application/x-java-jnlp-file 323, 326, 1173 Applikationen 301 Applikations-Server 989 applyPattern 427 ARCHIVE 929, 1220, 1290 Archivierungswerkzeug 1289 Arial 554 ArithmeticException 294 Arithmetische Operatoren 117 Array 104, 106, 1042 arraycopy 403 ArrayIndexOutOfBoundsException 403 ArrayList 350, 353, 1261 Arrays 410–411 ArrayStoreException 403 ASC 1021 asin 417 assert 40, 44, 144 assert-Anweisung 144 AssertionError 144 Assoziationen 160 Assoziativittsregeln 115 atan 417 ATM 1144 Attribute 157 au-Dateien 47 AudioClip 933 AudioFileFormat 1231 AudioFormat 1231 AudioInputStream 1233 AudioSystem 1231 au-Format 933, 1231 Aufruf einer Methode 165 Aufzhlungstypen 229 Ausdrucksanweisungen 135 Ausdrcke 44 Ausfhrungszeitpunkt 1058 Ausgabe von Sound 933 Ausgabe, einfache 66 Ausgabeformatierung 278 Ausgabe-Streams 441 Auslçsen einer Ausnahme 285, 294 Ausnahmen 263, 285
Auswertungsreihenfolge 116 -author 1288 Autoboxing 228 Auto-Commit-Modus 1012 Automatisches Speichermanagement 44 AUTO_RESIZE_ALL_COLUMNS 892 AUTO_RESIZE_LAST_COLUMN 892 AUTO_RESIZE_NEXT_COLUMN 892 AUTO_RESIZE_OFF 892 AUTO_RESIZE_SUBSEQUENT_COLUMNS 892 Autounboxing 228 available 470 AWT 46, 531 AWTEvent 611, 628 AWTPermission 1224
B Baratz, Alan 37 baseline 930 BasicService 329 Basisklasse 158 BDK 1066 Bean Development Kit 1066 Beanbox 1066 Bean-Customizer 1095 BeanInfo 1091 BeanInfo-Klasse 1091 Beans 1057 Bedingtes Kompilieren 137 before 394 Behandeln einer Ausnahme 285 Beschleunigertasten 663, 819 BETWEEN 1021 BevelBorder 829 Bezeichner 97 BigDecimal 418 BigInteger 418 Bildschirmflackern reduzieren 772 Binre Suche 370 binarySearch 370, 410 bind 1187 Bindungsregeln 115 Bitmap laden und anzeigen 753 BitmapComponent 757 BitSet 345 Bitweise Operatoren 120 black 564 _blank 945 Blobs 987
1329
Stichwortverzeichnis Bloch, Joshua 229 Block 133, 298 BLOCK_DECREMENT 732 BLOCK_INCREMENT 732 blue 564 bmp-Format 753 BOLD 555 Book 583 boolean 98, 99, 110, 136, 224, 224 BooleanControl 1234 Boolean.TYPE 1029 booleanValue 225 Bootstrap Classes 306 Bootstrap Loader 1061 Border 795 BorderFactory 795, 805 BorderLayout 689 Borland 38 BOTH 693 BOTTOM 822, 930 Bound Properties 1074 Bounded Wildcards 381 BPM 1244 break 44, 138, 140, 292 Breite eines Zeichens 559 BufferedInputStream 473, 1264 BUFFERED_OPTION 832 BufferedOutputStream 464, 1263 BufferedReader 453, 456 BufferedWriter 442, 445, 1263 Bug Parade 52, 85 Button 715 ButtonGroup 823, 857 ButtonModel 857 byte 98, 100, 223, 223 ByteArrayInputStream 472, 983 ByteArrayOutputStream 463, 983 Bytecode 313 Bytecode-Verifier 1215 Byte-Streams 440 ByteToCharConverter 454, 1265 Byte.TYPE 1029
C [C 1272, 1291 CA 1214 Csarische Verschlsselung 1197 Cafe 38 CAFEBABE 482
1330
Calendar 387, 396 call by reference 167, 227 call by value 166 Callback-Methoden 302 Call-Level-Interface 988 cancel 578 CancelButton 852 canRead 331, 489 Canvas 736, 741, 757 canWrite 331, 489 capacity 277 CardLayout 682 CaretListener 844 cascade 1131 CascadeType.ALL 1130 case 138 catch 286 catch-or-throw-Regel 293 ceil 418 CENTER 683, 686, 693, 714, 822 Certificate 1210 Certification Authority 1214 CGI-Script 944 ChangeEvent 870, 887 ChangeListener 870, 887 char 98–99, 99, 224, 265 Character 224 Character-Streams 440, 1263 Character.TYPE 1029 CharArrayReader 453 CharArrayWriter 442, 444, 444 charAt 267 CharSequence 277, 1259 CharToByteConverter 442, 1263 CHAR_UNDEFINED 651–652 charValue 225 charWidth 559 Checkbox 716 CheckboxGroup 718 CheckboxMenuItem 657, 660 CheckedInputStream 475 CheckedOutputStream 469 checkRead 1225 Checksum 475 Choice 725 class 163, 319, 1024 ClassCastException 677, 1024 .class-Dateien 311–312, 313, 482, 1278 classes.zip 306
Stichwortverzeichnis Classloader 45, 1027, 1060 .class-Notation fr Klassenobjekte 1034 ClassNotFoundException 1024 CLASSPATH 57, 73, 75, 305–308, 310, 317, 1278, 1280, 1288, 1291, 1294 clear 345, 361 clearRect 547 clearSelection 860, 894, 914 -client 1280 Client-Hotspot 1280 Client-Server-Beziehung 1147 Clip 1232 Clipboard 676 ClipboardOwner 678 ClipboardService 329 Clipping-Region 548 clipRect 548 clone 109, 167, 179, 209, 983 Cloneable 983 CloneNotSupportedException 209 close 441, 453, 462, 480, 992, 1235, 1240 Cluster 1010 CODE 928 CODEBASE 929 Coding Conventions 70 collapsePath 915 Collection 350 Collection-API 39, 49, 263, 349 Collections 368 Color 564 Column 1123 columnAtPoint 907 Comboboxen 725 commit 1012 CommPort 591 CommPortIdentifier 590 Community Source Licence 39 Comparable 202–202, 364 Comparator 364, 411 compare 364 compareTo 202, 269, 364 Compiler 1277 comp.lang.java 84 Component 595 ComponentAdapter 614 componentAdded 617 Component-Ereignisse 616 ComponentEvent 611, 616, 635 COMPONENT_EVENT_MASK 628, 744
Component-Events 635 componentHidden 616, 636 ComponentListener 616, 635 componentMoved 616, 636 componentRemoved 617 componentResized 616, 636 componentShown 616, 636, 745 ComponentUI 831 Composite-Pattern 250 CompoundBorder 829 CompoundControl 1234 com.sun.image.codec.jpeg 305 connect 523 Connection 992 Constrained Properties 1079 Constraints-Objekt 683 Constructor 1036 Container 595, 682 ContainerAdapter 614 Container-Ereignisse 616 ContainerEvent 616 ContainerListener 616 contains 342, 351 containsAll 351 containsKey 342, 361 containsValue 361 Content Handler Factories 1175 ContentPane 794, 800 CONTIGUOUS_TREE_SELECTION 911 continue 44, 140, 292 control 568, 1232, 1234 controlDkShadow 568 controlHighlight 568 controlLtHighlight 568 controlShadow 568 controlText 568 Control.Type 1234 CoolEdit 933 copyArea 547 CORBA 49, 305, 1181 cos 417 Courier 554 Courier New 554 -cp 75, 317, 1280 CRC32 475 CREATE INDEX 1018 CREATE TABLE 1018 createBevelBorder 805 createCompoundBorder 805
1331
Stichwortverzeichnis createCustomCursor 604 createEmptyBorder 830 createEtchedBorder 805 createImage 321, 754, 777 createLineBorder 830 createNewFile 497 createStatement 992 createTempFile 496 createToolTip 830 createTrack 1244 CROSSHAIR_CURSOR 604 currentTimeMillis 400 Cursor 603 cyan 564
D -d 318, 1281, 1288, 1294 -da 146 Dmon 501 Dangling else 136 darkGray 564 Data Definition Language 995 DatabaseMetaData 1001 DataFlavor 677 DataFlavors 676 DatagramPacket 1145 DatagramSocket 1145 DataInput 474 DataInputStream 465, 474 DataLine 1232 DataLine.Info 1237 DataOutput 465 DataOutputStream 465 Date 387, 396–396 DateFormat 430 Datei- und Verzeichnis-Handling 263, 487 Dateiformate 47–47, 60, 313, 753–753, 933–933, 1289 Datenbankzugriffe mit JDBC 961, 987 Datenflußanalyse 98, 116 Datentypen 93, 95, 97, 108 Datums-/Zeitarithmetik 394 Datumswerte 387 DAY_OF_MONTH 389 DAY_OF_WEEK 389–390 DAY_OF_WEEK_IN_MONTH 389 DAY_OF_YEAR 389 DayTime 1153 dB 1234 -debug 1282
1332
Debugger 1282 Debug-Grafik 786, 831 DebugGraphics 831–831 DecimalFormat 427 deep copy 209, 983 default 138, 430 DefaultButton 852 DEFAULT_CURSOR 604 DefaultDesktopManager 813 Default-Implementierung 213 Default-Konstruktor 172, 182 DefaultListModel 861 DefaultMutableTreeNode 908 defaultPage 580 Default-Paket 311 defaultReadObject 1065 DefaultTableCellRenderer 903 DefaultTableColumnModel 900 DefaultTreeModel 908, 915 DefaultTreeSelectionModel 911 Definite Assignment 98, 116 DeflaterOutputStream 468 Deklaration von Variablen 102, 134 Dekrement-Operator 102 Delegate 247 Delegate-Pattern 247, 370 Delegation 214, 247 Delegation Based Event Handling 261, 532, 609 Delegator 247 delete 276, 480, 494, 1257 DELETE FROM 995, 1019 deleteCharAt 276 deleteOnExit 497 deleteShortCut 664 delItem 729 Denial-of-Service-Attacken 330 -depend 1278 deprecated 66, 344, 465, 472, 503, 505, 554, 556, 726, 1210, 1279 -deprecation 1279 DESC 1021 deselect 728 Design Patterns 233–235, 237–237, 244, 247, 250, 253, 257, 627 Designzeitpunkt 1058 desktop 567–568, 813 DesktopManager 813 destroy 406, 811, 926 Destruktoren 174
Stichwortverzeichnis Device-Kontext 534 Dezibel 1234 Dialog 533, 595, 682, 702 Dialog, modaler 701 Dictionary 341 digest 1200 DigestInputStream 470 DigestOutputStream 469 Digital Signature Architecture 1205 Digitale Unterschrift 1206 Digitaler Fingerabdruck 1202 Dimension 743 -disableassertions 146, 1281 Disassembler 1291 DISCONTIGUOUS_TREE_SELECTION 911 dispose 573, 598 DISPOSE_ON_CLOSE 815 divide 419 Division 117 DNS 1147 DNS-Konfiguration 1283 do 44, 139–140 Doclets 1288 doClick 852 Document 845 DocumentListener 845 Dokumentation des JDK 57, 82 Dokumentationsgenerator 1285 Dokumentationskommentare 96, 96, 1285 Domain Name System 1147 DO_NOTHING_ON_CLOSE 815 Doppelpufferung 776 double 98, 101, 101, 223, 223 Double.TYPE 1029, 1035 doubleValue 225 DownloadService 329 Dr. Dobb's Journal 87 Drag-and-Drop API 39, 789 drawArc 544 drawBytes 551 drawChars 551 drawImage 753–754, 777 drawLine 539 drawOval 542 drawPolygon 541 drawPolyline 541 drawRect 540 drawRoundRect 540 drawString 551
DriverManager 991 DROP INDEX 1018 DROP TABLE 1018 Drop-Down-Listboxen 725 Drucken 529, 571 DSA 1205 DST_OFFSET 390–390 Duff's Device 138 Dynamische Datenstrukturen 98, 300 Dynamische Methodensuche 180 Dynamisches Binden 180 Dynamisches Laden von Klassen 1024
E -ea 146 EAST 683, 693, 822 ECHO-Service 1155 editCellAt 895 Eiffel 148 Eigenzertifikat 1209 Einerkomplement 120 Einfache Vererbung 177 Eingaben, einfache 67 Eingabe-Streams 452 Einschrnkende Konvertierungen 110 Einweg-Hashfunktion 1199 Einzeilige Kommentare 96 elementAt 337 elements 338, 342 else 69, 137 EMBED 957 Embedded SQL 988 empty 340 EmptyBorder 829 EmptyStackException 340 -enableassertions 146, 1281 enableEvents 628, 673, 744 end 573 Ende des Programms 501 endsWith 269 Entity Bean 1104 EntityManager 1113–1114 EntityManagerFactory 1114–1114 EntityTransaction 1114 Entry 362 entrySet 362 Entschlsseln 1195 Entwicklungszyklus 65, 312 Entwurfsmuster 233
1333
Stichwortverzeichnis enum 230 EnumControl 1234 enumerate 526 Enumeration 49, 338, 355 EnumMap 230 EnumSet 230 equals 109, 125, 179, 269, 341 equalsIgnoreCase 269 ERA 389–390 Ereignisempfnger 609, 612 Ereignisquellen 609, 613 Ereignistyp 611 Ergebnistyp eines Ausdrucks 117 err 399 Erreichbare Anweisungen 137 Error 289 ERROR_MESSAGE 807 Ersetzen von Zeichenketten 271–271 Erste Gehversuche 59 Erstellen eigener Pakete 309 Erweiternde Konvertierungen 110 Escape-Kommandos 1012 Escape-Sequenzen 99 ESQL 988 EtchedBorder 829 Ethernet 1144 Event 611 Event Sources 609 EventListener 609, 610, 612 EventObject 611–611, 1074 Exception 289 Exceptions 45, 263, 285 exec 404 executeQuery 992, 993 executeUpdate 992, 995 exists 489, 1021 exit 399 exitValue 406 EXKLUSIV-ODER-Operator 119 exp 418 expandCapacity 1270 expandPath 915 ExperimentalWebServer 1172 Exponentialfunktion 418 extends 177, 381 Extension Framework 39 Externalizable 973
1334
F Factory 237–238 Factory-Pattern 237 false 97–98, 99 FDDI 1144 Fehlerobjekt 288 Fensterklassen 595 Fenstertitel 602 fetch 1131 FetchType.EAGER 1131 FetchType.LAZY 1131 Field 1038 FieldPosition 431 File 444, 487 FileContents 331 FileDescriptor 444 FileDialog 595 FileInputStream 471, 969 FilenameFilter 490 FileNotFoundException 454, 471, 480 FileOpenService 329–330 FileOutputStream 462, 964, 1263 FilePermission 1224 FileReader 453 FileSaveService 329 file.separator 397, 440 FileWriter 442, 442 fill 410, 693 fillArc 545 fillOval 545 fillPolygon 545 fillRect 545 fillRoundRect 545 FilterInputStream 473 FilterOutputStream 464 FilterReader 453, 459 FilterWriter 442, 445, 449 final 179, 181, 186, 188, 1260 finalize 174 finally 292 Fingerprint 1202 firePropertyChange 1076 Firewall 1150 first 365 First Person, Inc. 36 firstElement 337 FLASH_OPTION 832 Fließkommazahlen 101 float 98, 101, 101, 224, 224
Stichwortverzeichnis FloatControl 1234 FloatControl.TYPE 1234 Float.TYPE 1029 floatValue 225 floor 418 FlowLayout 685 flush 441, 445, 462, 464 Focus Model Specification 836 FocusAdapter 614 Focus-Ereignisse 614 FocusEvent 614 FOCUS_EVENT_MASK 744 Focus-Events 646 focusGained 615, 647, 744 FocusListener 614 focusLost 615, 647, 744 Fokus-Subsystem 745 Font 553 Font-Informationen 558 FontMetrics 559 Font-Metriken 559 font.properties 555 for 44, 140, 140 foreach 142 format 278, 428, 430 Formatierte Ausgabe 278 Formatierung 427, 430 Formatter 278 formatTo 281 forName 1024, 1034 for-Schleife 139, 142 Fragezeichenoperator 122 Frame 533, 558, 595, 682 friend 44 Fllmodus 545 FULL 430 Funktionstasten 650 Funktionszeiger 210, 1033
G -g 1278, 1283, 1294 Gamelan 38 Gamma, Erich 233 Garbage Collector 109, 400 Garbage-Collector 44 gc 400, 1266 gcd 419 Gebundene Eigenschaften 1074 Gebundene Wildcards 381
General Public License 41 Generics 371 Generische Klassen 371 Generische Methoden 383 Generizitt 204 Gesampelter Sound 1230 Geschachtelte Schleifen 140 get 342, 345, 361, 389, 1039, 1044, 1158, 1173 getAbsolutePath 488 getActionCommand 668, 716, 721 getAddress 1150 getAdjustable 732 getAdjustmentType 732 getAnchorSelectionIndex 860 getAnnotation 1054 getAnnotations 1054 getApplet 945, 949 getAppletContext 945 getAppletInfo 928 getApplets 945, 949 getAscent 560 getAsText 1095 getAudioClip 933 getAudioFileFormat 1233 getAudioInputStream 1233 getAvailableFontFamilyNames 556 getBestCursorSize 604 getBlockIncrement 731, 866 getBlue 564 getBoolean 994, 1044 getBounds 549, 599 getBuffer 444 getBundle 432 getByName 1151 getByte 994, 1044 getBytes 994 getCaretPosition 721, 844 getCertificate 1210 getChar 1044 getChars 1259 getCheckboxGroup 719 getChecksum 469, 475 getChildAt 909 getChildCount 909 getClass 382, 516, 1024 getClickCount 640 getClip 549 getClipBounds 549 getCodeBase 933
1335
Stichwortverzeichnis getColor 565 getColumnClass 896 getColumnCount 894, 896, 1012 getColumnModel 906 getColumnName 896, 1012 getColumns 720 getColumnType 1012 getComponent 636, 683 getComponentAt 886 getComponentCount 683 getComponents 683 getConnection 991 getConstructor 1036 getConstructors 1036 getContent 1175 getContentPane 794, 801 getContents 678 getControl 1234 getControls 1234 getCopies 578 getCountry 426 getCurrent 719 getCustomEditor 1098 getDate 994 getDateInstance 430 getDateTimeInstance 430 getDeclaredAnnotations 1054 getDeclaredField 1039 getDeclaredFields 1039 getDeclaredMethods 1028 getDefault 393, 426–426 getDefaultRenderer 903 getDefaultToolkit 556 getDescent 560 getDocument 845 getDocumentBase 933 getDouble 994, 1039, 1044 getEchoCharacter 724 getEditingColumn 895 getEditingRow 895 getElements 857 getEnabled 819 getErrorCode 995 getErrorStream 406 getFamily 558 getField 1039 getFields 1039 getFilePointer 481 getFloat 994, 1044
1336
getFont 554 getFontList 556 getFontMetrics 559 getGlassPane 801 getGraphics 572, 777 getGreen 564 getHAdjustable 735 getHeight 560, 579, 758 getHorizontalAlignment 842, 852 getHorizontalTextPosition 841, 852 getHostAddress 1150 getHostName 1150 getIcon 1091 getID 612, 633 getImage 753 getImageableHeight 579 getImageableWidth 579 getImageableX 579 getImageableY 579 getInputStream 331, 406, 591, 1153 getInsets 535, 552 getInstance 1203 getInt 994, 1039, 1044 getItem 659, 726–727 getItemCount 659, 726 getItemSelectable 717, 727 getJobName 578 getKey 362 getKeyChar 612, 650, 652, 745 getKeyCode 620, 650, 652 getKeys 433 getKeyStroke 819 getLabel 660, 716–717 getLanguage 426 getLastPathComponent 912 getLayeredPane 801 getLeading 560 getLeadSelectionIndex 860 getLeadSelectionPath 911 getLeadSelectionRow 912 getLength 331, 1044 getLine 1233 getLineCount 847 getLineEndOffset 847 getLineNumber 458 getLineOfOffset 847 getLineStartOffset 847 getLineWrap 848 getLocalGraphicsEnvironment 556
Stichwortverzeichnis getLocalHost 1151 getLocation 599, 705 getLong 994, 1044 getMajorTickSpacing 869 getMaximum 731, 866, 1234 getMaximumCursorColors 604 getMaximumSize 743, 835 getMaxReceivers 1240 getMenu 658 getMessage 288 getMetaData 1001, 1011 getMethod 1034 getMethodDescriptors 1092 getMethods 1028 getMicrosecondPosition 1240 getMidiDevice 1239 getMidiDeviceInfo 1239 getMidiFileTypes 1248 getMinimum 731, 866, 1234 getMinimumSize 742, 835 getMinorTickSpacing 869 getMixer 1233 getMixerInfo 1233 getMnemonic 818, 852 getModel 861 getModifiers 612, 1028, 1036 getName 331, 488, 526, 590, 678, 1028, 1036 getNewLeadSelectionPath 912 getNewValue 1075 getNextException 995 getNumberInstance 427 getNumberOfPages 583 getObject 435 getOldLeadSelectionPath 912 getOldValue 1075 getOrientation 579 getOutputStream 331, 406, 591, 1153 getPageDimension 573 getPageFormat 583 getPageResolution 573 getPaper 579 getParameter 930 getParameterInfo 927 getParameterTypes 1029, 1036 getParent 488, 526, 909 getPath 488, 912 getPathToRoot 916 getPoint 612 getPortIdentifier 590
getPortIdentifiers 590 getPortType 590 getPosition 639 getPreferredSize 735, 742, 835 getPrintable 583 getPrinterJob 578 getPrintJob 572 getPriority 526 getProperties 398 getProperty 344, 398 getPropertyDescriptors 1092 getPropertyName 1075 getPublicKey 1210 getReceiver 1240 getRed 564 getResource 1060 getResourceAsStream 319 getRootPane 801 getRowCount 894, 896 getRuntime 404 getScreenResolution 573 getScreenSize 600 getScrollPosition 736 getSelectedColumn 893 getSelectedColumns 893 getSelectedComponent 886 getSelectedIndex 726, 860, 863, 886 getSelectedIndexes 728 getSelectedIndices 860 getSelectedItem 726, 863 getSelectedItems 728 getSelectedRow 893 getSelectedRows 893 getSelectedText 721, 844 getSelectedValue 860 getSelectedValues 860 getSelection 857 getSelectionEnd 721, 844 getSelectionMode 860 getSelectionModel 906–907, 911 getSelectionPath 911 getSelectionPaths 911 getSelectionRows 912 getSelectionStart 721, 844 getSequence 1247 getSequencer 1243 getShort 994, 1044 getSize 552, 558, 599 getSource 611, 633, 721
1337
Stichwortverzeichnis getSQLState 995 getState 601, 661, 717–717, 823 getString 435, 994 getStringArray 435 getStyle 558 getSuperClass 1041 getSynthesizer 1239 getSystemClipboard 677 getTabCount 886 getTableCellRendererComponent 905 getTableName 1012 getTabPlacement 885 getTabSize 848 getTags 1096 getter-Methoden 1061 getText 715, 720, 844 getThreadGroup 526 getTime 396, 994 getTimeInstance 430 getTimestamp 994 getTitle 602 getToolkit 754 getToolTipText 830 getTransactionIsolation 1013 getTransferData 676 getTransferDataFlavors 676 getType 1039 getTypeInfo 1013 getUnitIncrement 731, 866 getUserName 578 getUserObject 909 getVAdjustable 735 getValue 362, 731–732, 866, 872, 1095, 1234 getValueAt 894, 896 getValueIsAdjusting() 866, 870 getVariant 426 getVerticalAlignment 842, 852 getViewportSize 736 getVisibleAmount 731, 866 getWhen 640 getWidth 579, 758 getWindow 633 getWrapStyleWord 848 getX 639 getY 639 gif-Format 753 gk.util 308, 1000 GlassPane 800 Gleichheits-Operator 118
1338
Globale Funktionen 164 GoF (Gang of Four) 234 GoldWave 933 Gosling, James 36 Grafikkontext 534 Graphical User Interface 1057 Graphics 534 Graphics2D 582 GraphicsEnvironment 556 gray 564 green 564 Green-OS 36 Green-Projekt 36 GregorianCalendar 388 GridBagConstraints 692 GridBagLayout 692 gridheight 693 GridLayout 687 gridwidth 693 gridx 693 gridy 693 Grçßergleich-Operator 118 Grçßer-Operator 118 GROUP BY 1021 Grundlinie 559 GUI-Designer 1058 GZIPInputStream 476 GZIPOutputStream 468
H handleEvent 609 handleGetObject 433 Hardware-Voraussetzungen 55 hasBeenExpanded 915 hashCode 179, 351, 1199 Hash-Funktion 341, 362 HashMap 49, 359, 362 HashSet 359 Hashtable 341, 362 hasMoreElements() 49, 338 hasNext 356 hasPrevious 358 HAVING 1021 HEAD 1173 headSet 365 Heavyweight Components 786 HEIGHT 928–928 Helm, Richard 233 -help 1280
Stichwortverzeichnis Helvetica 554 HIDE_ON_CLOSE 815 Himmelsrichtungen 689 Hintergrundfarbe 602 Hintergrund-Thread 501 Hçhe einer Zeile 559 HORIZONTAL 693, 731, 822 HORIZONTAL_SCROLLBAR_ALWAYS 878 HORIZONTAL_SCROLLBAR_AS_NEEDED 878 HORIZONTAL_SCROLLBAR_NEVER 878 HORIZONTAL_SPLIT 882 Host-ID 1145 Host-Namen 943 hosts 1283 Host-Variablen 988 HotJava 37 HotJava Views 38 HotSpot 39, 1280 HOUR 389 HOUR_OF_DAY 389 hprof 1267 HSPACE 930 HSQLDB 997 HTML-Adresse 943 HTML-Ausgabe des Buchs 87 HTMLConverter 959 HTML-Dokument 928 http 944 Hybride Kryptosysteme 1205 Hypersonic SQL 1002
I [I 1272 I18N 424 IAB 1148 IBM 38 ICMP 1144 Icon 602, 821 ICON_COLOR_16x16 1091 ICON_COLOR_32x32 1091 ICONIFIED 601 ICON_MONO_16x16 1091 ICON_MONO_32x32 1091 if 44, 135, 136 if-Anweisung 135 if-else 135 IIOP 1181 IllegalArgumentException 147, 353 IllegalThreadStateException 406
Image 753 ImageIcon 822 ImageObserver 754 immutable 227, 359 Immutable-Pattern 235 Impedance Mismatch 1103 Implementierung eines Interfaces 198 implements 198 import 68, 302, 303 import static 208 Import von java.lang 303 in 399, 1021 inactiveCaption 567 inactiveCaptionBorder 567 inactiveCaptionText 567 .inc-Dateien 537 indexOf 270 IndexOutOfBoundsException 291 Indizierte Eigenschaft 1062 InetAddress 1150 inetd.conf 1165 InflaterInputStream 476 info 568 Informationen im Internet 84 INFORMATION_MESSAGE 807 infoText 568 init 811, 923, 925 Initialisieren 103, 105 initSign 1209 initVerify 1209 Inkrement-Operator 102 Inner Classes 217 Input Method Framework 789 InputEvent 612, 649 InputStream 461, 461, 470 InputStreamReader 453, 454 insert 276, 724, 909 INSERT INTO 995, 1005, 1019 insertElementAt 337 insertItemAt 864 insertNodeInto 916 insertSeparator 659 insertTab 885 insets 694 Installation 56 instanceof 126, 337, 383, 722 InstantDB 997 Instanzmerkmale 157 Instanzvariablen 102, 104, 157
1339
Stichwortverzeichnis int 98, 100, 223 Integer 223 Integer.TYPE 1029–1029 Integrale Typen 100 interface 197 Interfaces 177, 197, 237 Interger einlesen 68 Internationalisierung 424 Internet 84 Internet Activity Board 1148 Interpreter 1279 interrupt 503 interrupted 503 InterruptedException 505, 756 InterruptedIOException 1157 Introspection 1024, 1059 Introspector 1090 intValue 225 invalidate 835 InvalidClassException 972 Invalidierung 835 Invariante 144 invoke 1029, 1035 IOException 344, 443, 480 IP-Adresse 1145 ipadx 694 ipady 694 IP-Protokoll 1144 IPv6 1146 IS NOT NULL 1020 IS NULL 1020 isAbsolute 489 isAbstract 1028 isAlive 506, 506 isAltDown 650 isAnnotationPresent 1054 isCancelled 578 isCellEditable 896 isCollapsed 914 isControlDown 650 isControlSupported 1234 isConversionSupported 1233 isDataFlavorSupported 676 isDirectory 489 isDoubleBuffered 834 isEditable 721, 863 isEditing 895 isEmpty 336, 351, 361 isEnabled 599, 660, 852
1340
isEnabledAt 886 isExpanded 914 isExplicit 1028 isFile 489 isFinal 1028 isFocusable 745 isFocusTraversable 744 isHidden 489 isIndeterminate 874 isInterface 1028 isInterrupted 503 isLeaf 909 isMetaDown 650 isModal 702 isNative 1028 ISO/OSI-7-Schichten-Modell 1144 ISO-639 425 ISO-3166 425 ISO-8859-1 95 isOpen 1240 isPaintable 1098 isPathSelected 912 isPopupTrigger 673, 827 isPrivate 1028 isProtected 1028 isPublic 1028 isResizable 703 isRootVisible 908 isRunning 1235, 1244 isSelected 823, 855 isSelectedIndex 860 isSelectionEmpty 860, 912 isShiftDown 650 isStatic 1028 isStrict 1028 isSynchronized 1028 isTemporary 646 isTransient 1028 isVisible 915 isVolatile 1028 ITALIC 555 Item-Ereignisse 618, 726 ItemEvent 611, 618, 717, 726 ItemListener 618, 717, 726 itemStateChanged 618, 717, 726 Iterable 142 Iterator 49, 356, 356 Iterator-Pattern 244
Stichwortverzeichnis
J -J 1274 J++ 38 JAAS 1206 Jakarta 315 JApplet 794, 811 -jar 318, 1289 JAR-Archiv 929 JarOutputStream 468 jarsigner 1219, 1293 java 64, 1279 Java 2 Platform 39 Java 2 SDK 42 Java 2D API 39, 46 Java 5 Enterprise Edition 42 Java 6 Standard Edition 42–42 Java Authentication and Authorization Service 1206 Java Beans Homepage 1066 Java Card Edition 42 Java Communications API 571, 589 Java Community Process 41 JAVA Cryptography Extension 1206 Java Data Objects 1104 Java Database Connectivity 49, 988 Java Developer's Connection 38, 85 Java Developer's Journal 87 Java Development Kit 37 Java Foundation Classes 39, 46, 785 Java Media Framework 1230 Java Micro Edition 42 Java Naming and Directory Interface 1192 Java Network Launching Protocol 323 Java Platform Debugger Architecture 1282 Java Runtime Environment 57, 1281 Java Secure Socket Extension 1206 Java Server Pages 53 Java Spektrum 87 Java Virtual Machine Profiler Interface 1267 Java Web Start 322, 1173 Java Workstations 322 Java World 87 java.applet 304 java.awt 304, 533 java.awt.datatransfer 676 java.awt.event 611 java.awt.image 47 java.awt.print 577 JavaBeans 38, 49, 304, 1074 javac 61, 64, 1278
JavaCard API 38 java.class.path 397 java.class.version 397 JAVA_COMPILER 1274, 1280–1280 .java-Dateien 60, 64, 311, 1278 javadoc 96, 1285 javadt 1282 java_g 1274, 1281 java.home 397 javaidl 49 java.io 304, 440 javakey 1207 java.lang 303–304 java.lang.Iterable 142 java.lang.Math 208 java.lang.ref 304 java.lang.reflect 304, 1032 JavaLobby 86 java.math 304, 418 java.net 304, 1150 java.nio 304 JavaOne 38 JavaOS 1.0 38 javap 1291 Java-Plugin 788, 957 java.policy 1222–1222 java.rmi 304, 1183–1183 java.rmi.server 1184 JavaScript 45 java.security 304 java.security.cert 1210 JavaSoft 37, 85 java.specification.name 397 java.specification.vendor 397 java.specification.version 397 java.sql 304, 991 JavaStation 38 java.text 278, 304, 427 Java-Usergruppen 38 java.util 304, 349, 611 java.util.Deque 340 java.util.Formattable 281 java.util.Formatter 278 java.util.jar 468 java.util.zip 468 java.vendor 397 java.vendor.url 397 java.version 397 java.vm.name 397
1341
Stichwortverzeichnis java.vm.specification.name 397 java.vm.specification.vendor 397 java.vm.specification.version 397 java.vm.vendor 397 java.vm.version 397 javaw 72, 1279 javax.accessibility 305 javax.comm 590 javax.crypto 305 javax.imageio 305 javax.jnlp 330 javax.naming 305 javax-Pakete 304 javax.print 305 javax.security.auth 305 javax.sound 305 javax.sound.midi 1238 javax.sound.sampled 1231 javax.swing 305, 793 javax.swing.event 861, 870 javax.swing.plaf 831 javax.swing.table 896 javax.swing.text 843 javax.swing.tree 908 javax.xml 305 JButton 796, 851 JCE 1206 JCheckBox 855 JCheckBoxMenuItem 823–823 JComboBox 863 JComponent 794, 829 JCP 41 jdb 1282 JDBC 38, 49, 961, 987, 988 JDBC-ODBC-Bridge 988 JDBC-Versionen 990 JDC 85, 85 JDesktopPane 813 JDialog 794, 805 JDK 37, 42 JEditorPane 847 JFC 46 JFormattedTextField 846 JFrame 247, 794, 799 JInsight 1275 JInternalFrame 813 JIT 1253, 1280 JLabel 795, 841 JLayeredPane 800–801, 839
1342
JList 795, 859 JMenu 817 JMenuBar 800 JMenuItem 818 JNDI 1192 jnlp-Datei 324 Johnson, Ralph 233 join 505, 507 JOptionPane 806 Joy, Bill 36 JPA 961, 1103 JPanel 794, 839 JPasswordField 795, 847 JPDA 1282 jpeg-Format 753 JPopupMenu 826 JProbe 1275 JProgressBar 872 JRadioButton 857 JRadioButtonMenuItem 823 JRE 42, 57, 1281 JRootPane 800 JScrollBar 865 JScrollPane 796, 848, 877 JSlider 868 JSpinner 849 JSplitPane 881 JSSE 1206 JTabbedPane 885 JTable 888 JTextArea 847 JTextComponent 843 JTextField 843 JTextPane 847 JToggleButton 855 JToolTip 830 JTree 907 Just-In-Time-Compiler 1253, 1280 JVMPI 1267 JWindow 794, 803
K Kapselung 157 -keepgenerated 1294 Kestrel 40 KeyAdapter 614, 622, 624 Key-Ereignisse 615 KeyEvent 612, 615, 620, 649 KEY_EVENT_MASK 744
Stichwortverzeichnis Key-Events 649 KeyListener 615, 620, 622, 649 -keypass 1293 keyPressed 615, 620, 624, 650, 652, 745 keyReleased 615, 620, 650 keys 342 keySet 362 .keystore 1207, 1210, 1293 KeyStroke 819 keytool 1207, 1221, 1292 keyTyped 615, 620, 650, 652 Klammerung 116 Klartext 1195 Klassen 300 Klassendiagramme 90 Klassenmethoden 189, 300 Klassenobjekt 1024 Klassenvariablen 102, 104, 187 Kleinergleich-Operator 118 Kleiner-Operator 118 Kommentare 96 Komposition 160 Konstanten 188, 207 Konstruktoren 171 Konstruktorenverkettung 172, 181 Kontextmens 673, 826 Kontext-URL 945 Konvertierungen auf primitiven Datentypen 110 Konvertierungsfunktionen 272 Koordinatensystem 534 Kopieren einer Datei 471 Kopieren von Flchen 546 Kopieren von Objekten 983 Kreisbçgen zeichnen 544 Kreise zeichnen 542 Kritischer Bereich 516 Kryptoanalyse 1196 Kryptographie 961, 1195, 1196 Kryptologie 1196
L -l 1291 L10N 424 Label 714 Ladefaktor 1256 Lnge der Zeichenkette 267 LANDSCAPE 579 last 365 lastElement 337
lastIndexOf 270 lastModified 489 Late Binding 161 Laufzeitfehler 285 LayeredPane 800 Layoutmanager 684 LEADING 822 Lebensdauer 103, 183 Leere Anweisung 133 LEFT 686, 714, 822, 930 length 106, 108, 268, 268, 277, 481 Lexikalische Elemente 95 LIFO-Prinzip 339 lightGray 564 Lightweight Components 786 LIKE 1020 Line 1231 Lineare Liste 336 LineBorder 829 Line.Info 1233 LineNumberReader 453, 458 line.separator 397, 440, 445 Linien zeichnen 539 Linien- oder Fllmodus 545 LinkedList 350, 353, 1261 List 349, 352, 490, 728, 1187 Listboxen 728 ListDataEvent 861 Listener 261 listFiles 493, 1003 ListIterator 357 ListModel 796, 859, 861 listRoots 490 ListSelectionEvent 861 ListSelectionListener 861 ListSelectionModel 859, 889, 893 Literale 99–101 load 344 loadImage 1091 Locale 425 localhost 1152 Lockdateien 497 Lçschen von Flchen 546 log 418 Logarithmus 418 Logische Operatoren 119 Logischer Typ 99 LOG_OPTION 832 Lokale Klassen 622
1343
Stichwortverzeichnis Lokale Variable 102, 134 Lokalisierung 424 long 98, 100, 223, 223, 430 Long.TYPE 1029 longValue 225 Look-and-Feel 787, 796 lookup 330, 1187, 1190 loop 934 lostOwnership 678 Lotus 38 lowerCase 452 LOWER_LEFT_CORNER 878 LOWER_RIGHT_CORNER 878
M magenta 564 main 60, 190, 301, 923, 1279 Main-Class 318 make 315 makefile 315 makeVisible 915 MalformedURLException 944 Manifest-Datei 318–318, 1070 Map 349, 360 Map.Entry 362 mappedBy 1131 mark 453, 471 markSupported 453, 471 MASTER_GAIN 1234 Matcher 414 Math 387, 417, 438 Mauscursor 602, 603 max 417 MAX_PRIORITY 526 MAX_VALUE 101–101, 226 McNealy, Scott 35 MD5 1199 MDI 812 Mediator-Pattern 627 MediaTracker 755 MEDIUM 430 Mehrdimensionale Arrays 106 Mehrfachselektion 728 Mehrfachvererbung 43, 159, 177, 197 Mehrfachverzweigung 138 Mehrstufige Client-Server-Architekturen 989 Mehrzeilige Kommentare 96 Membervariablen 157, 163 Member-Zugriff 126
1344
menu 568, 657 MenuBar 657 Men 602 Meneintrge 660 Menleiste 658 MenuItem 657, 660 MenuShortcut 663 menuText 568 Message Digest 469, 1199 Message Queue 464 MessageDigest 1199 meta-inf 318 Metainformationen 1047 Metal-Look-and-Feel 790 MetaMessage 1239 Meta-Ressourcen 85 Method 1028, 1092 MethodDescriptor 1092 Methoden 126, 157, 164, 179, 300 Metriken fr Fonts 559 Meyer, Bertrand 148 Microsoft Internet Explorer 45 middle 930 Middleware 989 Midi 1230, 1237 Midi-Dateien 47 MidiDevice 1239 Midi-Ereignisse 1238 MidiEvent 1239 Midi-Format 933 MidiMessage 1239 Midi-Nachrichten 1238 MidiSystem 1239 MILLISECOND 390 MIME-Spezifikation 676 MIME-Typ 1173 min 417 Minimum und Maximum 417 MINUTE 390 MIN_VALUE 101–101, 226 MissingResourceException 433 Mixer 1230, 1232 Mixer.Info 1233 mkdir 494 mkdirs 494 Modale Dialoge 701 Model-Delegate-Prinzip 787 Model-View-Controller-Prinzip 787 Modifier 164, 183, 1028
Stichwortverzeichnis Modulo-Operator 117 Monitor 500 Monospaced 554 MONTH 389 MouseAdapter 614 mouseClicked 615 mouseDragged 616 mouseEntered 615 Mouse-Ereignisse 615 MouseEvent 612, 615–616, 638 MOUSE_EVENT_MASK 744 Mouse-Events 638 mouseExited 615 MouseListener 615, 638 MouseMotionAdapter 614 MouseMotion-Ereignisse 616 MouseMotion-Events 643 MouseMotionListener 616 mouseMoved 616 mousePressed 615, 744 mouseReleased 615 moveCaretPosition 844 MOVE_CURSOR 604 Mozilla Firefox 45 MS-Access 997 multiple bounds 383 Multiple Document Interface 812 MULTIPLE_INTERVAL_SELECTION 859, 893 Multiplikation 117 multiply 419 Multi-Tier-Architekturen 989 Mustang 40 mutable 359 MutableTreeNode 909 MVC 627, 787
N NAME 929 NamedQuery 1138 Namenskonventionen 70 Namens-Service 1180 Name-Server 1147 Naming 1187 NaN 101, 101, 226 National Institute of Standards and Technology 1199 Natrliche Ordnung 364 Naughton, Patrick 35 NCSA Mosaic 36 Nebeneffekte 116, 135
Nebenlufigkeit 499 negate 419 NEGATIVE_INFINITY 101, 102, 226 Netscape 38, 45 Network Information Center 1145 Networking-API 49 Netzwerk-ID 1145 Netzwerkprogrammierung 961, 1143 Netzwerkschicht 1144 new 105, 109, 126, 163 New I/O Package 304 newAudioClip 935 newInstance 1024, 1036, 1042 newLine 445 Newsgroups 53, 84 next 356, 993 nextBytes 1203 nextDouble 386 nextElement() 49, 338 nextFloat 386 nextGaussian 387 nextIndex 358 nextInt 386 nextLong 386 NIC 1145 NICHT-Operator 119 NoClassDefFoundError 63, 64, 66 nodeChanged 916 NONE 693 NONE_OPTION 832 NORMAL 601 NORM_PRIORITY 526 NORTH 683, 693, 822 NORTHEAST 693, 822 NORTHWEST 694, 822 NoSuchElementException 356 NoSuchMethodException 1035 NO_SUCH_PAGE 582 NOT 1020 NOTE_OFF 1241 NOTE_ON 1241 notify 520 NotSerializableException 966, 978 -nowarn 1278 null 97, 108, 164, 994 Null-Layout 685, 697 null-Objekt 160 NullPointerException 1035 Number 379
1345
Stichwortverzeichnis NumberFormat 427–427 NumberFormatException 286
O -O 1278 Oak 36 Oberlnge 559 Object... 168, 179, 179, 378, 929 Object Relational\nMapping 1103 ObjectInputStream 472, 967 ObjectOutputStream 463, 963 Objektorientierte Persistenz 961, 1103 Objektorientierte Programmiersprache 44 Objektorientierte Programmierung 155 Objektvariable 161 Observer-Pattern 257 ODBC-Treiber 988 ODER-Operator 119 Offscreen-Image 776 OK_CANCEL_OPTION 808 Online-Dokumentationen 87 OOP 44, 155 open 591, 1235, 1240 openConnection 1175 openStream 1175 Operatoren 117–123 Operator-Vorrangregeln 127 or 346, 1020 Oracle 38 orange 564 ORDER BY 1021 org.omg 305 org.w3c 305 org.xml 305 ORM 1103 os.arch 397 os.name 397 os.version 397 out 48, 399 OutOfMemoryError 1266 OutputStream 461–461, 461, 1263 OutputStreamWriter 442, 442
P pack 683, 743 package 309, 1288, 1291 package scoped 183, 185 package-list 1287 Pageable 577, 583
1346
pageDialog 580 PAGE_EXISTS 582 PageFormat 578 paint 534, 604 paintBorder 831 paintChildren 831 paintComponent 831 paintValue 1098 Pakete 301, 302, 309 PAN 1234 Panel 595, 699, 1086 Paper 578 ParallelPort 591 Parameter von Methoden 166–167 PARAM-Tag 929 _parent 945 parse 430 parseByte 226 parseDouble 226 parseFloat 226 parseInt 226 parseLong 226 PATH 73–73 path.separator 397 Pattern 413 PCM 1237 peek 339 Performance-Tuning 1251, 1253 persist 1116 Persistence Descriptor 1111 PersistenceService 329 Persistenz 963 PGP 1206 PI 208 PicoJava 38 pink 564 Pipe 523 PipedInputStream 473, 523 PipedOutputStream 464, 523 PipedReader 442, 453–454, 525 PipedWriter 442–442, 453, 525 pkunzip 468 PLAIN 555 PLAIN_MESSAGE 807 plainTextFlavor 677 play 933–934 Pluggable Look-and-Feel 46, 787 Plugin fr HTML-Browser 957 Point 639
Stichwortverzeichnis Pointer 43 Policy-Datei 1216, 1222 policytool 1222, 1293 Polygon 541 Polygone zeichnen 541 Polymorphismus 161, 192 pop 339 PopupMenu 673 Popup-Mens 673, 826 Port 1232 Port-Nummer 944, 1147 PORT_PARALLEL 590 PORTRAIT 579 PORT_SERIAL 590 Positionierung des Dateizeigers 480 POSITIVE_INFINITY 101, 102, 226 Postconditions 148 Postdekrement 117 Postinkrement 117 pow 418–419 PPQ 1244 Prdekrement 117 Prinkrement 117 Prprozessor 97 Preconditions 148 Prepared Statements 1015 PreparedStatement 1016, 1136 prepareStatement 1016 Pretty Good Privacy 1206 previous 358 previousIndex 358 Primitive Datentypen 97 Primitive Variable 161 print 447, 464, 574, 582 Printable 577, 582 printAll 574 printDialog 580–581 PrinterException 583 PrinterJob 577–578 printf 278 PrintGraphics 572 PrintJob 572 println 399, 447, 464 PrintService 329 printStackTrace 288–289 PrintStream 48, 399, 464 PrintWriter 442, 445, 447 private 44, 181, 183–184, 1260, 1288, 1291 Process 406
processActionEvent 627 processComponentEvent 745 processEvent 627 processFocusEvent 744 processKeyEvent 628, 745 processMouseEvent 627, 673, 744 Producer/Consumer-Beispiel 520 -prof 1274, 1280 Profiler 1267, 1280 PROGRAM_CHANGE 1241 Programmende 501 Projektverwaltung 313 Properties 343, 398 propertyChange 1075 PropertyChangeEvent 1074 PropertyChangeListener 1075 PropertyChangeSupport 1075 PropertyDescriptor 1092 PropertyEditorSupport 1094 propertyNames 344, 398 PropertyPermission 1224 PropertyResourceBundle 438 PropertyVetoException 1080 protected 44, 183, 185, 1288, 1291 Protokoll 1144 Provider fr Security-API 1209 Proxy-Server 1150 Pseudo-Zufallszahlen 1203 public 44, 183, 185, 312, 314, 1288, 1291 Public-Key-Verschlsselung 1205 push 339 PushbackInputStream 473 PushbackReader 453, 459 put 341, 361 putAll 361
Q Query 1135 QUESTION_MESSAGE 807
R Radiobuttons 718 Random 49, 385 RandomAccessFile 467, 479, 1265 Random-Access-I/O 263, 479 read 453, 470 readBoolean 482, 967 readByte 482, 967 readChar 482, 967
1347
Stichwortverzeichnis readDouble 482, 967 Reader 452 readFloat 482, 967 readFully 482 readInt 482, 967 readLine 456, 482 readLong 482, 967 read-Methoden 482 readObject 967 readShort 482, 967 readUnsignedByte 482 readUnsignedShort 475, 482 readUTF 482, 967 ready 453 rebind 1187 Receiver 1239 Rechtecke zeichnen 540 Rechtsschiebeoperator 120 Rectangle 766 red 564 Red-Black-Tree 365 Referenzgleichheit und -ungleichheit 124 Referenztypen 108 Reflection 49, 961, 965, 1023 regionMatches 269 registerKeyboardAction 836 Registry 57 Regulre Ausdrcke 413 Relationale Operatoren 118 remainder 419 Remote 1183 Remote Method Invocation 49, 961, 1179 RemoteException 1183 Remote-Interface 1179 Remote-Objekte 1180 Remote-Referenzen 1180 remove 353, 356, 361, 658–659, 683, 729, 909 removeActionListener 819 removeAll 353, 886 removeAllChildren 909 removeAllItems 864 removeColumnSelectionInterval 894 removeItem 864 removeItemAt 864 removeNodeFromParent 916 removePropertyChangeListener 1075 removeRowSelectionInterval 894 removeSelectionInterval 860 removeTabAt 886
1348
removeTableModelListener 896 removeVetoableChangeListener 1080 renameTo 494 Rendering von Tabellen 903 repaint 636, 744 repaint-Schleife 760 replace 271, 274 replaceAll 271 replaceItem 729 replaceRange 724 Request For Comments 1148 requestDefaultFocus 887 requestFocus 647, 744 RESERVED_ID_MAX 612 reset 445, 453, 471, 978 ResourceBundle 432 Ressourcen 319, 432 Ressourcendatei 657 Restwertoperator 117 ResultSet 993 ResultSetMetaData 1011 resume 505 retainAll 353 Retention 1053 return 126, 169, 292 revalidate 835 REVERSE_LANDSCAPE 579 RFC 1148 RFC 1521 676 RFC 1522 676 RGB-Farbmodell 563 RIGHT 686, 714, 822, 930 Rivest, Ron 1199 rmf-Format 933 RMI 961, 1179 rmic 1185, 1294 RMI-Registry 1180, 1186, 1294 RMISecurityManager 1188 rollback 1012 RootPane 800 RootPaneContainer 801 round 418 ROUND_CEILING 422 ROUND_DOWN 422 ROUND_FLOOR 422 ROUND_HALF_DOWN 422 ROUND_HALF_EVEN 422 ROUND_HALF_UP 422 ROUND_UNNECESSARY 422
Stichwortverzeichnis ROUND_UP 422 rowAtPoint 907 RSA 1205 rt.jar 307 Rckgabewert einer Methode 169 run 500, 506 Runden und Abschneiden 418 Runnable 500, 507, 509 Runtime 404 RuntimeException 294 RuntimePermission 1224
S -s 1291 Samples 1230 Sampling 1230 Sandbox-Konzept 1215 SansSerif 554 save 344 scale 422 Scanner 67 Schachteln 445, 456, 699 Schiebeoperationen 120 Schieberegler 731 Schleifen 139 Schleifeninvarianten 148 Schließen eines Fensters 535 Schlssel 1196 Schlsseltext 1195 Schlsseltransformation 341 Schlsselwçrter 97 Schneier, Bruce 1199 Schnittstellen (Interfaces) 197 Schriftarten 553 scrollbar 568, 731 SCROLLBARS_ALWAYS 734 SCROLLBARS_AS_NEEDED 734 SCROLLBARS_BOTH 724 SCROLLBARS_HORIZONTAL_ONLY 724 SCROLLBARS_NEVER 734 SCROLLBARS_NONE 724 SCROLLBARS_VERTICAL_ONLY 724 ScrollPane 569, 734 search 340 SECOND 390 SecureRandom 1203 SecurityException 1217 SecurityManager 1225 seek 481
Segment7 742 select 721, 726, 728, 1019 selectAll 721, 894 SELECT-Anweisung 993 _self 945 semidynamische Arrays 43 send 1240 Separatoren 659 Sequence 1239 SequenceInputStream 472 Sequencer 1230, 1239 Sequenz 1238 Sequenzer 1238 Serialisierte Beans 1072 Serialisierung 49, 963 Serializable 965, 969 SerialPort 591 serialver 972, 1292 serialVersionUID 971 Serif 554 -server 1280 Server-Hotspot 1280 ServerSocket 1152, 1163 ServiceManager 330 Services 329 Servlet-API 53 set 73, 345, 349, 358, 358, 389, 1039, 1044 setAccelerator 819 setActionCommand 664, 669, 716 setAsText 1095 setAutoCommit 1012 setAutoResizeMode 892 setBackground 538, 604 setBlockIncrement 731, 866 setBoolean 1044 setBorder 795, 829 setBounds 599, 697 setByte 1044 setCaretPosition 721, 844 setCellSelectionEnabled 893 setChar 1044 setCharAt 276 setCheckboxGroup 719 setClip 548 setClosable 814 setColor 565 setColumnHeaderView 878 setColumns 720 setColumnSelectionAllowed 893
1349
Stichwortverzeichnis setColumnSelectionInterval 894 setComponentAt 886 setConstraints 692 setContentPane 805 setContents 678 setCopies 578 setCorner 878 setCurrent 719 setCursor 603 setDebugGraphicsOptions 831 setDecimalSeparatorAlwaysShown 429 setDefaultButton 852 setDefaultCloseOperation 814 setDefaultRenderer 903 setDouble 1039, 1044 setDoubleBuffered 834 setEchoChar 847 setEchoCharacter 721, 795 setEditable 721, 863 setEnabled 599, 660, 819, 852 setEnabledAt 886 setErr 399, 465 setFlashCount 832 setFlashTime 832 setFloat 1044 setFont 554, 604 setForeground 604 setGridColor 892 setGroupingSize 429 setHeaderValue 901 setHorizontalAlignment 842, 852 setHorizontalTextPosition 822, 841, 852 setIcon 822 setIconifiable 814 setIconImage 603 setIn 399 setIndeterminate 874 setInt 1039, 1044 setIntercellSpacing 891 setJMenuBar 820 setJobName 578 setLabel 660, 716–717 setLayout 682, 685 setLength 481 setLineNumber 458 setLineWrap 848 setLocation 599 setLong 1044 setLookAndFeel 796
1350
setMajorTickSpacing 869 setMaximizable 814 setMaximum 866 setMaximumSize 835 setMenuBar 658 setMessage 1240 setMinimum 866 setMinimumSize 835, 883 setMinorTickSpacing 869 setMnemonic 818, 852 setModal 702 setName 525 setNextFocusableComponent 836 setOneTouchExpandable 883 setOpaque 833 setOut 399, 465 setPage 584 setPaintLabels 869 setPaintTicks 869 setPreferredSize 835 setPrintable 582 setPriority 526 setPropertyEditorClass 1092 setReceiver 1244 setResizable 703, 814 setRootPaneCheckingEnabled 803 setRootVisible 908 setRowHeaderView 878 setRowHeight 891 setRowMargin 891 setRowSelectionAllowed 893 setRowSelectionInterval 894 setScale 422 setScrollPosition 736 setSeed 1203 setSelected 823, 855 setSelectedIndex 860, 863, 886 setSelectedIndices 860 setSelectedItem 863 setSelectionBackground 892 setSelectionEnd 844 setSelectionForeground 892 setSelectionInterval 860 setSelectionMode 859, 893, 911 setSelectionModel 911 setSelectionPath 914 setSelectionPaths 914 setSelectionStart 844 setSequence 1244
Stichwortverzeichnis setShort 1044 setShortCut 664 setShowGrid 891 setShowHorizontalLines 891 setShowVerticalLines 891 setSize 599, 697, 735 setSnapToTicks 870 setSoTimeout 1157 setState 601, 661, 717, 823 setStringPainted 872 setTabPlacement 885 setTabSize 848 setTempoInBPM 1244 setter-Methoden 1061 setText 715, 720, 844 setTime 396, 489 setTimeZone 393 setTitle 602, 814 setToolTipText 795, 830 setTransactionIsolation 1013 setUnitIncrement 731, 866 setUserObject 909 setValue 731, 866, 872, 1095, 1234 setValueAt 894, 896 setVerticalAlignment 842, 852 setVisible 533, 597, 683 setVisibleAmount 866 setWindowAdapter 955 setWrapStyleWord 848 SHA 1199 shallow copy 209, 983 Shape 549 Shell 72 Sheridan, Mike 36 short 98, 100, 223, 223, 430 Short-Circuit-Evaluation 119 ShortMessage 1239–1240 Short.TYPE 1029 show 673, 826, 1292 showConfirmDialog 807 showDocument 945 showInputDialog 809 showMessageDialog 806 showStatus 927 Sicherheit 45, 961, 1195 Sichtbarkeit 103, 183, 298 sign 1210 Signatur einer Methode 170 Signature 1209
signedjar 1293 signierte Applets 924 signum 419 SimpleBeanInfo 1091 sin 208, 417 SINGLE_INTERVAL_SELECTION 859, 893 SINGLE_SELECTION 859, 893 Singleton-Pattern 234 SINGLE_TREE_SELECTION 911 size 336, 351, 361, 445 Skeleton 1181 skip 453, 470 skipBytes 481 sleep 402, 506 SMPTE-Format 1244 Socket 1152, 1152 SocketException 1158 SocketPermission 1224 Sonstige Operatoren 122 sort 368, 410 SortedMap 351, 368 SortedSet 351, 365 Sortierte Collections 364 Sound 961, 1229 Soundausgabe 47, 933 Soundbanks 1230 -source 1279 -source 1.4 62, 145 -source 1.5 62 SourceDataLine 1232 -sourcepath 1288 SOUTH 683, 694, 822 SOUTHEAST 693, 822 SOUTHWEST 694, 822 Speichermanagement 109, 109 SpinnerDateModel 850 SpinnerListModel 850 SpinnerModel 850 SpinnerNumberModel 850 SplashScreen 803 Sprachmerkmale 43 Sprunganweisungen 142 SQL-2 Entry-Level 990 SQLException 992, 995–995 SQLWarning 996 sqrt 208, 418 Stack 339 Standarderweiterungen 304 Standard-Font 602
1351
Stichwortverzeichnis Standardschriftarten 556 Standard-Sichtbarkeit 183 Standardwert 98 Star Seven 36 start 500, 811, 923, 925, 1235, 1244 Starten der Beispielprogramme 64 startsWith 269 stateChanged 871 Statement 992 static 181, 185, 187, 189–190 static import 208 Statische Initialisierer 190 Statische Methoden 189 Statische Variable 187 Statuszeile des HTML-Browsers 927 Stelligkeit eines Operators 115 stop 502, 811, 926, 934, 1235, 1244 store 344 Stored Procedures 987 -storepass 1293 -storetype 1293 Stream 439 String 48, 99, 108, 265, 278 StringBuffer 48, 108, 275 StringBufferInputStream 472 StringBuilder 275 stringFlavor 677 StringIndexOutOfBoundsException 267, 276 String.intern 125 String-Literale 273 StringReader 453, 455 Strings 263, 265 StringSelection 677 StringTokenizer 272, 706 String-Verkettung 123, 268, 1255 stringWidth 559 StringWriter 442, 444 Stub 1180 Subqueries 1021 subSet 365 substring 267, 267, 274, 1258 subtract 419 Subtraktion 117 Suchen in Zeichenketten 270 SUN HotJava 45 sun.boot.class.path 306 sun.io 442, 454 sun.jdbc.odbc.JdbcOdbcDriver 991 SunWorld '95 37
1352
super 181, 383 super.clone 209 Superklassenkonstruktor 181 Superklassenmethoden 181 supportsCustomEditor 1098 supportsTransactionIsolationLevel 1013 suspend 505 Swing 39, 46, 532, 785 SwingConstants 822 SwingUtilities 796 switch 44, 135, 138 Symantec 38 Symboldarstellung 601 Symmetrische Verschlsselung 1197 Synchronisieren 370, 513 synchronized 349, 503, 516, 1260 Synthesizer 1230, 1239 SysexMessage 1239 System 397 SystemColor 567 System.currentTimeMillis 1275 System.err 1279 Systemfarben 567 System.in 48, 1279 System.out 278, 1279 System.out.print 66 System.out.println 66, 399 System-Properties 397
T TA Trustcenter 1214 TableCellRenderer 903 tableChanged 907 TableColumn 900 TableColumnModel 889, 900 TableModel 889, 896 TableModelListener 896 tailSet 365 tan 417 -target 1279 TargetDataLine 1232 targetEntity 1131 TCP/IP 1144 TCP/UDP 1144 Temporre Dateien 496 text 568–568 TextArea 723 Textausgaben 48 TextComponent 720
Stichwortverzeichnis TEXT_CURSOR 604 TextEvent 611, 618, 722 TextField 720 textHighlight 568–568 textHighlightText 568–568 textInactiveText 568 TextListener 618, 722 textText 568–568 texttop 930 textValueChanged 618, 722 Thawte 1214 this 165, 172, 182, 298 Thread 500 ThreadGroup 526 Thread-Gruppen 526 Threads 499, 762, 874 Thread-Synchronisation 513 throw 295 Throwable 288, 289 throws 225, 294–295 Time 994 Timecodes 1230 Times New Roman 554 TimesRoman 554 Timestamp 994 TimeZone 425 Titelleiste 602 TitledBorder 829 toArray 351 toCharArray 444 toLowerCase 271 Toolkit 556, 754 Toolkit-Pattern 240 Tooltips 786, 795, 830 TOP 822, 930, 945 toString 123, 179, 225, 277, 281, 288, 444–444, 1258 toUpperCase 271, 451 TRACK 732, 1239, 1244 Tracks 1230 TRAILING 822 Transaction Isolation Level 1013 TRANSACTION_NONE 1013 TRANSACTION_READ_COMMITTED 1013 TRANSACTION_READ_UNCOMMITTED 1013 TRANSACTION_REPEATABLE_READ 1013 TRANSACTION_SERIALIZABLE 1013 Transaktionen 1012 Transferable 676 transient 965, 974
Transmitter 1239 Transparente Komponente 833 Transportschicht 1144 TreeMap 365, 368 TreeModel 908 TreeModelEvent 915 TreeModelListener 915 TreeNode 908 TreePath 912 TreeSelectionEvent 912 TreeSelectionListener 912 TreeSelectionModel 911 TreeSet 365 Treibermanager 991 Trigger 987 trim 267, 1258 true 97–98, 99 try 286 try-catch-Anweisung 286 TYPE 1029 Type-Cast-Operator 122 .TYPE-Objekte 1029 Types 1012 Typisierte Klassen 371 Typkonvertierungen 109 Typsicherheit 314 Typberprfungen 102
U UDP 1145 berladen von Methoden 170 berlagern von Methoden 162, 179 bersetzen des Quelltextes 61 UI Delegate 788 UIManager 796 ULAW 1237 UML 90 Umrandungen 795 UnavailableServiceException 330 unbind 1187 unchecked warning 383 UND-Operator 119 Ungarische Notation 70 Ungleichheits-Operator 118 UnicastRemoteObject 1184 Unicode 95, 99–100 Unified Modeling Language 90 Uniform Resource Locator 943 UNION 1021
1353
Stichwortverzeichnis UNIT_DECREMENT 732 UNIT_INCREMENT 732 UnknownHostException 1151 UNKNOWN_NUMBER_OF_PAGES 583 unread 459, 473 UnsupportedLookAndFeelException 796 UnsupportedOperationException 352 Unterlnge 559 Untermens 666 Untersttzung fr XML 40 Unvernderliche Collections 371 unwrapping 1030 update 774, 995, 1019, 1199 updateComponentTreeUI 796 UPPER_LEFT_CORNER 878 UPPER_RIGHT_CORNER 878 URL 943, 944–945, 1175 URLConnection 1175 Usenet-Newsgroups 84 User Datagram Protocol 1145 user.dir 397 user.home 397 user.name 397 user.timezone 393 UTF-8-Codierung 466
V -v1.1 1294 -v1.2 1294 validate 835 Validierung 835 valueChanged 861, 912 valueOf 272 values 230, 362 van Hoff, Arthur 37 Variable Parameterlisten 167 Variablen 102, 134 Vaterklasse 158 -vcompat 1294 Vector 48, 336, 353, 1261 Vernderbarkeit 183 Vernderliche Objekte 359 -verbose 1278, 1281, 1288 -verbosegc 1281 Verdecken von Variablen 298 Vererbung 158, 177 Vergleichen von Zeichenketten 268 verify 1210, 1293 VeriSign 1214
1354
Verkettung 123, 172 Verknpfung auf dem Desktop 71 Verschlsseln 1195 -version 1278, 1280, 1288 Versionierung von Klassen 971 VERTICAL 693, 731, 822 VERTICAL_SCROLLBAR_ALWAYS 878 VERTICAL_SCROLLBAR_AS_NEEDED 878 VERTICAL_SCROLLBAR_NEVER 878 VERTICAL_SPLIT 882 Verwalten von Threads 525 Verweise auf andere Seiten 943 Verzeichniszugriffe 490 Verzweigungen 135 vetoableChange 1079 VetoableChangeListener 1079 VetoableChangeSupport 1080 View einer Collection 361 Viewport 735 Virtuelle Ausgabeflche 734 Virtuelle Maschine 42, 45, 1253 Visitor-Pattern 253 Visual Cafe 38 VK_0 651 VK_9 651 VK_A 650–651 VK_BACK_SPACE 651 VK_DELETE 651 VK_DOWN 651 VK_END 651 VK_ENTER 651 VK_ESCAPE 620, 651 VK_F1 651 VK_F12 651 VK_HOME 651 VK_INSERT 651 VK_LEFT 651 VK_PAGE_DOWN 651 VK_PAGE_UP 651 VK_RIGHT 651 VK_SPACE 651 VK_TAB 651 VK_UNDEFINED 651–652 VK_UP 651 VK_Z 651 Vlissides, John 233 VM 45 void 126, 169, 224, 224 Void.TYPE 1029
Stichwortverzeichnis volatile 187 Vordefinierte Pakete 304 Vordergrundfarbe 602 Vorrangregeln 127 VSPACE 930
W Wahlfreier Zugriff auf Dateien 479 wait 505, 520 WAIT_CURSOR 604 waitFor 406 waitForAll 756 WARNING_MESSAGE 807 Warteliste 520 wasNull 994 Wave-Dateien 47 wav-Format 47, 933, 1231 WebRunner 37 WebStart 322 WEEK_OF_MONTH 389 WEEK_OF_YEAR 389 weightx 694 weighty 694 Weitergabe einer Exception 294 WEST 683, 694, 822 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 837 WHEN_FOCUSED 837 WHEN_IN_FOCUSED_WINDOW 837 WHERE 1020 while 44, 139, 140 white 564 WIDTH 928 Wiederverwendung 157 Wildcards 380 Window 533, 567, 595 windowActivated 617, 634 WindowAdapter 614, 634 windowBorder 568 windowClosed 617, 634 windowClosing 536, 617, 634 WindowClosingAdapter 64, 535 windowDeactivated 617, 634 windowDeiconified 617, 634 Window-Ereignisse 617 WindowEvent 617, 633 Window-Events 633 windowIconified 617, 634 WindowListener 535, 617, 633 windowOpened 617, 634
windowText 568 Winkelfunktionen 417 winzip 468 Wrapper-Klassen 223 write 441, 462 writeBoolean 485, 964 writeByte 485, 964 writeBytes 485, 964 writeChar 485, 964 writeChars 485, 964 writeDouble 485, 964 writeFloat 485, 964 writeInt 485, 964, 967 writeLong 485, 964 write-Methoden 485 writeObject 964 Writer 441, 1263 writeShort 485, 964 writeTo 445 writeUTF 466, 485, 964
X X.509-Zertifikat 1214 -Xclassic 1280 -Xint 1270, 1274, 1280 -Xlint 1279 -Xlint:unchecked 383 -Xmixed 1280 XML-Dateien 305 -Xms 1266, 1281 -Xmx 1281 xor 346 -Xprof 1274 -Xrunhprof 1268, 1274
Y YEAR 389 yellow 564 YES_NO_CANCEL_OPTION 808 YES_NO_OPTION 808 yield 1157
Z ZapfDingbats 557 Zeichenextraktion 267 Zeichenketten 48, 265 Zeichentasten 650 Zeichentyp 99 Zeilenabstand 559
1355
Stichwortverzeichnis Zeitzonen 388 Zeitzonenangabe 393 Zero-Knowledge Proof 1202 Zertifikat 1214 ZipEntry 469 ZipInputStream 476
1356
ZipOutputStream 468 ZONE_OFFSET 390–390 Zufallszahlen 49, 385 Zuweisung 102 Zuweisungsoperatoren 121 Zwischenablage 676
Copyright Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als persönliche Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschließlich
der Reproduktion,
der Weitergabe,
des Weitervertriebs,
der Platzierung im Internet, in Intranets, in Extranets,
der Veränderung,
des Weiterverkaufs und
der Veröffentlichung
bedarf der schriftlichen Genehmigung des Verlags. Insbesondere ist die Entfernung oder Änderung des vom Verlag vergebenen Passwortschutzes ausdrücklich untersagt! Bei Fragen zu diesem Thema wenden Sie sich bitte an: [email protected] Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf unseren Websites ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen. Hinweis Dieses und viele weitere eBooks können Sie rund um die Uhr und legal auf unserer Website herunterladen: http://ebooks.pearson.de