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!
, benGtigen kein schließendes
-Tag. Eine vollst$ndige HTML-Datei enth$lt formatierende und strukturierende Tags: <TITLE>Beispiel HTML-Dokument HTML Demo 180Das Java Development Kit finden Sie auf der JavaSoft Home Page. Das Absatz-Tag (
) verbessert die Lesbarkeit des Dokuments. Ein Webbrowser ignoriert .berz$hlige Leerzeichen und Zeilenumbr.che bei der Darstellung eines Dokuments. Wenn Sie Zeilenumbr.che oder Abs$tze in Ihr Dokument einf.gen wollen, dann m.ssen Sie entsprechend das
-Tag oder das
-Tag verwenden. Nun verf.gt das Beispieldokument .ber Text, Grafik und einen Link, wie in der folgenden Abbildung gezeigt wird:
Abb. 7.7 Ein HTML-Beispieldokument mit Text, Grafik und Hypertext-Link
Ein Java-Applet in ein HTML-Dokument einzuf.gen, ist recht einfach. Es gibt ein <APPLET>",4>-Tag, das die Stelle angibt, an der sich die .class-Datei befindet und welcher Platz im Dokument f.r das Applet bereitgestellt wird. Angenommen, Sie wollen ein Uhr-Applet in Ihr Dokument einf.gen, das die aktuelle Uhrzeit mit Stunden, Minuten und Sekunden anzeigt. Hier ein einfaches Beispiel eines <APPLET>-Tags, das ein Uhr-Applet (Clock.class) l$dt: 183
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Applets, Applikationen und das Java Development Kit
<APPLET CODE="Clock.class" WIDTH=200 HEIGHT=60> Wenn der Webbrowser das <APPLET>-Tag erreicht, wird die VM gestartet und Clock.class geladen. Der VM wird außerdem mitgeteilt, dass vom Applet eine Fl$che von 200x60 Pixel benutzt werden darf. Die Position des <APPLET>-Tags im Dokument bestimmt die Koordinaten der linken oberen Ecke des darstellenden Bereichs des Applets. F.gen Sie die Zeile nun der Beispieldatei hinzu: <TITLE>Beispiel HTML-Dokument HTML Demo Dieses Dokument ist ein HTML Beispiel.
Das Java Development Kit finden Sie auf der JavaSoft Home Page. <APPLET CODE="Clock.class" WIDTH=200 HEIGHT=60> Dieses Dokument kGnnte jetzt zum Beispiel so dargestellt werden:
Abb. 7.8 Das Uhr-Applet eingebettet in ein HTML-Dokument
184
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Erstellen von Applets mit dem JDK
Wie Sie sehen kGnnen, ist das Einbinden von Java-Applets in HTML-Dokumente recht einfach. Java kann Plug-in-Komponenten erzeugen, die von Anf$ngern und Fortgeschrittenen gleichermaßen benutzt werden kGnnen. Damit dieses Komponentenmodell funktionieren kann, muss der HTML-Autor die Eigenschaften und das Verhalten des Applets .ber HTML anpassen kGnnen. Der Java-Programmierer entscheidet, welche Parameter f.r das Applet von Bedeutung sind und der HTMLAutor .bergibt mit dem -Tag die initialen Parameter an das Applet, zum Beispiel so: <APPLET CODE="FilledBox.class" WIDTH=50 HEIGHT=50> Das -Tag akzeptiert zwei Argumente: NAME und VALUE. NAME wird verwendet, um den Namen eines Parameters anzugeben, VALUE .bergibt den entsprechenden Wert. Soweit es Java betrifft, sind alle .bergebenen Parameter StringObjekte, also Zeichenketten, die jedoch leicht in jeden anderen Datentyp umgewandelt werden kGnnen. Die Ausgabe des FilledBox-Applets ist in der folgenden dargestellt. Beachten Sie bitte, dass nur die Ausgabe des Applets dargestellt wird:
Abb. 7.9 Der Applet Viewer bei der Ausf1hrung des FilledBox-Applets aus der Datei FilledBox.html
Enth$lt der Webbrowser eine Java-VM, wird er das Applet darstellen und mit Ausnahme des -Tags alles ignorieren, das sich zwischen den <APPLET>- und -Tags befindet. Webbrowser, die nicht dazu in der Lage sind, Java auszuf.hren, ignorieren die <APPLET>- und -Tags und stellen stattdessen alle g.ltigen HTML Anweisungen zwischen dem <APPLET>- und -Tag dar. Dies ermGglicht es Ihnen, Alternative Inhalte f.r Browser zu erstellen, die kein Java ausf.hren kGnnen. Dies ist besonders wichtig, da nicht alle Anwender Java-Applets ausf.hren kGnnen oder wollen. Wenn Sie Ihre Webseiten f.r jeden Anwender benutzbar machen wollen, dann m.ssen Sie auch solche Anwender ber.cksichtigen, die kein Java ausf.hren kGnnen.
Wie Webbrowser Applets ausfhren Ein Browser, der Java ausf.hren kann, befolgt eine bestimmte Reihenfolge von Schritten, die er ausf.hrt, wenn er im HTML-Dokument auf ein <APPLET>-Tag stGßt:
185
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Applets, Applikationen und das Java Development Kit
1
Der Browser reserviert zur Darstellung des Applets Platz im Dokument. Die Parameter WIDTH und HEIGHT des <APPLET>-Tags geben die Fl$che an, die vom Applet belegt wird.
2
Der Browser liest die Parameter des -Tags aus.
3
Die VM wird gestartet und dazu aufgefordert, das Applet zu laden und zu initialisieren. Das Applet hat Zugriff auf die Namen und Werte innerhalb der -Tags.
4
Die VM erzeugt eine Laufzeitkopie des Applets, basierend auf der .class-Datei.
5
Der Browser ruft die init-Methode auf, damit sich das Applet selbst initialisiert.
6
Die VM ruft die start-Methode des Applets auf, sobald sie dazu bereit ist, das Applet mit der Verarbeitung anfangen zu lassen. Die VM ruft außerdem die paint-Methode auf, um das Applet im Browser darzustellen.
7
Wann immer ein Applet erneut dargestellt werden muss (zum Beispiel wenn der Anwender das Applet in den sichtbaren Bereich des Browsers hineinbewegt), wird paint erneut aufgerufen.
8
Der Browser ruft die stop-Methode auf, wenn der Anwender das gegenw$rtig dargestellte HTML-Dokument durch ein anderes ersetzt.
9
Der Browser ruft die destroy-Methode auf, wenn das Applet aus dem Speicher entfernt wird.
Der Quellcode des Applets Der Quellcode eines Java-Applets wird genau so erstellt wie der Quellcode einer Java-Applikation: mit einem Texteditor. Der Unterschied besteht darin, dass JavaApplets keine main-Methode haben. Stattdessen verf.gen sie .ber einige andere Methoden, die von der VM aufgerufen werden, wenn der Browser diese anfordert. Hier der Quellcode f.r das FilledBox-Applet: import java.awt.*; import java.applet.Applet; /** FilledBox stellt einen farbig ausgefuellten Kasten im Browser / Fenster dar */ public class FilledBox extends Applet { // Diese Variable speichert die Farbe, die im HTML// Dokument als Color boxColor; angegeben wird. Color boxColor; 186
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Erstellen von Applets mit dem JDK
/** Hole die Farbe des Kastens aus der HTML-Datei */ public void init() { String s; s = getParameter("color"); // Die vorgegebene Farbe ist grau. boxColor = new Color ( 0,0,0); // Erwartet wird ein Parameter color, der die // Werte red, white oder blue haben kann. Fehlt // der Parameter, wird s null. if (s != null) { if (s.equals("red")) boxColor = Color.red; if (s.equals("white")) boxColor = Color.white; if (s.equals("blue")) boxColor = Color.blue; } } /** Stelle den Kasten in der dem Applet zugewiesenen * Region dar. Benutze die im HTML-Dokument angege* bene Farbe. */ public void paint(Graphics g) { g.setColor (boxColor); g.fillRect (0, 0, size().width, size().height); } } Dies ist ein wenig komplizierter als das Beispiel der Java-Applikation, aber das liegt daran, dass es mehr macht, als die Applikation. Sie werden sich daran erinnern, dass die main-Methode von allen Java-Applikationen benGtigt wird. Diese fehlt hier. Tats$chlich sind in Applets gar keine Methoden erforderlich. Es gibt jedoch f.nf Methoden, die von der VM aufgerufen werden kGnnen, wenn diese vom Webbrowser (oder Applet Viewer) angefordert werden: public void init() initialisiert das Applet. Wird einmal aufgerufen. public void start() wird aufgerufen, wenn der Browser bereit ist, das initialisierte Applet zu starten. Kann mehrfach aufgerufen werden, wenn der Anwender die Webseite mehrfach aufruft. Wird ebenfalls aufgerufen, wenn das Browserfenster aus dem Status iconified wiederhergestellt wird. public void stop() wird aufgerufen, wenn der Browser die Ausf.hrung des Applets beenden will. Wird aufgerufen, wenn der Anwender die Webseite verl$sst, die das Applet enth$lt. Wird ebenfalls aufgerufen, wenn das Browserfenster in den Status iconified wechselt. public void destroy() wird aufgerufen, wenn der Browser das Applet aus dem Speicher entfernt. public void paint(Graphics g) wird aufgerufen, wenn der Browser das Applet erneut darstellen muss.
187
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Applets, Applikationen und das Java Development Kit
Wenn in dem Applet keine dieser Methoden implementiert ist, wird es f.r die entsprechenden Methoden keine Funktionalit$t f.r die entsprechende Methode aufweisen. In dem Beispiel sind die Methoden init und paint implementiert. Die Methode init() bezieht die Farbe des Kastens aus einem Parameter des HTML-Dokuments, in das es eingebettet ist (Applet-Parameter sind bereits im Abschnitt „HTML fr Java-Applets“ erkl$rt worden.) Speichern Sie diesen Quellcode f.r das Java-Applet unter dem Namen FilledBox.java ab.
Verwenden von javac Der javac-Compiler arbeitet bei Applets genau so, wie Sie dies bereits von den JavaApplikationen her kennen: Javac FilledBox.java Hier einige Tipps, die Ihnen den Start erleichtern sollen: Als Erstes muss ein Applet immer als public deklariert werden oder es wird nicht kompiliert. Weiterhin sollten Sie beachten, dass f.r Java die Schreibweise von Bedeutung ist: filledbox.java ist etwas Anderes als FilledBox.java (und wird nicht kompiliert werden), es wird zwischen GROSSBUCHSTABEN und kleinbuchstaben unterschieden. Wenn der Java-Code f.r den Compiler akzeptabel ist, wird sich die einzige Meldung, die Sie sehen werden, auf ein veraltetes API beziehen: Note: FilledBox.java uses a deprecated API. Recompile with "-deprecation" for details. 1 warning. Im Augenblick kGnnen Sie diese Warnung ignorieren. Solange keine weiteren Fehlermeldungen erscheinen, wird die Datei FilledBox.class erzeugt. Falls weitere Fehlermeldungen ausgegeben wurden, m.ssen Sie Ihren Code .berarbeiten. Es gibt eine Vielzahl von Fehlermeldungen, die Ihr Compiler ausgeben kann, wenn er einen Quellcode bearbeitet. Am einfachsten sind Syntaxfehler zu beheben, wie zum Beispiel ein fehlendes Semikolon oder schließende Klammern. Andere Fehler werden die falsche Verwendung von Variablentypen oder ung.ltige Ausdr.cke oder VerstGße gegen Zugriffsbeschr$nkungen betreffen. Den Quellcode erfolgreich zu kompilieren, ist der erste Schritt des Prozesses der Fehlerbereinigung (so genanntes Debugging). Fehlerfreies Kompilieren garantiert nicht, dass Ihr Programm auch das tut, was Sie wollen. Machen Sie sich aber noch keine Sorgen um das Debugging. Das Beispiel sollte einfach genug sein, dass es ohne Probleme l$uft.
Hinweis
188
Zwischen Java 1.0 und Java 1.1 wurden einige Methoden umbenannt. Bis alle Anwender auf Java 1.1 umgestiegen sind, kann es erforderlich sein, die Java-1.0-Methoden zu verwenden. Sollten Sie einen Java-1.1-f$higen Browser verwenden, kGnnen Sie die size()-Aufrufe gegen getSize() austauschen, um den Warnhinweis zu umgehen.
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Erstellen von Applets mit dem JDK
Bevor Sie Ihr Applet benutzen kGnnen, m.ssen Sie ein HTML-Dokument erstellen, das Ihr Applet ansteuert.
Erstellen einer HTML-Datei Da Sie jetzt bereits .ber grundlegende HTML-Kenntnisse verf.gen, kGnnen Sie sich sehr leicht eine HTML-Datei erstellen, in die Sie Ihr Applet einbinden: <TITLE>Beispiel HTML-Dokument mit FilledBox.class FilledBox Demo
<APPLET CODE="FilledBox.class" WIDTH=50 HEIGHT= 50> Sie kGnnen diese Datei erzeugen, indem Sie das Listing einfach in einen Texteditor eingeben. Speichern Sie die Datei als FilledBox.html. HTML-Dateien kGnnen jeden beliebigen Namen erhalten. Es ist allerdings .blich, die HTML-Dokumente nach den Applets zu benennen, die sie beherbergen. Wenn Sie die HTML-Datei nach dem Applet benennen und dann javadoc auf den Quellcode anwenden, wird die HTML-Datei .berschrieben. Hinweis
Verwenden von appletviewer appletviewer wird verwendet, um das Applet so darzustellen, wie es in einem Browser dargestellt wird, ohne jedoch das HTML-Dokument anzuzeigen. Im Falle der FilledBox.html-Datei wird appletviewer nur das ausgef.llte K$stchen in einem eigenen Fenster darstellen: appletviewer FilledBox.html Sehen Sie unter Abbildung 7.9 nach, um einen Eindruck von der Ausgabe zu bekommen. Zum Vergleich zeigt die folgende Abbildung das HTML-Dokument, wie es zum Beispiel im Netscape Navigator aussehen w.rde. Hier werden der Text und das Applet dargestellt.
189
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Applets, Applikationen und das Java Development Kit
Abb. 7.10 Netscape Navigator stellt die Datei FilledBox.html dar
Wenn in einer HTML-Datei mehr als ein Applet enthalten ist, wird appletviewer f.r jedes Applet ein eigenes Fenster Gffnen. Ein Webbrowser wird alle in einem HTMLDokument enthaltenen Applets in einer Webseite darstellen. Eine angenehme F$higkeit von appletviewer ist die MGglichkeit, Klassen nicht nur aus lokalen Dateien laden zu kGnnen, sondern auch .ber Netzwerke hinweg. -Tag =nderungen Dieses Tag zum Laden von Java-Applets wurde ver$ndert. Sie kGnnen jetzt Ressourcen und andere Objekte angeben, die zusammen mit dem Applet geladen werden.
191
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Applets, Applikationen und das Java Development Kit
(javac) @missbiligtes Tag Der javac-Compiler wird Sie jetzt warnen, wenn Sie Methoden verwenden, die zwar in $lteren Versionen des JDK unterst.tzt werden, aber nicht den in der aktuellen Version bevorzugten Methoden entsprechen. (N$heres .ber alle missbilligten Methoden kGnnen Sie der Java-Plattform 1.3 API-Spezifikation unter http://java.sun. com/products/jdk/1.3/docs/api/index.html entnehmen.)
(jar) Java-Archive Java-Klassen und -Ressourcen, wie zum Beispiel Bilder und TGne, kGnnen nun in komprimierten Archiven zusammengefasst werden, den so genannten .jar-Dateien. Dabei werden digitale Signaturen unterst.tzt und die 0) out.println(byteCount + " bytes written"); } Exceptions sind Objekte mit hierarchischen Beziehungen und Abh$ngigkeiten. Sie kGnnen einen einzelnen Exception Handler erstellen, der eine Reihe von Exceptions einer Klasse abf$ngt und diese dann durch individuelle Unterklassen behandeln l$sst. Das MyCopy-Beispiel demonstriert eine andere MGglichkeit. Die zweite catchAnweisung behandelt die FileNotFoundException und die n$chste jede andere IOException. Die FileNotFoundException ist eine Unterklasse der IOException, so dass Sie jeweils auf Exceptions der Oberklasse und der untergeordneten Klassen .berpr.fen kGnnen. Hier das vollst$ndige Programm: import java.io.*; public class MyCopy { public static void main (String args[]) { int byteCount = 0; String inputFile = null; String outputFile = null; PrintWriter out = new PrintWriter(System.out,true); try { inputFile = args[0]; outputFile = args[1]; byteCount = copyFile(inputFile, outputFile); } catch (ArrayIndexOutOfBoundsException e) { out.println("Usage: java MyCopy [inputFile]" + "[outputFile]"); } catch (FileNotFoundException e) { out.println("Cannot open input file: " +
Listing 9.3 Exception Handling mit Pr1fung der Oberklasse und der untergeordneten Klassen
225
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
inputFile); } catch (IOException e) { out.println("I/O exception occurs!"); } finally { if (byteCount > 0) out.println(byteCount + " bytes written"); } } static int copyFile(String inputFile, String outputFile) throws IOException { int bytesInOneRead, byteCount = 0; byte buffer[] = new byte[512]; FileInputStream fin = new FileInputStream(inputFile); FileOutputStream fout= new FileOutputStream(outputFile); while ((bytesInOneRead = fin.read(buffer)) != -1) { fout.write(buffer, 0, bytesInOneRead); byteCount += bytesInOneRead; } return byteCount; } }
Die Hierarchie der Exception-Klassen Wie fast alles in Java sind auch Exceptions entweder Instanzen von Objekten oder Klassen. Exceptions bilden Klassen aus ihrer eigenen Klassenhierarchie. Der Ursprung aller Klassen von Exceptions ist die Klasse Throwable, die eine unmittelbare Unterklasse der Klasse Object ist. In der Klasse Throwable werden Methoden definiert, mit denen die zu einer bestimmten Exception gehGrenden Fehlermeldungen aufgefunden werden und der Verlauf durch den Stack (die so genannte Stack Trace) ausgegeben werden kann, mit dem wiederum dargestellt wird, wo die Exception auftritt (mehr dazu in Kapitel 10: Schneller und kompatibler durch Java Packages). Die Klasse Throwable hat zwei unmittelbare Unterklassen: die Klasse Error und die Klasse Exception. Die Unterklassen der Klasse Exception sind an der Namensendung Exception erkennbar. Die Unterklassen der Klasse Error haben dagegen die Namensendung Error (zus$tzlich gibt es noch die Klasse ThreadDeath, die ebenfalls eine Unterklasse von Error ist). Die Unterklassen von Error dienen grunds$tzlich der Signalisierung abnormer Systemzust$nde. So signalisiert zum Beispiel ein OutOfMemoryError, dass die Java-VM den gesamten zur Verf.gung stehenden Speicher verbraucht hat und die Garbage Collection keinen weiteren Speicher freimachen kann. Ein StackOverflowErrror signalisiert, dass der Stack im Interpreter .bergelaufen ist. Solche Fehler sind generell nicht behebbar und sollten deshalb auch nicht behandelt werden. 226
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
4bersicht ber das Exception Handling
Die Unterklassen der Klasse Exception gelten dagegen grunds$tzlich als behebbar. So signalisiert zum Beispiel eine EOFException, dass die Datei, die Sie geGffnet haben, keine weiteren Daten mehr enth$lt, die ausgelesen werden kGnnten. Eine FileNotFoundException signalisiert, dass eine Datei, die Sie Gffnen wollen, nicht im Dateisystem existiert. Sie kGnnen sich dazu entscheiden, solche Exceptions zu behandeln, indem Sie diejenigen Statements, deren außergewGhnliche Zust$nde behandelt werden sollen, mit einem try-catch-Block umschließen. Die folgende Abbildung zeigt die hierarchischen Beziehungen zwischen einigen der etwas h$ufiger vorkommenden Errors und Exceptions. Es gibt sehr viel mehr, aber diese sind im Augenblick nicht so sehr von Bedeutung und werden betrachtet, wenn Sie in den Beispielen verwendet werden. Zus$tzliche Informationen .ber Exceptions kGnnen Sie der Onlinedokumentation unter http://www.java.sun.com/ products/jdk/1.3/docs/api/index.html entnehmen.
Abb. 9.1 Hierarchie der 1blichen Exceptions
Die folgenden Beispiele durchlaufen vier pathologische F$lle, in denen das System vier Typen von RuntimeExceptions auswirft: ArithmeticException – F.r außergewGhnliche arithmetische Zust$nde, wie zum Beispiel die Division durch Null. NullPointerException – F.r das Zugreifen auf ein Feld oder das Aktivieren einer Methode eines nicht existierenden Objekts (null object). ArrayIndexOutOfBoundsException – F.r das Zugreifen auf das Element eines Arrays .ber einen Indexwert, der entweder kleiner als Null oder grGßer oder gleich der GrGße des Arrays ist. StringIndexOutOfBoundsException – F.r das Zugreifen auf ein Zeichen in einem String oder StringBuffer mit einem Index, der kleiner als Null oder grGßer oder gleich der L$nge des Strings ist. 227
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
Hier ein Programm, mit dem dies ausprobiert werden kann: Listing 9.4 RuntimeExceptions
import java.io.*; public class ExceptionTest { public static void main(String args[]) { PrintWriter out = new PrintWriter(System.out, true); for (int i = 0; i < 4; i++) { int k; try { switch (i) { case 0: // Division durch Null int zero = 0; k = 911 / zero; break; case 1: // null pointer int b[] = null; k = b[0]; break; case 2: // array index out of bound int c[] = new int[2]; k = c[9]; break; case 3: // string index out of bound char ch = "abc".charAt(99); break; } } catch (Exception e) { out.println("\nTest case #" + i + "\n"); out.println(e); } } } } Die Ausgabe des vorangegangenen Programms kGnnen Sie hier sehen: C:\MasteringJava\Ch07>javac ExceptionTest.java C:\MasteringJava\Ch07>java ExceptionTest Test case #0 java.lang.ArithmeticException: / by zero Test case #1 java.lang.NullPointerException Test case #2 java.lang.ArrayIndexOutOfBoundsException: 9 Test case #3 java.lang.StringIndexOutOfBoundsException: String index outof range: 99
228
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Konstrukte des Exception Handlings
Konstrukte des Exception Handlings Die grunds$tzliche Form eines Konstrukts zum Exception Handling (das try-Statement) ist: try { normalProgramBody } catch (ExceptionClass1 exceptionVariable1) { exceptionHandlerProgramBody1 } catch (ExceptionClass2 exceptionVariable2) { exceptionHandlerProgramBody2 . . . } finally { exitProgramBody } Fr.he Versionen des JDK (vor 1.0.2) benGtigten keine geschweiften Klammern im Rumpf eines try-catch-finally-Konstrukts, wenn der Rumpf des Programms aus einem einzigen Statement bestand. Seit JDK 1.0.2 sind geschweifte Klammern jedoch immer notwendig.
Tipp
Das Schl.sselwort try wird verwendet, um einen Block zu spezifizieren, dessen Exceptions durch die umgebenden catch-Anweisungen behandelt werden sollen. Es kann jede beliebige Anzahl solcher catch-Anweisungen geben. Tritt eine Exception auf, wird der Rumpf des ersten Exception Handlers ausgef.hrt, dessen Klassentyp der Exception dieselbe Klasse oder die Oberklasse der ausgeworfenen Exception ist. Da das Abgleichen der Exceptions sequenziell ausgef.hrt wird, kann es vorkommen, dass ein bestimmter Exception Handler niemals ausgef.hrt wird, wenn dessen catch-Anweisungen zum Beispiel hinter der catch-Anweisung seiner Oberklasse aufgef.hrt sind. So musste zum Beispiel in einem schon vorher dargestellten Beispiel der Handler f.r die FileNotFoundException vor dem Handler der IOException erscheinen, da letztere die unmittelbare Oberklasse der FileNotFoundException ist. Der Compiler .berpr.ft, ob alle Exception Handler erreichbar sind. Wenn Sie zum Beispiel die Reihenfolge der FileNotFoundException und der IOException vertauschen, dann wird der Compiler folgende Fehlermeldung ausgeben: C:\MasteringJava\Ch07>javac MyCopy.java MyCopy.java:16: catch not reached. } catch (FileNotFoundException e) { ^ 1 error Der Programmblock exit, der dem Schl.sselwort finally folgt, wird ausgef.hrt, bevor die Kontrolle .ber das Programm nach außerhalb des programmierenden Konstrukts transferiert wurde. Dies kann mGglicherweise passieren, wenn die Ausf.hrung des Programmrumpfs oder des Exception Handlers beendet wird, ein den Pro229
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
grammfluss unterbrechendes Statement (ein break-, continue- oder return-Statement) erreicht wird oder eine Exception ausgeworfen wird, f.r die es keinen Handler innerhalb des Konstrukts gibt, der diese Exception behandeln kGnnte. Die catch-Anweisung ist optional, genauso wie die finally-Anweisung. Allerdings muss mindestens entweder eine catch- oder eine finally-Anweisung in einem trycatch-finally-Konstrukt existieren. Der Rumpf von exit program ist sehr n.tzlich, wenn Ressourcen freigemacht werden sollen, wie zum Beispiel Datei-Handler, die innerhalb des normalen Programmrumpfes zugewiesen sind. Das folgende Beispiel demonstriert die Effekte der break- und continue-Statements in einer finally-Anweisung. Innerhalb einer verschachtelten Schleife werden benannte und unbenannte break- und continue-Statements ausgef.hrt und der Ablauf mitverfolgt: Listing 9.5 break- und continueStatements
import java.io.*; public class FinallyTest { public static void main(String args[]) { PrintWriter out = new PrintWriter(System.out, true); outerLoop: for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) try { out.println("try before if: i=" + i + ", j=" + j); if ((i == 0) && (j == 1)) continue; else if ((i == 0) && (j == 2)) continue outerLoop; else if ((i == 1) && (j == 0)) break; else if ((i == 2) && (j == 1)) break outerLoop; out.println("try after if: i=" + i + ", j=" + j); } finally { out.println("finally: i=" + i + ", j=" + j + "\n"); } } } Die Ausgabe des Programms wird als N$chstes abgebildet. Sie kGnnen sehen, dass die finally-Anweisung immer ausgef.hrt wird, sobald mit der Ausf.hrung des tryBlocks begonnen wurde:
230
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Konstrukte des Exception Handlings
C:\MasteringJava\Ch07>javac FinallyTest.java C:\MasteringJava\Ch07>java FinallyTest try before if: i=0, j=0 try after if: i=0, j=0 finally: i=0, j=0 try before if: i=0, j=1 finally: i=0, j=1 try before if: i=0, j=2 finally: i=0, j=2 try before if: i=1, j=0 finally: i=1, j=0 try before if: i=2, j=0 try after if: i=2, j=0 finally: i=2, j=0 try before if: i=2, j=1 finally: i=2, j=1 Wird die Exception nicht im aktuellen try-catch-finally-Konstrukt abgefangen, wird es durch den Stack des Programms hindurch nach oben propagiert. Derselbe Prozess zur Erkennung der Exception wird f.r alle umschließenden try-catch-finallyKonstrukte wiederholt, vom innersten zum $ußersten Konstrukt, bis schließlich ein zutreffender Exception Handler gefunden wird. Wird innerhalb der aktuellen Methode kein zutreffender Exception Handler gefunden, wird derselbe Prozess auf das try-catch-finally-Konstrukt der aufrufenden Methode angewandt, wieder vom innersten zum $ußersten Konstrukt, bis eine javac NestedException.java C:\MasteringJava\Ch07>java NestedException Outer try block; Test Case #0 Inner try block Inner ArithmeticException>java.lang.ArithmeticExcepti on: /by zero Inner finally block Outer finally block Outer try block; Test Case #1 Inner try block Inner IndexOutOfBoundsException>java.lang.ArrayIndexOutOfBo undsException: Inner finally block Outer ArrayIndexOutOfBound>java.lang.ArrayIndexOutOfBoundsE xception: Outer finally block Outer try block; Test Case #2 Inner try block Inner IndexOutOfBoundsException>java.lang.StringIndexOutOfB oundsException: String index out of range: 99 Inner finally block Outer finally block main() RuntimeException>java.lang.StringIndexOut OfBoundsException: String index out of range: 99 main() finally block 233
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
Verfgbare Methoden der Exceptions Alle Errors und Exceptions sind Unterklassen der Klasse Throwable und kGnnen deshalb die darin definierten Methoden verwenden. getMessage() – Erhalt der Fehlermeldung, die der Exception oder dem Error zugeordnet ist. printStackTrace() – Ausgabe der Stack Trace, die zeigt, wo die Exception auftritt. toString() – Ausgabe des Namens der Exception zusammen mit der von getMessage() zur.ckgelieferten Mitteilung. getLocalizedMessage() – Ausgabe einer lokalisierten Beschreibung der Exception oder des Errors, der von einer Unterklasse verwendet werden kann, um diese Methode zu .berschreiben oder eine locale-spezifische Mitteilung auszugeben. fillInStackTrace() – Zur Aufzeichnung von Informationen .ber die gegenw$rtigen Zust$nde der Stack Frames f.r den aktuellen Thread innerhalb der Exception oder des Errors. printStackTrace(PrintStream s) – Zur Ausgabe einer Stack Trace entsprechend des Ausgabesystems, die zeigt, wo die Exception auftritt. Die meisten Klassen von Exceptions haben zwei Konstruktoren: einen mit einem String-Argument, um die Fehlermeldung zu setzen, die dann sp$ter durch die Methode getMessage() ausgelesen wird; die andere ohne Argumente. Im zweiten Fall wird die Methode getMessage() null zur.ckgeben. Die gleiche Fehlermeldung wird in die R.ckgabe der Methode toString() eingebettet oder ein Teil der Ausgabe der Stack Trace der Methode printStackTrace() sein. Eine Ausgabe beziehungsweise R.ckgabe der Methoden wird hier als Beispiel gezeigt: *** example of return from getMessage() *** / by zero *** example of return from toString() *** java.lang.ArithmeticException: / by zero *** example of output by printStackTrace() *** java.lang.ArithmeticException: / by zero at NoHandler.inner(NoHandler.java:6) at NoHandler.outer(NoHandler.java:11) at NoHandler.main(NoHandler.java:16)
234
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Konstrukte des Exception Handlings
Das throw-Statement Ein throw-Statement lGst das Auswerfen einer Exception aus. Es wird wie folgt verwendet: throw expression; wobei die Expression .ber eine Instanz der Klasse Throwable (oder einer der vielen Unterklassen davon) evaluiert werden muss. Die h$ufigste Verwendung besteht darin, ein neues Statement einzusetzen, das eine Instanz innerhalb der Expression erzeugt. So wird zum Beispiel das folgende Statement eine IOException mit der Fehlermeldung „kann Verzeichnis nicht finden“ ausgeben: throw new IOException("kann Verzeichnis nicht finden" );
Die throws-Anweisung Eine Methode, die in sich selbst eine Exception auswirft, muss diese Exception selber abfangen, wenn die Exception keine Unterklasse der Klasse Error oder RuntimeException ist. Wenn mehrere Exceptions in einer throws-Anweisung verwendet werden sollen, m.ssen Sie Kommas (,) verwenden, um diese abzutrennen. Das folgende Programmsegment deklariert eine Methode, die eine IOException und eine InterruptedException nach außen propagiert: int readModel(String filename) throws IOException,Int erruptedException Es gibt vier Gr.nde daf.r, dass Exceptions, die Unterklassen von Error oder RuntimeException sind, nicht in einer Methode deklariert oder behandelt werden m.ssen: Wenn Sie eine throws-Anweisung f.r jede Exception, die in einer Methode entstehen kGnnte, abfangen oder deklarieren m.ssen, wird das Programm sehr schwerf$llig und unhandlich. Es ist sehr schwierig, w$hrend des Kompilierens zu .berpr.fen, ob eine entsprechende Exception .berhaupt auftreten kann. So kann zum Beispiel prinzipiell jede Referenz auf ein Objekt eine NullPointerException auswerfen. Sicherzustellen, dass jedes referenzierte Objekt w$hrend der Laufzeit ein nicht-Null-Objekt ist, ist eine sehr aufwendige Arbeit f.r den Compiler, besonders dann, wenn das Objekt als Argument einer Methode .bergeben wird. Die meisten Fehler kGnnen ohne KontrollmGglichkeit des Programmierers auftreten. Vom Programmierer zu verlangen, solche Fehler abzufangen und zu behandeln, macht wenig Sinn. 235
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
Die meisten Exceptions, die w$hrend der Laufzeit auftreten, sind das Ergebnis eines Programmierfehlers. Korrekter Code wird solche Exceptions nicht erzeugen. Der Compiler verl$sst sich auf die Deklaration einer throws-Anweisung, mit der festgestellt wird, ob innerhalb eines Ausdrucks, einer Anweisung oder Methode eine Exception auftreten kann. Die Exceptions, die in einer Methode auftreten kGnnen, sind die Gesamtheit aller Exceptions, die in throws-Statements innerhalb der Methode enthalten sind, sowie alle Exceptions, die in throws-Anweisungen der Methoden enthalten sind, welche innerhalb der Methode aufgerufen werden kGnnten. Der Compiler gibt f.r jede Methode, die nicht alle (nicht-Error/nicht-Laufzeit-) Exceptions innerhalb ihrer throws-Anweisung deklariert, eine Fehlermeldung aus. Ein Beispiel f.r eine solche Fehlermeldung wird hier gezeigt: DontCompile.java:8: Exception java.io.FileNotFoundException must be caught, or it must be declared in the throws clause of this method. FileInputStream fin = new FileInputStream ("BasicException.java"); ^
Erstellen eigener Klassen von Exceptions Wenn Sie eine Methode erstellen, dann haben Sie zwei MGglichkeiten, der aufrufenden Methode abnorme Zust$nde mitzuteilen: Sie verwenden entweder einen vordefinierten Fehlercode als R.ckgabewert oder Sie werfen eine Exception aus. Wenn eine Exception ausgeworfen wird, stehen der aufrufenden Methode automatisch alle Mittel und Wege des Exception Handlings zur Verf.gung, um auf die abnormen Zust$nde reagieren zu kGnnen. Außerdem wird es dem Compiler ermGglicht, zu .berpr.fen, ob diese abnormen Zust$nde korrekt behandelt werden, da solche abnormen Zust$nde in der throws-Anweisung der Methode deklariert werden. Wenn Sie eine Exception auswerfen, kGnnen Sie eine Instanz einer Exception-Klasse erzeugen, die bereits innerhalb der Sprache definiert ist, oder Sie definieren eigene Exceptions. Es kann problematisch sein, eine vordefinierte Exception zu finden, die genau auf die von Ihnen definierte Situation passt. Indem Sie eine vordefinierte Exception verwenden, kann es passieren, dass Sie die Situation f.r den Exception Handler unnGtig erschweren. Der Grund daf.r ist der, dass der Exception Handler eventuell Ihre abnormen Situationen von solchen unterscheiden muss, f.r die diese Klasse urspr.nglich erstellt wurde, wenn beide in einer Methode vorkommen kGnnen. Die .bliche Praxis beim Erstellen von eigenen Klassen-Exceptions ist, eine Unterklasse der Klasse Exception zu erstellen. Dies stellt sicher, dass der Compiler .berpr.ft, ob damit korrekt umgegangen wird. Wenn Sie aber system- oder hardware236
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Beispiel: Altersbedingte Exceptions
orientierte Software erstellen, kann es sinnvoller sein, eine Unterklasse der Klassen Error oder RuntimeException zu erstellen. Sie sollten aber keine Unterklassen von Error oder RuntimeException erstellen, um keine throws-Anweisungen f.r Ihre Methoden entwickeln m.ssen, denn dies entkr$ftet den gesamten Sinn der Verwendung von Exceptions. Da Klassen von Exceptions Objektklassen sind, kGnnen Sie data members haben und in ihnen kGnnen Methoden definiert sein. So weist zum Beispiel die InterruptedIOException, die in java.io definiert wird, eine public instance-Variable BytesTransferred auf, in der die Anzahl der gelesenen oder geschriebenen Bytes abgelegt ist, bevor die Operation unterbrochen wird. Sie kGnnen sich dazu entschließen, eigene Klassen von Exceptions in der Hierarchie zu erzeugen, damit der Handler die MGglichkeit hat, die Oberklasse als Ganzes und die Unterklassen jeweils f.r sich oder beide Klassen gleichzeitig zu verwenden.
Beispiel: Altersbedingte Exceptions Das Beispiel, das in diesem Abschnitt vorgestellt wird, demonstriert, wie eine Hierarchie anwenderdefinierter Klassen von Exceptions f.r die Behandlung abnormer Zust$nde erstellt wird und wie ein Programm zu erstellen ist, das diese anwenderdefinierten Exceptions abnormer Zust$nde verwendet. Im ersten Teil des Beispiels werden Sie eine Hierarchie von Exception-Klassen erstellen, mit der Sie .ber altersbedingte Anomalien berichten kGnnen, wie dies in der folgenden Abbildung dargestellt wird:
Abb. 9.2 Die Hierarchie der Klasse AgeException
Die Wurzel dieser Hierarchie ist die Klasse AgeException. Sie hat ein data member, age, welches das Alter enth$lt, das die Exception auslGst. Diese hat wiederum zwei Unterklassen: OutOfAgeLimitException f.r diejenigen F$lle, in denen das angegebene Alter zu niedrig oder zu hoch ist, um eine bestimmte Aktion auszuf.hren, und IllegalAgeFormatException f.r solche F$lle, in denen das Alter außerhalb des zul$ssigen Bereichs liegt oder ein ung.ltiges Format hat. OutOfAgeLimitException hat ein data member, ageLimit, das die Beschr$nkungen enth$lt, gegen die verstoßen wurde. Das Programm zur Definition dieser Klassen ist unten aufgelistet. Speichern Sie diese Hierarchie von Exceptions in einer Datei mit dem Namen AgeException.java: class AgeException extends Exception { int age; AgeException(String message) { super(message); } AgeException() {
Listing 9.7 AgeException.java
237
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
super(); } } class OutOfAgeLimitException extends AgeException { int ageLimit; OutOfAgeLimitException(int ageLimit, String message ){ super(message); this.ageLimit = ageLimit; } OutOfAgeLimitException(String message) { super(message); } } class TooYoungException extends OutOfAgeLimitException { TooYoungException(int age,int ageLimit, String message) { super(ageLimit, "You are too young to " + message + "."); this.age = age; } TooYoungException() { super("too young"); } } class TooOldException extends OutOfAgeLimitException { TooOldException(int age, int ageLimit, String message) { super(ageLimit, "You are too old to " + message + "."); this.age = age; } TooOldException() { super("too old"); } }
238
class IllegalAgeFormatException extends AgeException { IllegalAgeFormatException(String message) { super(message); } IllegalAgeFormatException() {
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Beispiel: Altersbedingte Exceptions
super("Illegal age format"); } } class NegativeAgeException extends IllegalAgeFormatException { NegativeAgeException(String message) { super(message); } NegativeAgeException(int age) { super("Age must be nonnegative."); this.age = age; } } Wie bei allen Java-Klassen, sind die einzigen Klassen, die in eigenen Dateien gespeichert werden m.ssen, die so genannten public classes, also die allgemein verf.gbaren Klassen. Deshalb kGnnen alle diese Exception-Klassen in einer Datei gesammelt oder jeweils in eigenen Dateien gespeichert werden oder auch in derselben Datei gespeichert werden, wie das Programm AgeExceptionTest, das hier ebenfalls gezeigt wird.
Tipp
Der zweite Teil des Beispiels ist ein Programm, das die vorher erstellte Hierarchie der Exceptions benutzt. Das Programm wird in Schleifen verschiedene Altersgruppen testen und so ermitteln, ob eine Person mit dem angegebenen Alter eine Achterbahnfahrt mitmachen darf. Die Methode rideRollerCoasterAtAge() wird eine TooYoungException auswerfen, wenn das angegebene Alter zu niedrig ist, ein TooOldException, wenn das angegebene Alter zu hoch ist und eine NegativeAgeException, wenn das angegebene Alter negativ ist. Hier das Programm: import java.io.*;
Listing 9.8
public class AgeExceptionTest { static PrintWriter out = new PrintWriter( System.out, true); static void rideRollerCoasterAtAge(int age) throws NegativeAgeException, OutOfAgeLimitException { out.println("Trying to ride a roller coaster at age " + age + "..."); if (age < 0) throw new NegativeAgeException(age); else if (age < 5) throw new TooYoungException(age, 5, "ride a roller coaster");
AgeExceptionTest
239
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Fehler vermeiden durch effektives Exception Handling
else if (age > 45) throw new TooOldException(age, 45, "ride a roller coaster"); out.println("Riding the roller coaster...."); } public static void main(String args[]) { int ages[] = {-3, 2, 10, 35, 65}; for (int i = 0; i < ages.length; i++) try { rideRollerCoasterAtAge(ages[i]); out.println("Wow! What an experience!"); } catch (OutOfAgeLimitException e) { out.println(e.getMessage()); if (ages[i] < e.ageLimit) out.println((e.ageLimit - ages[i]) + " more years and you'll be able to try it."); else out.println((ages[i] - e.ageLimit) + " years ago riding it was like a " + " piece of cake."); } catch (NegativeAgeException e) { out.println(e.getMessage()); } finally { out.println(); } } } Die Ausgabe des Beispielprogramms ist hier dargestellt: C:\MasteringJava\Ch07>javac AgeException.java C:\MasteringJava\Ch07>javac AgeExceptionTest.java C:\MasteringJava\Ch07>java AgeExceptionTest Trying to ride a roller coaster at age -3... Age must be nonnegative. Trying to ride a roller coaster at age 2... You are too young to ride a roller coaster. 3 more years and you'll be able to try it. Trying to ride a roller coaster at age 10... Riding the roller coaster.... Wow! What an experience! Trying to ride a roller coaster at age 35... Riding the roller coaster.... Wow! What an experience! 240
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Ausblick
Trying to ride a roller coaster at age 65... You are too old to ride a roller coaster. 20 years ago riding it was like a piece of cake.
Ausblick In Kapitel 10: Schneller und kompatibler durch Java Packages wird die am h$ufigsten verwendeten Java packages behandeln, inklusive derer, die Sprachen, Grafiken, Internetprogrammierung und Swing unterst.tzen.
241
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Schneller und kompatibler durch Java Packages
Java-Pakete und die Klassenhierarchie
244
java.lang – Hauptuntersttzung der Sprache
246
Das Paket java.util – ntzliche Sprachuntersttzung
253
Das Paket java.io – Dateien und Ein-/AusgabestrBme
259
Das Paket java.awt – das Herz der Hierarchie
264
Das Paket javax.swing
275
Das Paket java.net – Untersttzung fr Internet, Web und HTML
281
Ausblick
285
10
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Schneller und kompatibler durch Java Packages
Aus „Mastering Java 2“ von John Zukowski, ISBN 0-7821-2180-2, $49,99, 1280 Seiten
Dieses Kapitel f.hrt Java-Pakete ein und konzentriert sich dabei auf die sieben Pakete, die am h$ufigsten benGtigt werden. Bevor Sie jedoch mehr .ber einzelne Pakete erfahren, werden Sie sehen, wie diese Pakete in die Klassenhierarchie von Java passen.
Java-Pakete und die Klassenhierarchie Java ist von Anfang an objektorientiert. Wie alle objektorientierten Sprachen kommt auch Java mit einem Standardsatz unterst.tzender Klassen, wohingegen Hybriden, wie zum Beispiel C++, erst jetzt standardisierte Bibliotheken erhalten. Die Klassen von Java unterscheiden sich von bekannten Bibliotheken, wie sie prozeduralen Sprachen wie C oder Pascal beiliegen. Da diese unterst.tzenden Klassen das volle Potenzial der objektorientierten Sprachen aufdecken, .bertreffen sie einfache Bibliotheken. Das Vererben von Klassen ist bei weitem die bekannteste und auch leistungsf$higste verwendete F$higkeit (siehe auch Kapitel 1: Erstellen der ersten Java-Beispiele und Kapitel 8: Arbeiten mit Java-Objekten f.r weitere Informationen .ber Klassenvererbung). Die gesamte Java-Hierarchie kann aus zwei Blickwinkeln betrachtet werden: als eine objektorientierte Vererbungshierarchie und als eine Gruppe von Klassen in Paketen. Die Vererbungshierarchie gruppiert Klassen in Pakete, die sich gemeinsame Aspekte der Implementierung teilen (Code oder Variablen). Java-Pakete sammeln einfach nur Klassen auf einer sehr pragmatischen Grundlage: Klassen mit verwandter Funktionalit$t werden im selben Paket geb.ndelt, unabh$ngig davon, ob sie Code oder Daten gemeinsam haben oder nicht. Zus$tzlich zu den offensichtlichen Vorteilen der Strukturierung verwenden Pakete zus$tzlich eine Partitionierung im Namensraum. Das bedeutet, dass jede Klasse, die in einem Paket enthalten ist, einen eindeutigen Namen hat, der nicht mit anderen Namen, die an anderer Stelle definiert sind, kollidieren kann. So kGnnten zwei Firmen zum Beispiel problemlos Klassen mit dem gleichen Namen vertreiben. Eine Klasse mit Sortieralgorithmen der Firma Mango Macrosystems kGnnte beispielsweise mango.utilities.Bubble heißen, w$hrend ein vergleichbares Produkt der Firma Sun-So-Soft sosoft.utils.Bubble heißt. Die Klassennamen sind gleich, aber Java verwendet die Namen der Pakete und Unterpakete, um Klassen voneinander zu unterscheiden. Das strikte Schema der einfachen Vererbung der Sprache bestimmt den Weg, auf dem die Standardklassen von Java im Sinne der objektorientierten Vererbung miteinander in Beziehung stehen. Der daraus entstehende Vererbungsbaum ist deshalb ein reiner Baum und kein Graph, wie dies bei anderen objektorientierten mehrfach vererbenden Hierarchien der Fall ist. Mehrfachvererbung ist in den JavaKlassen auf die eine oder andere Art durch den m$chtigen Mechanismus der Schnittstellenbildung der Sprache realisiert.
244
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java-Pakete und die Klassenhierarchie
Mehrfache Vererbung gegen einfache Vererbung Mehrfache Vererbung ist ein Mechanismus, der es einer Kasse erm"glicht, von mehr als einer Oberklasse zu erben. Dies erzeugt den Netzeffekt, der aus dem Mischen von Charakteristika mehrerer Klassen eine neue Klasse entstehen lsst. Die Mehrfachvererbung wurde eingefhrt, um die beschrnkenden Effekte der Einfachvererbung zu umgehen. Angenommen, Sie htten zum Beispiel eine einfachvererbende Hierarchie, die sich in zwei fundamentale Unterbume aufteilt: „lebendig“ und „nicht bewegt“. Aus „lebendig“ verzweigt sich der Arm der unmittelbar folgenden Unterklassen Pflanze – Obstbaum – Banane. Der aus dem „nicht bewegt“ hervorgehende Zweig k"nnte auch einen sehr sinnvollen Zweig haben, der Lebensmittel enthlt. Aus offensichtlichen Grnden m"chten Sie die Banane auch in diesen Zweig mit einbinden. Einfachvererbung lsst dies nicht zu. Sie k"nnen aus einer Oberklasse ererben, nicht aus zwei oder mehr. Der hier gezeigte einfachvererbende Baum illustriert die Beschrnkungen der reinen Einfachvererbung.
Abb. 10.1 Schematische Darstellung des Prinzips der einfachen Vererbung
Da Sie .ber Pakete eine ganze Hierarchie sehr einfach handhaben kGnnen, werden diese nun Ihr Wegweiser sein, w$hrend Sie die Hierarchie von Java kennen lernen. Das Release 2 von Java hat ca. 60 java.*-Pakete. Dieses Kapitel betrachtet die sieben meistverwendeten Pakete: java.lang enth$lt die Hauptunterst.tzungsmodule der Sprache. Diese befassen sich mit Objekt-Wrappern, Strings, Multithreading und verwandten Bereichen.
245
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Schneller und kompatibler durch Java Packages
java.util enth$lt die eher werkzeugartigen Unterst.tzungsklassen. Diese beinhalten Klassen zum Sammeln und Kalenderklassen, aber auch einige n.tzliche abstrakte Designs die durch die Schnittstellen von Comparator, Iterator und Observer kodiert sind. java.io bietet ger$teunabh$ngige Ein-/Augabedienste f.r Dateien und DatenstrGme an. java.awt verbirgt den Großteil der grafischen Klassen. Da hier das Java Abstract Toolkit (AWT) und zwGlf Unterklassen enthalten sind, kann dieses Paket als Herzst.ck der Hierarchie angesehen werden. javax.swing bietet Klassen f.r Komponenten, Steuerungen auf .bergeordneter Ebene (so genannte higher-level controls) und Anschlussstellen f.r den $ußeren Eindruck eines Programms (das so genannte Look-and-Feel). java.net kombiniert die Klassen, die Programmierung f.r das Internet auf den unteren Schichten anbieten. Zus$tzlich wird Unterst.tzung f.r das World Wide Web und HTML angeboten. java.applet enth$lt eine einzige Klasse, die Unterst.tzung f.r in HTML eingebettete Java-Applets anbietet.
java.lang – Hauptunterst,tzung der Sprache Das Paket java.lang als Sammlung von Klassen ist kurz und knapp gehalten. Die Mehrzahl der java.lang-Klassen erweitern direkt die Klasse Object, welche die Wurzel f.r die gesamte Klassenhierarchie von Java ist und nicht nur f.r java.lang. Die Unterhierarchie Number ist ein gutes Beispiel daf.r, wie objektorientierte Vererbung funktioniert und wann diese angewendet werden soll. Die Klassen Byte, Short, Long, Float und Double haben Faktoren gemeinsam. Deshalb wurde eine Oberklasse geschaffen, die diese gemeinsamen Eigenschaften enth$lt (eingekapselt, engl. encapsulate). Beachten Sie, dass die Klasse Number auch als abstrakt deklariert ist. Sie kGnnen keine Objekte direkt aus einer abstrakten Klasse erzeugen (Instanzen bilden, engl. instantiate). Dies ist nur mit konkreten Klassen mGglich. Obwohl es .blich ist, dass eine .bergeordnete Klasse (superclass) abstrakt ist, ist dies keinesfalls notwendig. Konkrete Klassen kGnnen die lokale Wurzel ganzer Unterhierarchien sein (die Klasse Object ein herausragendes Beispiel daf.r). Von allen Paketen ist java.lang außergewGhnlich, da es das einzige Paket ist, das Sie niemals explizit in Ihre Programme importieren m.ssen. Der Compiler .bernimmt dies, indem er implizit die folgende Zeile an den Anfang aller Ihrer Quellcodedateien schreibt: import java.lang.*; 246
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
java.lang – Hauptuntersttzung der Sprache
Der Stern (*) in dieser Zeile bedeutet, dass alle Klassen des Pakets importiert werden. Dies importiert allerdings keine Klassen in Unterpaketen. Das Paket java.lang erh$lt eine Sonderbehandlung, weil einige der Klassen so tiefe Schichten der Programmierung ansprechen, dass sie als Teil des Java-Sprachkerns betrachtet werden. Die Trennlinie zwischen der Sprache und den externen Bibliotheken kann vielleicht f.r Sprachentwickler von Bedeutung sein, aber f.r die Programmierer von Anwendungen ist diese Problemstellung von eher akademischer Natur. BASIC hat zum Beispiel die Kommandos zur Manipulation von Strings als Teil der Sprachdefinition deklariert. Auf der anderen Seite verl$sst sich C auf externe (aber intern reorganisierte) Standardbibliotheken von Funktionen, um diese Aufgaben zu erledigen. Da sich Java mehr an die Philosophie von C anlehnt, nach der der Kern einer Sprache so einfach wie mGglich sein soll, verl$sst es sich ebenfalls auf eine externe Ansammlung von Methoden, die sich an alles richten, was .ber die grunds$tzliche Datenverarbeitung und algorithmische Steuerung hinausgeht. Die folgenden Typen von Klassen sind im Paket java.lang enthalten: Typewrapper-Klassen Unterst.tzungsklassen f.r String Eine Klasse, in der die mathematische Bibliothek enthalten ist Unterst.tzungsklassen f.r das Multithreading Unterst.tzungsklassen f.r den Systemzugriff auf den unteren Schichten (low-level system access) Error- und Exception-Klassen Im folgenden Abschnitt werden diese Klassen n$her betrachtet.
Die Typewrapper-Klassen Java arbeitet mit zwei unterschiedlichen Arten von Entities: primitiven Typen und echten Objekten. Zahlen, boolesche Werte und Zeichen verhalten sich sehr $hnlich, wie die aus prozeduralen Sprachen wie C, Pascal oder sogar C++ bekannten Entsprechungen. Andere objektorientierte Sprachen, wie zum Beispiel Smalltalk, behandeln diese primitiven Typen nicht auf dieselbe Art. Smalltalk verwendet zum Beispiel f.r alles Objekte: Zahlen sind Objekte, Zeichen sind Objekte und so weiter. Obwohl Smalltalk in einer Zeit entstand, die von Lochkarten dominiert wurde (1972), stellt diese Sprache noch immer die Referenz in Sachen objektorientierte Sprachen dar. Jede seit Smalltalk entwickelte objektorientierte Sprache hat seitdem versucht,
Hinweis 247
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Schneller und kompatibler durch Java Packages
besser zu sein als Smalltalk, aber die meisten haben es nur mit M.he geschafft, mit Smalltalk gleich zu ziehen. Als rein objektorientierte Sprache gesehen kommt Java Smalltalk sehr nahe. Obwohl Java durchweg objektorientiert ist, verwendet es aus Gr.nden der Performance f.r die meisten primitiven Typen keine Objekte, weil das Manipulieren primitiver Typen ohne den objektorientierten Overhead ein wenig effizienter ist. Allerdings ist eine gleichfGrmige und konsistente Umgebung, die nur aus Objekten besteht, sehr viel einfacher und kann deshalb deutlich leistungsf$higer sein. Java enth$lt viele Untersysteme, die ausschließlich mit Objekten arbeiten kGnnen. Mit der Zahl solcher Untersysteme h$ufen sich die F$lle, in denen das System dazu in der Lage sein soll, direkt mit Zahlen, booleschen Werten und Zeichen umzugehen. Wie umgeht nun Java dieses Dilemma? Indem es die primitiven Typen in eine Art Zuckermantel der Objekte verpackt (wrapping). Sie kGnnen zum Beispiel sehr leicht eine Klasse erzeugen, deren einziger Zweck das Einkapseln einer einzelnen Integerzahl ist. Der Netzeffekt w$re, dass es ein Integerobjekt g$be, dem die Universalit$t und Macht zu Eigen w$re, die nur im Zusammenhang mit Objekten zu erreichen ist, allerdings auf Kosten eines gewissen Verlustes an Performance. Das Paket java.lang enth$lt solche Typewrapper-Klassen f.r alle primitiven Java-Typen: Klasse Integer f.r Typ int Klasse Long f.r Typ long Klasse Byte f.r Typ byte Klasse Short f.r Typ short Klasse Float f.r Typ float Klasse Double f.r Typ double Klasse Character f.r Typ char Kasse Boolean f.r Typ boolean Klasse Void f.r Typ void Unter den nummerischen Typen sind die Klassen Integer, Long, Byte, Short, Float und Double so $hnlich, dass sie sich alle aus einer abstrakten Oberklasse mit dem Namen Number ableiten. Grunds$tzlich erlaubt jede einzelne dieser Klassen das Erstellen eines Objekts aus dem $quivalenten primitiven Typ und umgekehrt.
248
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
java.lang – Hauptuntersttzung der Sprache
Die String-Klassen Es existieren in java.lang zwei Klassen, die Strings unterst.tzen: String und StringBuffer. Die Klasse String unterst.tzt Strings, die nur ausgelesen werden, w$hrend die Klasse StringBuffer modifizierbare Strings unterst.tzt. Obwohl beide Klassen offensichtlich einige Dinge gemeinsam haben, sind sie doch insofern unabh$ngig voneinander, als dass keine von beiden von einer gemeinsamen String-Oberklasse erbt. Die Klasse String enth$lt folgende Funktionalit$t: Sich auf die String-L$nge beziehende Funktionen Teilstringentnahme Teilstring-Suche und -Vergleich String-Vergleich, neben vielen anderen auch unter Verwendung der Schnittstelle Comparable Umwandlung zwischen Groß- und Kleinschreibung Entfernen vorausgehender und folgender Leerzeichen Umwandlung in und aus char-Arrays Umwandlung von primitiven Typen in String-Typen Aneinanderh$ngen von Strings (umgewandelt aus jedem Typen, inklusive Objekten) Einf.gen von Strings (wieder umgewandelt aus jedem Typen) Die Methoden zur Umwandlung und Entfernung von Leerzeichen scheinen dem Ansatz der nur lesenden String-Operationen zu widersprechen. Dies stimmt, aber die Klasse String durchbricht nicht ihre eigenen Regeln. W$hrend dieser Operationen werden von der Klasse String neue Strings erzeugt, aus denen nur gelesen wird, die jedoch unbemerkt w$hrend des Prozesses wieder verworfen werden. Im Gegensatz dazu konzentriert sich die Klasse StringBuffer auf solche Operationen, die typischerweise den String selbst oder seine L$nge ver$ndern.
Die Bibliothekenklasse Math Die Klasse Math fasst eine typische und recht konservative Sammlung mathematischer Funktionen zusammen. Die zur Verf.gung stehenden Funktionen lassen sich wie folgt klassifizieren: 249
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Schneller und kompatibler durch Java Packages
Absolute Werte, Ober- und Untergrenzen, Minimal- und Maximalfunktionen. Diese sind angemessen .berladen, so dass Sie jeden nummerischen Typ an diese Funktionen .bergeben kGnnen, ohne dass Ihre Argumente in andere Typen gewandelt werden und dabei mGglicherweise an Genauigkeit verlieren. Quadratwurzel, Potenzierung, Logarithmus und Exponenzialfunktionen. All diese Funktionen nehmen ausschließlich Werte doppelter Genauigkeit an und geben auch nur solche zur.ck (Double und nicht Float ist der vorgegebene Typ f.r die Gleitkommagenauigkeit in Java). Sie brauchen andere Typen (wie zum Beispiel Int oder Float), die Sie an diese Funktionen .bergeben, nicht zu wandeln, da der Compiler automatisch kompatible Argumente f.r Sie umwandelt. Eine Konstante f.r die Basis des Logarithmus ist als doppeltgenauer Wert in Math.E definiert. Trigonometrische Funktionen (sin, cos, tan, asin, acos, atan). All diese Funktionen arbeiten mit Winkeln, die in Radianten und nicht in Grad dargestellt sind. Ein Vollkreis in Radianten hat 2xPi Radianten (entgegen 360 Grad). Pi ist bequem erreichbar mit doppelter Genauigkeit als Konstante Math.PI in der Klasse Math definiert. Ein Funktion zur Erzeugung von Pseudozufallszahlen. Eine Methode random() wird angeboten, die als Grundlage f.r Zufallszahlen in Applikationen verwendet werden kann. Zufallszahlen sind von besonderer Bedeutung in Simulationen, statistischen Auswertungen und nat.rlich Spielen.
Die Untersttzungsklassen fr Multithreading Zwei Klassen, Thread und ThreadGroup und eine Schnittstelle, Runnable, sind 2) gbc.anchor = GridBagConstraints.SOUTHEAST; gbl.setConstraints(checkboxes[i], gbc); cboxPanel.add(checkboxes[i]); } spreadPerRadio = (float)(maxValue-minValue) / 4.0f; // Rollbalken erstellen und hinzuf:gen Panel cboxSbarPanel = new Panel(); cboxSbarPanel.setLayout(new GridLayout(2, 1)); cboxSbarPanel.add(cboxPanel); bar = new Scrollbar(Scrollbar.HORIZONTAL, value, 0, minValue, maxValue); bar.addAdjustmentListener(this); cboxSbarPanel.add(bar); Panel restrictorPanel = new Panel(); restrictorPanel.setLayout(new BorderLayout()); restrictorPanel.add(cboxSbarPanel, BorderLayout.SOUTH); add(restrictorPanel, BorderLayout.CENTER);
357
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Benutzerdefinierte Komponenten
// Alle untergeordneten Komponenten mit dem // aktuellen Wert aktualisieren reviseScrollbar(); reviseTextfield(); reviseRadios(); } public int getValue() { return(value); } public synchronized void setValue(int newValue) { value = newValue; reviseScrollbar(); reviseTextfield(); reviseRadios(); notifyListeners(); } public void addAdjustmentListener( AdjustmentListener listener) { if (!listeners.contains(listener)) listeners.addElement(listener); } public void removeAdjustmentListener( AdjustmentListener listener) { listeners.removeElement(listener); } private void notifyListeners() { AdjustmentListener listener;
358
AdjustmentEvent event = new AdjustmentEvent( this, 0, 0, value); Vector copyOfListeners = (Vector)(listeners.clone()); Enumeration enum = copyOfListeners.elements(); while (enum.hasMoreElements()) { listener = (AdjustmentListener) enum.nextElement(); listener.adjustmentValueChanged(event); }
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Gruppierung: die Komponente ThreeWay
} private void reviseScrollbar() { bar.setValue(value); } private void reviseTextfield() { textfield.setText((new Integer(value)). toString()); } private void reviseRadios() { float f = (value - minValue) / spreadPerRadio; int nth = Math.round(f); if (nth < 0) { nth = 0; } else if (nth > 4) { nth = 4; } cbgroup.setSelectedCheckbox(checkboxes[nth]); }
// // Wird aufgerufen, wenn der Rollbalken bewegt // wird // public synchronized void adjustmentValueChanged( AdjustmentEvent e) { value = e.getValue(); reviseRadios(); reviseTextfield(); notifyListeners(); } // // Wird aufgerufen, wenn ein Optionsfeld // angeklickt wird // public synchronized void itemStateChanged( ItemEvent e) {
359
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Benutzerdefinierte Komponenten
// Nur auf das aktivierte Optionsfeld reagieren if (e.getStateChange() != ItemEvent.SELECTED) return; // Neuen Wert feststellen int newValue = minValue; for (int i=0; ijavac ThreeWay.java C:\JavaDevHdbk\Ch03>javac ThreeWayTest.java C:\JavaDevHdbk\Ch03>appletviewer ThreeWayTest.html
Unterklassen von Standardkomponenten: Textfelder mit G,ltigkeitspr,fung Bei vielen Programmen ist es erforderlich, die Benutzereingaben auf deren G.ltigkeit zu .berpr.fen. Beispielsweise kann es sein, dass die Eingaben nummerisch sein sollen, in einem bestimmten Bereich liegen oder mit einer bestimmten Eingabemaske .bereinstimmen m.ssen. Da in der Standardklasse AWT TextField keine G.ltigkeitspr.fungen vorgesehen sind, m.ssen Sie zum Hinzuf.gen dieser Funktion eine benutzerdefinierte Komponente erstellen. Zu diesem Zweck werden im folgenden Beispiel zwei Alternativen entwickelt: eine einfache IntTextField-Komponente zur java MethodTest Auf das Ende des ersten Thread warten... Erster Thread beginnt mit der Ausf:hrung. Zweiter Thread beginnt mit der Ausf:hrung. Zweiter Thread unterbricht sich selbst. Erster Thread beendet die Ausf:hrung. Eine lange Wartezeit! Zweiten Thread aktivieren... Auf das Ende des zweiten Thread warten... Zweiter Thread wird fortgesetzt und beendet. Bereit f:r den Schluss. Das Schl.sselwort synchronized wird in dem sp$tere Abschnitt „Multithreading fr Fortgeschrittene“ kurz erl$utert. Hinweis 415
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
Die Lebensdauer von Threads Nach der Erzeugung und vor der Freigabe eines Threads befindet sich der Thread immer in einem der folgenden vier Zust$nde: neu erzeugt, ausfhrbar, blockiert oder tot (dead). Diese Zust$nde sind in der folgenden Abbildung 14.1 dargestellt und werden in den n$chsten Abschnitten beschrieben.
Abb. 14.1 Die Lebensdauer von Threads
Neu erzeugte Threads Ein Thread erh$lt sofort nach der Erzeugung den Status neu erzeugt, d.h. dieser Status wird direkt erreicht, nachdem die Anweisung new zur Thread-Erzeugung ausgef.hrt wurde. In diesem Zustand werden die lokalen Datenelemente zugewiesen und initialisiert, aber die Ausf.hrung der Methode run() wird erst begonnen, wenn die Methode start() aufgerufen wird. Nach dem Aufruf der Methode start() wird der Thread in den Status ausfhrbar gesetzt.
Ausfhrbare Threads Wenn sich ein Thread in dem Status ausfhrbar befindet, besteht der Ausf.hrungskontext bereits und der Thread kann jederzeit ausgef.hrt werden, d.h., er wartet nicht darauf, dass ein Ereignis eintritt. Zur besseren Erkl$rung kann dieser Status in zwei Unterzust$nde aufgeteilt werden: in den Status gerade ausgefhrt und in den Status wartend. Wenn sich ein Thread in dem Zustand gerade ausgefhrt befindet, werden ihm CPU-Zyklen zugewiesen und er wird tats$chlich gerade verarbeitet. Ein Thread in dem Zustand wartend befindet sich in der Warteschlange und konkurriert mit anderen Threads um CPU-Zyklen. Der javac ThreadInfo.java C:\MasteringJava\Ch08>java ThreadInfo Thread-Gruppe: system; Max. Priorit[t: 10 Thread: Signal dispatcher; Priorit[t 10 [D[mon] [Aktiv] Thread: Reference handler; Priorit[t 10 [D[mon] [Aktiv] Thread: Finalizer; Priorit[t: 8 [D[mon] [Aktiv] Thread-Gruppe: main; Max. Priorit[t: 10 Thread: main; Priorit[t: 5 [Aktiv] javac ThreadInfo.java harpoon:/users/me/java/examples/ch8>java ThreadInfo Thread-Gruppe: system; Max. Priorit[t: 10 Thread: Clock; Priorit[t: 12 [D[mon] [Aktiv] Thread: Idle thread; Priorit[t: 0 [D[mon] [Aktiv] Thread: Async Garbage Collector; Priorit[t: 1 [D[mon] [Aktiv] Thread: Reference handler; Priorit[t: 10 [D[mon] [Aktiv] Thread: Finalizer; Priorit[t: 8 [D[mon] [Aktiv] Thread: SoftReference sweeper; Priorit[t: 9 [D[mon] [Aktiv] Thread-Gruppe: main; Max. Priorit[t: 10 Thread: main; Priorit[t: 5 [Aktiv] javac Deposit.java C:\MasteringJava\Ch08>java Deposit #1 Versuch einer Einzahlung von 1000 #1 Kontostand abrufen... #2 Versuch einer Einzahlung von 1000 #2 Kontostand abrufen... #1 Ermittelter Kontostand: 1000 #1 Kontostand festlegen... #2 Ermittelter Kontostand: 1000 #2 Kontostand festlegen... #1 Neuer Kontostand ist 2000 #2 Neuer Kontostand ist 2000 *** Endkontostand betr[gt 2000 426
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Das Java-Monitormodell fr die Synchronisierung Java verwendet zum Synchronisieren des Datenzugriffs ein so genanntes Monitormodell. Monitor beschreibt in diesem Zusammenhang eine Art von .berwachtem Ort, an dem alle Ressourcen durch dasselbe Schloss gesch.tzt sind. Nur ein einziger Schl.ssel passt zu allen SchlGssern in einem Monitor. Ein Thread muss zun$chst den Schl.ssel erhalten, bevor er in den Monitor gelangen und auf die gesch.tzten Ressourcen zugreifen kann. Wenn mehrere Threads gleichzeitig in den Monitor gelangen wollen, wird nur einem einzigen der Schl.ssel .bergeben, alle anderen m.ssen vor dem Monitor warten, bis der Thread mit dem Schl.ssel die Ressourcen nicht mehr benGtigt und den Schl.ssel wieder an die virtuelle Maschine von Java zur.ckgibt. Sobald ein Thread den Schl.ssel zu einem Monitor erh$lt, kann er auf die von diesem Monitor .berwachten Ressourcen zugreifen, so oft und so lange er den Schl.ssel besitzt. Wenn der Thread mit dem Schl.ssel jedoch auf Ressourcen zugreifen muss, die von einem anderen Monitor kontrolliert werden, benGtigt der Thread den Schl.ssel dieses Monitors. Ein Thread kann jederzeit die Schl.ssel zu mehreren Monitoren und unterschiedliche Threads kGnnen gleichzeitig die Schl.ssel zu verschiedenen Monitoren besitzen. Wenn mehrere Threads darauf warten, jeweils den Schl.ssel von einem anderen Thread zu erhalten, kann es zu Deadlocks kommen. In Java handelt es sich bei von Monitoren gesch.tzten Ressourcen um Programmfragmente in Form von Methoden oder AnweisungsblGcken, die in geschweifte Klammern eingeschlossen sind. Wenn auf bestimmte Daten nur .ber von demselben Monitor gesch.tzte Methoden oder BlGcke zugegriffen werden kann, ist der Datenzugriff indirekt synchronisiert. Mit dem Schl.sselwort synchronized geben Sie an, dass die folgende Methode oder der folgende Anweisungsblock von einem Monitor synchronisiert werden soll. Wenn ein Anweisungsblock synchronisiert werden soll, muss unmittelbar nach dem Schl.sselwort synchronized eine in Klammern eingeschlossene Objektinstanz folgen, damit die virtuelle Maschine von Java dar.ber informiert wird, welcher Monitor .berpr.ft werden muss. Einen Monitor kGnnen Sie sich auch als bewachten Parkplatz vorstellen, wobei alle synchronisierten Methoden und BlGcke die Autos darstellen, die gefahren (bei Threads ausgef.hrt) werden kGnnen. Alle Autos benutzen denselben Schl.ssel. Dieser Schl.ssel ist erforderlich, um auf den Parkplatz zu gelangen und Autos so lange zu fahren, bis der Schl.ssel zur.ckgegeben wird. Eine andere wartende Person erh$lt dann den zur.ckgegebenen Schl.ssel und kann mit den gew.nschten Autos fahren. Die folgende Abbildung illustriert dieses Modell. Die Methode deposit() aus dem vorherigen Beispiel kann synchronisiert werden, damit nur ein Thread zur gleichen Zeit ausgef.hrt wird. Dazu muss nur das Schl.sselwort synchronized vor der Methodendefinition eingef.gt werden: synchronized void deposit(int amount, String name) {
427
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
Abb. 14.2 Threads benjavac Deposit.java C:\MasteringJava\Ch08>java Deposit #1 Versuch einer Einzahlung von 1000 #1 Kontostand abrufen... #1 Ermittelter Kontostand: 1000 #1 Kontostand festlegen... #1 Neuer Kontostand ist 2000 #2 Versuch einer Einzahlung von 1000 #2 Kontostand abrufen... #2 Ermittelter Kontostand: 2000 #2 Kontostand festlegen... #2 Neuer Kontostand ist 3000 *** Endkontostand betr[gt 3000 Ein Anweisungsblock kann auch folgendermaßen in der Methode deposit() f.r das aufgerufene Objekt synchronisiert werden: void deposit (int amount, String name) { int balance; out.println (name + " Versuch einer Einzahlung von " + amount); synchronized (this) { out.println (name + " Kontostand abrufen..."); balance = getBalance(); out.println (name + " Ermittelter Kontostand = " + balance); balance += amount; out.println (name + " Kontostand festlegen..."); setBalance (balance); } out.println (name + " Neuer Kontostand = " + balance); } Die Ausgabe dieses Programms entspricht weitgehend der des vorherigen. Die erste Meldung des zweiten Threads ist in den Meldungen des ersten Threads integriert, weil die erste println()-Methode sich nicht innerhalb des synchronisierten Blocks befindet. Das vollst$ndige Programmlisting lautet folgendermaßen: Listing 14.8 Deposit.java (Version 3)
import java.io.*; public class Deposit { // Vom Remote-Server erhaltenen Kontostand // simulieren static int balance = 1000; public static void main (String args[]) { PrintWriter out = new PrintWriter (System.out,
430
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
true); Account account = new Account (out); DepositThread first, second; first = new DepositThread (account, 1000, "#1"); second = new DepositThread (account, 1000, "\t\t\t\t#2"); // Transaktionen starten first.start(); second.start(); // Warten, bis beide Transaktionen beendet sind try { first.join(); second.join(); } catch (InterruptedException e) {} // Endkontostand ausgeben out.println ( "*** Endkontostand betr[gt " + balance); } } class Account { PrintWriter out; Account (PrintWriter out) { this.out = out; } void deposit (int amount, String name) { int balance; out.println (name + " Versuch einer Einzahlung von " + amount); synchronized (this) { out.println (name + " Kontostand abrufen..."); balance = getBalance(); out.println (name + " Ermittelter Kontostand = " + balance); balance += amount; out.println (name + " Kontostand festlegen..."); setBalance (balance); } out.println (name + " Neuer Kontostand = " + balance); } int getBalance() { // VerzIgerung beim Abrufen des Kontostands // simulieren try { Thread.sleep (5000); } catch (InterruptedException e) {} return Deposit.balance;
431
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
} void setBalance (int balance) { // VerzIgerung beim Setzen des neuen Kontostands // simulieren try { Thread.sleep (5000); } catch (InterruptedException e) {} Deposit.balance = balance; } } class DepositThread extends Thread { Account account; int depositAmount; String message; DepositThread (Account account, int amount, String message) { this.message = message; this.account = account; this.depositAmount = amount; } public void run() { account.deposit (depositAmount, message); } } Die Ausgabe des Beispielprogramms lautet folgendermaßen: C:\MasteringJava\Ch08>javac Deposit.java C:\MasteringJava\Ch08>java Deposit #1 Versuch einer Einzahlung von 1000 #2 Versuch einer Einzahlung von 1000 #1 Kontostand abrufen... #1 Ermittelter Kontostand: 1000 #1 Kontostand festlegen... #1 Neuer Kontostand ist 2000 #2 Kontostand abrufen... #2 Ermittelter Kontostand: 2000 #2 Kontostand festlegen... #2 Neuer Kontostand ist 3000 *** Endkontostand betr[gt 3000 An jedes Objekt, das synchronisierte Instanzmethoden enth$lt oder das von einem synchronisierten Block referenziert wird, wird ein eindeutiger Schl.ssel ausgegeben. Bei synchronisierten Klassenmethoden wird der Schl.ssel an die Klasse ausgegeben, weil die Methode – schon bevor eine Klasseninstanz existiert – aufgerufen werden kGnnte. Das bedeutet, dass jedes Objekt und jede Klasse .ber einen Monitor verf.gen kann, wenn zugeordnete, synchronisierte Methoden oder Anwei432
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
sungsblGcke vorhanden sind. Dar.ber hinaus unterscheidet sich der Schl.ssel zu einem Klassenmonitor von den Schl.sseln zu Monitoren der jeweiligen Klasseninstanz.
Unterschiede zwischen Synchronisierungstechniken Im n$chsten Beispiel werden die Unterschiede zwischen einer synchronisierten Methode und einem synchronisierten Block sowie die Unterschiede zwischen einer klassenbasierten und einer objektbasierten Synchronisierung gezeigt. Die Klasse SyncToken enth$lt drei Methoden, die jeweils unterschiedlich synchronisiert sind und die Methode ticker() zum Ausgeben von drei periodischen Signalen in zuf$lligen Intervallen aufrufen. SyncTestRunner ist eine Thread-Klasse, die – basierend auf der .bergebenen ID – verschiedene Methoden der Klasse SyncToken f.r die Ausf.hrung ausw$hlt. Die Methode main() der Klasse SyncTest erzeugt zehn Threads, die ticker() zu Vergleichszwecken mit unterschiedlichen Synchronisierungsschemata ausf.hrt. Das Programmlisting lautet folgendermaßen: import java.io.*;
Listing 14.9
public class SyncTest {
SyncTest.java
public static void main (String args[]) { SyncToken token = new SyncToken(); SyncTestRunner runners[] = new SyncTestRunner[10]; for (int i = 0; i < 10; i++) { runners[i] = new SyncTestRunner (token, i); runners[i].start(); } } } class SyncTestRunner extends Thread { SyncToken token; int id; SyncTestRunner (SyncToken token, int id) { this.token = token; this.id = id; } public void run() { switch (id % 3) { case 0: SyncToken.classTicker ("\t\t\tKlasse #" + id, token); break; case 1: token.methodTicker ("Methode #" + id); 433
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
break; case 2: token.blockTicker ("Block #" + id); break; } } } class SyncToken { PrintWriter out = new PrintWriter (System.out, true); // Methode ticker: drei Signale in zuf[lligen // Intervallen senden void ticker (String message) { for (int i = 0; i < 3; i++) { try { Thread.sleep ((int) (800 * Math.random())); } catch (InterruptedException e) { } out.println(message + ", Signal #" + i); } } // Klassenbasierte Synchronisierung static synchronized void classTicker (String message, SyncToken token) { token.ticker(message); } // Objektbasierte Synchronisierung: // synchronisierter Block void blockTicker (String message) { synchronized(this) { ticker (message); } } // Objektbasierte Synchronisierung: // synchronisierte Methode synchronized void methodTicker (String message) { ticker (message); } } Die Ausgabe des Programms lautet folgendermaßen: C:\MasteringJava\Ch08>javac SyncTest.java C:\MasteringJava\Ch08>java SyncTest Klasse #0, Signal #0 434
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Methode #1, Signal #0 Klasse Methode #1, Signal #1 Methode #1, Signal #2 Block #2, Signal #0 Klasse Klasse Block #2, Signal #1 Klasse Klasse Block #2, Signal #2 Methode #4, Signal #0 Methode #4, Signal #1 Methode #4, Signal #2 Klasse Block #5, Signal #0 Klasse Block #5, Signal #1 Block #5, Signal #2 Klasse Methode #7, Signal #0 Methode #7, Signal #1 Klasse Methode #7, Signal #2 Klasse Klasse Block #8, Signal #0 Block #8, Signal #1 Block #8, Signal #2
#0, Signal #1
#0, Signal #2 #3, Signal #0 #3, Signal #1 #3, Signal #2
#6, Signal #0 #6, Signal #1
#6, Signal #2
#9, Signal #0 #9, Signal #1 #9, Signal #2
MGglicherweise erhalten Sie auf Ihrem System eine geringf.gig andere Ausgabe. Dies ist davon abh$ngig, wie der Hersteller Ihrer Java-Implementierung Ressourcen verwaltet. Aus der Ausgabe kGnnen Sie entnehmen, dass objektbasierte, synchronisierte Methoden und synchronisierte BlGcke denselben Monitorschl.ssel verwenden, sofern sie f.r dasselbe Objekt konzipiert sind. Des Weiteren kGnnen Sie an den ineinander verzahnten Ausgaben erkennen, dass klassenbasierte Synchronisierung und objektbasierte Synchronisierung verschiedene Schl.ssel verwenden. Da die Synchronisierung eine aufwendige Operation darstellt, sollte deren Einsatz besonders f.r h$ufig ausgef.hrte Methoden oder AnweisungsblGcke auf ein Minimum beschr$nkt bleiben. Durch Synchronisierung lassen sich aber die wechselseitigen StGrungen von Threads reduzieren. Ein vern.nftiger Einsatz der Synchronisierung wird die Stabilit$t und die Robustheit eines Programms auf jeden Fall verbessern.
435
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
Kommunikation zwischen Threads Die Kommunikation zwischen Threads ermGglicht, dass Threads miteinander interagieren oder aufeinander warten. Threads kGnnen .ber gemeinsam genutzte Daten miteinander kommunizieren und .ber Thread-Steuerungsmethoden dazu veranlasst werden, aufeinander zu warten.
Von Threads gemeinsam genutzte Daten Alle Threads eines Programms nutzen denselben Speicherplatz. Wenn die Referenz auf ein Objekt f.r unterschiedliche Threads (wegen der Syntaxregeln f.r Geltungsbereichen) sichtbar ist oder explizit an andere Threads .bergeben wird, haben diese Threads gemeinsamen Zugriff auf die Datenelemente dieses Objekts. Wie im vorherigen Abschnitt erl$utert ist es manchmal erforderlich, mittels Synchronisierung einen exklusiven Zugriff auf Daten festzulegen, um Datenverf$lschungen zu verhindern.
Threads, die auf andere Threads warten Mit Hilfe von Thread-Steuerungsmethoden kGnnen Sie veranlassen, dass Threads aufeinander warten. Beispielsweise kann mit der Methode join() bewirkt werden, dass der aufrufende Thread auf die Beendigung des aufgerufenen Threads wartet. Ein Thread kann mit der Methode suspend() auch unterbrochen werden und warten, bis er von einem anderen Thread .ber die Methode resume()wieder aktiviert wird. Beide Threads kGnnen danach gleichzeitig laufen. Wenn ein Thread, der den Schl.ssel zu einem Monitor besitzt, unterbrochen wird oder darauf wartet, dass ein anderer Thread beendet wird, kGnnen Deadlocks auftreten. Wenn der Thread, auf den gewartet wird, in denselben Monitor gelangen muss, werden beide Threads ewig warten. Aus diesem Grund sollten Sie die Methoden suspend() und resume() nicht mehr verwenden. Die in der Klasse Object des java.lang-Packages definierten Methoden wait(), notify() und notifyAll() lGsen dieses Problem. Die Methode wait() bewirkt, dass die aufrufende Methode wartet, bis entweder eine Zeitbegrenzung abgelaufen ist oder ein anderer Thread die Methode notify() oder notifyAll() desselben Objekts aufruft. Die Syntax der Methode wait() lautet wie folgt: wait() oder wait (long timeoutPeriodInMilliseconds) Bei der ersten Syntax wird gewartet, bis der Thread benachrichtigt wird. Bei der zweiten Syntax wird entweder so lange gewartet, bis die angegebene Zeitbegrenzung verstrichen ist oder bis der Thread benachrichtigt wird.
436
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Wenn ein Thread die Methode wait() aufruft, wird der Schl.ssel, den er besitzt, f.r einen anderen, wartenden Thread freigegeben. Mit der Methode notify() kann nur ein wartender Thread aktiviert werden. Die Methode notifyAll() aktiviert alle wartenden Threads. Nach der Benachrichtigung versucht der Thread, erneut in den Monitor zu gelangen, indem er den Schl.ssel anfordert. Eventuell muss er aber warten, bis ein anderer Thread den Schl.ssel freigibt. Bitte beachten Sie, dass diese Methoden nur innerhalb eines Monitors oder eines synchronisierten Blocks aufgerufen werden kGnnen. Der Thread, der die Methoden notify() oder notifyAll() eines Objekts aufruft, muss den Schl.ssel f.r diesen Objektmonitor besitzen, sonst wird die Exception IllegalMonitorStateException, ein Typ der Exception RuntimeException, ausgelGst. Im n$chsten Beispiel werden die Methoden wait() und notify() zur LGsung des klassischen Erzeuger-Verbraucher-Problems eingesetzt. Bei diesem Problem generiert der Erzeuger Daten, die der Verbraucher verwendet. Wenn aber der Erzeuger Daten schneller erzeugt, als der Verbraucher diese verarbeiten kann, kGnnten die neu erzeugten Daten – noch bevor sie verwendet wurden – wieder .berschrieben werden. Wenn andererseits der Verbraucher die Daten schneller verwendet, als der Erzeuger sie generieren kann, kGnnte es sein, dass der Verbraucher bereits verarbeitete Daten erneut verwendet. Durch Synchronisierung allein kann dieses Problem nicht gelGst werden, da dadurch nur ein exklusiver Datenzugriff, aber nicht die Verf.gbarkeit von Daten gew$hrleistet wird. In der ersten Implementierung wird mit einem Monitor, einer Instanz der Klasse NoWaitMonitor, der Zugriff auf die Daten token gesteuert. Der Erzeuger und der Verbraucher setzen bzw. ermitteln den Wert von token in zuf$lligen Intervallen. Die maximale L$nge eines Intervalls wird durch das Argument speed gesteuert, das an die Konstruktoren .bergeben wird. Das Hauptprogramm akzeptiert bis zu zwei Befehlszeilenargumente zum Setzen der Erzeugungs- und Verbrauchsgeschwindigkeit, erzeugt eine Instanz des Monitors, erstellt einen Erzeuger und einen Verbraucher und .berwacht deren Ausf.hrung zehn Sekunden lang. Im Folgenden finden Sie das zugehGrige Programmlisting: import java.io.*;
Listing 14.10
public class NoWaitPandC { static int produceSpeed = 200; static int consumeSpeed = 200;
NoWaitPandC.java
public static void main (String args[]) { if (args.length > 0) produceSpeed = Integer.parseInt (args[0]); if (args.length > 1) consumeSpeed = Integer.parseInt (args[1]); NoWaitMonitor monitor = new NoWaitMonitor(); new NoWaitProducer (monitor, produceSpeed); new NoWaitConsumer (monitor, consumeSpeed); try { Thread.sleep (1000);
437
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
} catch (InterruptedException e) { } System.exit(0); } } class NoWaitMonitor { int token = -1; PrintWriter out = new PrintWriter (System.out, true); // Wert von token ermitteln synchronized int get () { out.println ("Erhalten: " + token); return token; } // Wert von token setzen synchronized void set (int value) { token = value; out.println ("Gesetzt: " + token); } } class NoWaitProducer implements Runnable { NoWaitMonitor monitor; int speed; NoWaitProducer (NoWaitMonitor monitor, int speed) { this.monitor = monitor; this.speed = speed; new Thread (this, "Producer").start(); } public void run() { int i = 0; while (true) { monitor.set (i++); try { Thread.sleep ((int) (Math.random() * speed)); } catch (InterruptedException e) { } } } } class NoWaitConsumer implements Runnable { NoWaitMonitor monitor; int speed; 438
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
NoWaitConsumer (NoWaitMonitor monitor, int speed) { this.monitor = monitor; this.speed = speed; new Thread (this, "Consumer").start(); } public void run() { while (true) { monitor.get(); try { Thread.sleep((int) (Math.random() * speed)); } catch (InterruptedException e) {} } } } Im Folgenden finden Sie ein Beispiel der Ausgabe des Programms, in dem der Erzeuger schneller arbeitet als der Verbraucher: C:\MasteringJava\Ch08>javac NoWaitPandC.java C:\MasteringJava\Ch08>java NoWaitPandC 100 400 Gesetzt: 0 Erhalten: 0 Gesetzt: 1 Gesetzt: 2 Gesetzt: 3 Gesetzt: 4 Erhalten: 4 Gesetzt: 5 Gesetzt: 6 Gesetzt: 7 Gesetzt: 8 Gesetzt: 9 Gesetzt: 10 Erhalten: 10 Gesetzt: 11 Gesetzt: 12 Wie Sie sehen, werden eine Menge Daten generiert (ausgegeben als Gesetzt), aber vor der Verarbeitung (ausgegeben als Erhalten) bereits wieder .berschrieben. Im Folgenden finden Sie ein Beispiel f.r die Ausgabe des Programms, in dem der Verbraucher schneller arbeitet als der Erzeuger: C:\MasteringJava\Ch08>java NoWaitPandC 400 100 Gesetzt: 0 Erhalten: 0 Erhalten: 0 Erhalten: 0 439
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
Erhalten: 0 Erhalten: 0 Erhalten: 0 Gesetzt: 1 Gesetzt: 2 Erhalten: 2 Gesetzt: 3 Erhalten: 3 Erhalten: 3 Erhalten: 3 Erhalten: 3 Erhalten: 3 Gesetzt: 4 Erhalten: 4 Erhalten: 4 Erhalten: 4 Erhalten: 4 Erhalten: 4 In diesem Beispiel werden einige Daten mehrmals verarbeitet. Bei der zweiten Implementierung des Beispielprogramms wird mit den Methoden wait() und notify() sichergestellt, dass alle Daten exakt einmal erzeugt und verarbeitet werden. Das Programm unterscheidet sich vom vorherigen nur in der Implementierung des Monitors. Mit der booleschen Variablen valueSet wird angegeben, ob die Daten bereit zur Verarbeitung sind oder bereits verarbeitet wurden. Die Methode get() testet zuerst, ob die Daten bereit zur Verarbeitung sind. Falls nicht, wartet der aufrufende Thread, bis ein anderer Thread die Daten liefert und den aktuellen Thread benachrichtigt. Anschließend wird die boolesche Variable gesetzt, um anzugeben, dass die Daten verarbeitet wurden. Daraufhin werden alle Threads, die darauf warten, neue Daten zu erzeugen, dar.ber benachrichtigt, dass ihre Datenproduktion beginnen kann. Falls kein produzierender Thread vorhanden ist, wird die Methode notify() ignoriert. Im Folgenden finden Sie die Methode get(): synchronized int get() { if (! valueSet) try { wait(); } catch (InterruptedException e) { } valueSet = false; out.println ("Erhalten: " + token); notify(); return token; } Analog zu der Methode get() testet die Methode set() zun$chst, ob die Daten bereits verarbeitet wurden. Falls nicht, wartet der aufrufende Thread, bis ein anderer Thread die Daten verarbeitet und den aktuellen Thread benachrichtigt. Anschließend wird die boolesche Variable gesetzt, um anzugeben, dass die Daten zur Ver440
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
arbeitung bereit sind. Daraufhin werden alle Threads, die darauf warten, Daten zu verarbeiten, dar.ber benachrichtigt, dass sie mit der Datenverarbeitung beginnen kGnnen. Falls kein wartender Thread vorhanden ist, wird die Methode notify() ignoriert. Im Folgenden finden Sie die Methode set(): synchronized void set (int value) { if (valueSet) try { wait(); } catch (InterruptedException e) { } valueSet = true; token = value; out.println ("Gesetzt: " + token); notify(); } Das vollst$ndige Listing des Programms ist im Folgenden abgedruckt: import java.io.*;
Listing 14.11
public class PandC { static int produceSpeed = 200; static int consumeSpeed = 200;
PandC.java
public static void main (String args[]) { if (args.length > 0) produceSpeed = Integer.parseInt (args[0]); if (args.length > 1) consumeSpeed = Integer.parseInt (args[1]); Monitor monitor = new Monitor(); new Producer(monitor, produceSpeed); new Consumer(monitor, consumeSpeed); try { Thread.sleep(1000); } catch (InterruptedException e) { } System.exit(0); } } class Monitor { PrintWriter out = new PrintWriter (System.out, true); int token; boolean valueSet = false; // Wert von token ermitteln synchronized int get () { if (! valueSet)
441
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
try { wait(); } catch (InterruptedException e) { } valueSet = false; out.println ("Erhalten: " + token); notify(); return token; } // Wert von token setzen synchronized void set (int value) { if (valueSet) try { wait(); } catch (InterruptedException e) { } valueSet = true; token = value; out.println ("Gesetzt: " + token); notify(); } } class Producer implements Runnable { Monitor monitor; int speed; Producer (Monitor monitor, int speed) { this.monitor = monitor; this.speed = speed; new Thread (this, "Producer").start(); } public void run() { int i = 0; while (true) { monitor.set (i++); try { Thread.sleep ((int) (Math.random() * speed)); } catch (InterruptedException e) { } } } } class Consumer implements Runnable { Monitor monitor; int speed; 442
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Consumer (Monitor monitor, int speed) { this.monitor = monitor; this.speed = speed; new Thread (this, "Consumer").start(); } public void run() { while (true) { monitor.get(); try { Thread.sleep ((int) (Math.random() * speed)); } catch (InterruptedException e) { } } } } Im Folgenden finden Sie eine Beispielausgabe des Programms: C:\MasteringJava\Ch08>javac PandC.java C:\MasteringJava\Ch08>java PandC 400 100 Gesetzt: 0 Erhalten: 0 Gesetzt: 1 Erhalten: 1 Gesetzt: 2 Erhalten: 2 Gesetzt: 3 Erhalten: 3 Gesetzt: 4 Erhalten: 4 In diesem Beispiel werden alle generierten Daten exakt einmal verarbeitet.
Thread-Priorit5ten und Zuteilung von Rechenzeit Durch PrioritGten wird gew$hrleistet, dass wichtige oder zeitkritische Threads h$ufig oder sofort ausgef.hrt werden. Durch die Zuteilung von Rechenzeit kGnnen Priorit$ten ber.cksichtigt und eine gewisse Ausgewogenheit erzielt werden. Wenn nur eine CPU vorhanden ist, m.ssen alle ausf.hrbaren Threads abwechselnd ausgef.hrt werden. Bei der Zuteilung von Rechenzeit wird die Ausf.hrungsreihenfolge mehrerer Threads festgesetzt.
443
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
Priorit5tswerte von Threads In Java wird jedem Thread ein Priorit$tswert zugewiesen. Wenn mehrere Threads um die CPU-Zeit konkurrieren, erh$lt der Thread mit dem hGchsten Priorit$tswert den Vorzug. Priorit$tswerte von Threads, die benutzererstellten Threads zugeordnet werden kGnnen, sind Ganzzahlen im Bereich zwischen Thread.MIN_PRIORITY und Thread.MAX_PRIORITY. Benutzeranwendungen arbeiten normalerweise mit einem Priorit$tswert von Thread.NORM_PRIORITY. In JDK 1.3 haben die Konstanten MIN_PRIORITY, MAX_PRIORITY und NORM_PRIORITY der Klasse Thread die Werte 1, 10 bzw. 5. Jeder Thread-Gruppe wird ein maximaler Priorit$tswert zugeordnet. Wenn Element-Threads und Thread-Gruppen erzeugt oder deren Priorit$tswerte ge$ndert werden sollen, stellt der zugeordnete maximale Priorit$tswert den oberen Grenzwert dar. Bei der Erstellung erbt ein Thread den Priorit$tswert des erzeugenden Threads, sofern dieser Priorit$tswert nicht den Grenzwert der .bergeordneten ThreadGruppe .bersteigt. Mit der Methode setPriority() der Klasse Thread kann der Priorit$tswert eines Threads gesetzt werden. Wenn sich dieser Wert außerhalb des zul$ssigen Bereichs befindet, wird eine IllegalArgumentException ausgelGst. Wenn der Wert grGßer als der maximale Priorit$tswert der .bergeordneten ThreadGruppe ist, wird der maximale Priorit$tswert verwendet. Mit der Methode setMaxPriority() der Klasse ThreadGroup kann der maximale Priorit$tswert einer Thread-Gruppe festgelegt werden. Aus Sicherheitsgr.nden (damit ein benutzererzeugter Thread die CPU nicht mit Beschlag belegt) kann ein Webbrowser verhindern, dass ein Applet seine Priorit$t $ndert.
Preemptive Rechenzeitzuteilung und Zeitscheibenverfahren Die Rechenzeitzuteilung in Java ist preemptiv: Wenn ein Thread mit einer hGheren Priorit$t als der aktuell laufende den Zustand ausfhrbar erh$lt, wird der Thread mit der hGheren Priorit$t sofort ausgef.hrt und der aktuell laufende Thread in die Warteschlange zur.ckgestellt, wo er wartet, bis er wieder an der Reihe ist. Ein Thread kann sein CPU-Ausf.hrungsprivileg durch Aufruf der Methode yield() explizit an andere wartende Threads mit derselben Priorit$t .bergeben. In einigen Implementierungen werden Threads im so genannten Zeitscheibenverfahren ausgef.hrt: Threads mit denselben Priorit$tswerten haben dieselben Chancen, in einer Art „Reihum-Methode“ ausgef.hrt zu werden. Sogar Threads mit niedrigeren Priorit$ten erhalten einen kleinen Anteil der Ausf.hrungszeit, ann$hernd proportional zu ihren Priorit$tswerten. Deshalb muss kein Thread langfristig auf CPU-Zeit verzichten. Andere Implementierungen setzen das Zeitscheibenverfahren nicht ein. Ein Thread gibt hier die Kontrolle nur in den folgenden F$llen auf: Seine Ausf.hrung ist beendet, der Thread wird von einem Thread mit hGherer Priorit$t verdr$ngt oder der Thread wird von einer I/O-Operation oder den Methodenaufrufen sleep(), wait() oder suspend() blockiert. Bei rechenintensiven Threads sollte gelegentlich die
444
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Methode yield() aufgerufen werden, damit auch andere Threads eine Ausf.hrungschance erhalten. Dadurch kann die gesamte interaktive Ansprechbarkeit von grafischen Benutzerschnittstellen verbessert werden. Bis zum JDK 1.1 arbeitet die virtuelle Java-Maschine f.r Windows 95/98 und NT mit dem Zeitscheibenverfahren. Die virtuelle Java-Maschine f.r Solaris 2 verwendet dieses Verfahren nicht. In Java 2 steht aber f.r Solaris eine Variation dieses Verfahrens zur Verf.gung. Dazu m.ssen jedoch einige Patches installiert werden und deshalb ist dieses Verfahren nicht standardm$ßig aktiviert. In der Readme-Datei von JDK finden Sie eine Liste der Patches, die f.r Solaris 2.5.1 und Solaris-x86 installiert werden m.ssen. Anschließend m.ssen Sie zur Aktivierung des Zeitscheibenverfahrens die Umgebungsvariable THREADS_FLAG auf native setzen. F.r das Standardverhalten setzen Sie diese Variable auf green (oder belassen sie ungesetzt). Die Laufzeitoptionen -native oder -green kGnnen auch mit den Befehlszeilen-Tools wie java und javac festgelegt werden.
Tipp
Rechenzeitzuteilung bei Threads mit unterschiedlichen Priorit5ten Das n$chste Beispiel zeigt die Auswirkung der Rechenzeitzuteilung bei Threads mit unterschiedlichen Priorit$ten. Das Hauptprogramm akzeptiert ein optionales Befehlszeilenargument, das angibt, ob die erzeugten Threads sich regelm$ßig abwechseln. Das Hauptprogramm beginnt mit vier Threads mit den folgenden Priorit$tswerten 1, 2, 4 und 4. Jeder Thread erhGht seinen Z$hler 600.001 mal und .bergibt optional bei jeder 3.000sten ErhGhung sein Ausf.hrungsprivileg an Threads mit derselben Priorit$t. Da der Haupt-Thread einen hGheren Priorit$tswert (5) als diese rechenintensiven Threads hat, kann der Haupt-Thread alle 0,3 Sekunden auf die CPU zugreifen, um die Z$hlerwerte der vier Berechnungs-Threads auszugeben. Das Programm lautet folgendermaßen: import java.io.*;
Listing 14.12
public class PriorityTest { static int NUM_THREADS = 4; static boolean yield = true; static int counter[] = new int[NUM_THREADS];
PriorityTest.java
public static void main (String args[]) { PrintWriter out = new PrintWriter (System.out, true); int numIntervals = 10; if (args.length > 0) yield = false; out.println ("yield() verwenden? " + (yield ? "JA" : "NEIN")); for (int i = 0; i < NUM_THREADS; i++) (new PrTestThread ((i > 1) ? 4 : (i + 1), i)).start(); 445
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
out.println(); // Die Z[hlerwerte wiederholt ausgeben int step = 0; while (true) { boolean allDone = true; try { Thread.sleep (100); } catch (InterruptedException e) { } out.print ("Schritt " + (step++) + ": Z`HLER:"); for (int j = 0; j < NUM_THREADS; j++) { out.print (" " + counter[j]); if (counter[j] < 2000000) allDone = false; } out.println(); if (allDone) break; } System.exit(0); } } class PrTestThread extends Thread { int id; PrTestThread (int priority, int id) { super ("PrTestThread#" + id); this.id = id; setPriority(priority); } public void run() { for (int i = 0; i javac PriorityTest.java C:\MasteringJava\Ch08>java PriorityTest yield() verwenden? JA Schritt 0: Z`HLER: 2999 0 530999 533999 446
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
Schritt Schritt Schritt Schritt Schritt Schritt Schritt
1: 2: 3: 4: 5: 6: 7:
Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER:
5999 2999 1073999 1085999 8999 5999 1607999 1637999 149999 149999 2000000 2000000 704999 701999 2000000 2000000 1249866 1259999 2000000 2000000 1796999 1817999 2000000 2000000 2000000 2000000 2000000 2000000
Dieser Ausgabe kGnnen Sie einige .berraschende Ergebnisse entnehmen. Die beiden Threads mit der hGchsten Priorit$t versuchen, die meiste CPU-Zeit zu beanspruchen. Da aber die Priorit$ten 1 und 2 so nahe beieinander liegen, wird die CPUZeit knapper zugeteilt. Im Folgenden ist eine Beispielausgabe desselben Programms abgedruckt, das aber auf einer virtuellen Java-Maschine ohne Zeitscheibenverfahren ausgef.hrt wurde. Auch hier wurde die Methode yield() verwendet. harpoon:/users/me/java/examples/ch8> javac PriorityTest.java harpoon:/users/me/java/examples/ch8> java PriorityTest yield() verwenden? JA Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt
0: Z`HLER: 0 0 103563 101999 1: Z`HLER: 0 0 206999 208476 2: Z`HLER: 0 0 314999 312189 3: Z`HLER: 0 0 419999 416889 4: Z`HLER: 0 0 527999 520335 5: Z`HLER: 0 67070 600000 600000 6: Z`HLER: 0 295645 600000 600000 7: Z`HLER: 0 521522 600000 600000 8: Z`HLER: 145375 600000 600000 600000 9: Z`HLER: 374097 600000 600000 600000 10: Z`HLER: 515023 600000 600000 600000 11: Z`HLER: 600000 600000 600000 600000
Hier ist deutlich ersichtlich, dass die Threads mit niedrigeren Priorit$tswerten erst eine Chance erhalten, ausgef.hrt zu werden, wenn die Ausf.hrung aller Threads mit einer hGheren Priorit$t beendet ist. Sie m.ssen mit der Einstellung des Maximalwertes f.r die Z$hler auf Ihrem Rechner experimentieren, um vern.nftige Ergebnisse zu erzielen. Verwenden Sie keinen so niedrigen Wert, dass die Ausf.hrung bereits nach zwei oder drei Schritten beendet ist. Ein Wert, der .ber 20 Schritte hinausgeht, ist aber etwas zu hoch.
Hinweis
Im Folgenden finden Sie die Ausgabe desselben Programms, das auf einem System mit Zeitscheibenverfahren aber ohne yield() ausgef.hrt wurde:
447
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
C:\MasteringJava\Ch08>java PriorityTest 0yield() verwenden? NEIN Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt
Hinweis
0: 1: 2: 3: 4: 5: 6: 7:
Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER: Z`HLER:
60965 61129 546422 441717 126821 123038 1052759 951456 188446 182858 1555466 1484050 252345 246123 2000000 2000000 764587 861142 2000000 2000000 1302086 1435581 2000000 2000000 1900295 1977578 2000000 2000000 2000000 2000000 2000000 2000000
Wenn das Programm unter einem anderen Betriebssystem ausgef.hrt wird, kGnnte eine unterschiedliche Ausgabe generiert werden. Dies ist abh$ngig von dem Algorithmus f.r die Rechenzeitzuteilung des Betriebssystems und/oder dem jeweiligen Port des JDK. Interessanterweise haben die Threads mit niedriger Priorit$t eine hGhere Chance, ausgef.hrt zu werden als in dem vorherigen Durchlauf mit yield(). Das liegt wahrscheinlich daran, dass yield() den urspr.nglichen Zuteilungsplan des Schedulers f.r Threads mit niedriger Priorit$t stGrt, indem der Scheduler zuerst nach Threads mit derselben Priorit$t suchen muss. Ohne yield() kGnnen alle Zuteilungspl$ne f.r Threads mit niedriger Priorit$t abgearbeitet werden. F.r das letzte Beispiel wurde das Programm ohne yield() und auf einem System ohne Zeitscheibenverfahren ausgef.hrt: harpoon:/users/me/java/examples/ch8> java PriorityTest 0 yield() verwenden? NEIN Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt Schritt
0: Z`HLER: 0 0 203552 0 1: Z`HLER: 0 0 203552 210978 2: Z`HLER: 0 0 413376 210978 3: Z`HLER: 0 0 413376 422790 4: Z`HLER: 0 0 600000 444539 5: Z`HLER: 0 57353 600000 600000 6: Z`HLER: 0 272848 600000 600000 7: Z`HLER: 0 488745 600000 600000 8: Z`HLER: 100596 600000 600000 600000 9: Z`HLER: 314749 600000 600000 600000 10: Z`HLER: 587513 600000 600000 600000 11: Z`HLER: 600000 600000 600000 600000
Die Threads mit einer niedrigeren Priorit$t haben keine Chance, ausgef.hrt zu werden, solange die Threads mit einer hGheren Priorit$t noch nicht beendet sind. Sogar Threads mit denselben Priorit$tswerten kGnnen erst ausgef.hrt werden, wenn der Haupt-Thread den laufenden Thread an das Ende der Warteschlange setzt. Wenn der Haupt-Thread die Programmkontrolle nach dem Ausgeben der Z$hlerwerte abgibt, erh$lt der Thread, der an erster Stelle in der Warteschlange steht, eine Aus448
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Multithreading fr Fortgeschrittene
f.hrungschance. Sie kGnnen dies im obigen Ausgabebeispiel .berpr.fen: Nur der Z$hler von einem der Threads mit der hGchsten Priorit$t wird zwischen zwei Ausgaben hochgesetzt.
Lokale Thread-Variablen Obwohl das Konzept der lokalen Thread-Variablen in die API in Java 2 eingef.hrt wurde, ist es eigentlich nicht neu f.r Java. Eine $hnliche Klasse war bereits im internen sun.server.util-Package von Java Web Server enthalten. Anscheinend war die Nachfrage groß genug, um das Konzept zu einem Standardbestandteil von Java zu machen: Es ist nun in den Klassen java.lang.ThreadLocal und java.lang.InheritableThreadLocal zu finden. Lokale Thread-Variablen ermGglichen, dass einzelne ThreadInstanzen eigenst$ndige Kopien von Variablen besitzen. Normalerweise werden Sie ThreadLocal-Variablen kaum verwenden, InheritableThreadLocal-Variablen schon eher. Lokale Thread-Variablen werden wichtig, wenn Sie statische Variablen zum Speichern von Bezeichnern (z.B. f.r den Zugriff auf Datenbanken oder zur Identifizierung einer Sitzung) benGtigen. In diesem Fall nutzen Sie die Variable nur innerhalb eines bestimmten laufenden Threads oder in einem Thread und in allen seinen Nachkommen. Eine ThreadLocal-Variable wird durch die als protected deklarierte Methode initialValue() initialisiert. Der Standardanfangswert einer ThreadLocal-Variable ist null. Zum Zuweisen eines anderen Anfangswertes m.ssen Sie eine Unterklasse von ThreadLocal bilden und die Methode .berschreiben. Der Wert kann auch sp$ter mit der Methode set() ge$ndert werden.
Hinweis
Das folgende Beispiel zeigt die Unterschiede zwischen Klassenvariablen und ThreadLocal-Variablen. In einer Multithread-Umgebung erzeugt das Programm mehrere Instanzen einer Klasse und z$hlt die erzeugte Anzahl in der Klassenvariablen counter. Jedem Thread steht auch die statische Variable threadLocal zur Verf.gung. Der Wert von threadLocal wird als Angabe f.r die inaktive Zeit verwendet. Die innere Klasse MyThreadLocal bietet dem Thread in der Methode initialValue() eine inaktive Zeit von bis zu 1.000 Millisekunden. Beachten Sie, dass beide Variablen als static deklariert sind. Sie erwarten wahrscheinlich, dass eine Kopie beider Variablen f.r alle Instanzen der Klasse vorhanden ist. import java.io.*;
Listing 14.13
public class LocalThreadVars implements Runnable {
LocalThreadVars.java
static private class MyThreadLocal extends ThreadLocal { protected Object initialValue() { return new Double (Math.random() * 1000.0); } } static ThreadLocal threadLocal =
449
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Threads und Multithreading
new MyThreadLocal(); static int counter = 0; private LocalThreadVars() { counter++; } public void run() { LocalThreadVars myLTV = new LocalThreadVars(); displayValues(); try { Thread.currentThread().sleep ( ((Double)threadLocal.get()).longValue()); myLTV.displayValues(); } catch (InterruptedException e) { e.printStackTrace(); } } private void displayValues() { System.out.println (threadLocal.get() + "\t" + counter + "\t" + Thread.currentThread().getName()); } public static void main (String args[]) { LocalThreadVars ltv = new LocalThreadVars(); ltv.displayValues(); for (int i=0;ijavac LocalThreadVars.java C:\MasteringJava\Ch08>java LocalThreadVars 353.6782033483381 1 main 607.6189861951625 2 Thread-0 204.82242103443437 3 Thread-1 216.68547449023978 4 Thread-2 960.1210961092618 5 Thread-3 221.4544981562063 6 Thread-4 204.82242103443437 6 Thread-1 450
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Ausblick
216.68547449023978 221.4544981562063 607.6189861951625 960.1210961092618
6 6 6 6
Thread-2 Thread-4 Thread-0 Thread-3
Beachten Sie, dass die Variable counter von verschiedenen Threads gemeinsam genutzt wird, die Variable threadLocal aber nicht. Wenn die statische Variable ThreadLocal von verschiedenen Threads gemeinsam genutzt w.rde, w.rde derselbe Wert f.r alle Werte statt nur f.r mehrere Klassen innerhalb desselben Threads wiederholt werden. Sie werden die Klasse ThreadLocal hGher sch$tzen, wenn Sie sich mit der Programmierung von Netzwerken befassen. F.r jetzt gen.gt es, wenn Sie von ihrer Existenz wissen und sich bei Bedarf an sie erinnern.
Daemon-Threads Daemon-Threads sind Dienst-Threads. Sie sind nur vorhanden, um f.r andere Threads Dienste bereitzustellen. Normalerweise werden sie in Endlosschleifen ausgef.hrt und warten darauf, dass Clients ihre Dienste anfordern. Wenn es sich bei allen verbleibenden aktiven Threads um Daemon-Threads handelt, wird die virtuelle Java-Maschine beendet. Ein Timer-Thread, der in regelm$ßigen Intervallen aktiv wird, stellt ein gutes Beispiel f.r Daemon-Threads dar. Dieser Timer-Thread kann andere Threads regelm$ßig .ber Zeit.berschreitungen benachrichtigen. Wenn keine anderen Threads ausgef.hrt werden, gibt es keinen Bedarf f.r den Timer-Thread. Rufen Sie zum Erzeugen eines Daemon-Threads die Methode setDaemon() sofort nach der Erzeugung des Threads und vor dem Beginn der Thread-Ausf.hrung auf. Der Konstruktor des Threads ist f.r diesen Methodenaufruf der geeignete Ort. Standardm$ßig handelt es sich bei allen von einem Daemon-Thread erzeugten Threads ebenfalls um Daemon-Threads. Die Syntax der Methode setDaemon() lautet: setDaemon (boolean isDaemon) Wenn isDaemontrue ist, wird der Thread als Daemon-Thread, andernfalls als NichtDaemon-Thread gekennzeichnet.
Ausblick Kapitel 15: Java Database Connectivity (JDBC) behandelt die Java Database Connectivity (JDBC) und durchleuchtet Java als eine Front-End-Datenbankanwendung.
451
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java Database Connectivity (JDBC)
Java als ein Datenbank-Front-End
454
Client/Server-Datenbanken
455
Das zweischichtige Datenbankmodell
456
Das dreischichtige Datenbankmodell
457
JDBC-API
458
Ein Beispiel fr eine JDBC-Datenbank
481
JDBC-Treiber
488
Die JDBC-ODBC-Brcke
490
Aktuelle JDBC-Treiber
491
Alternative Connectivity-Strategien
491
15 Ausblick
493
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java Database Connectivity (JDBC)
Aus „Mastering Java 2“ von John Zukowski, ISBN 0-7821-2180-2, 1280 Seiten, $49,99
In unserem gegenw$rtigen Informationszeitalter stellt eine Datenbank das Tool zum Sammeln und Bearbeiten von Daten dar. Datenbanken bilden in vielen Firmen die Grundlage der Infrastruktur. Ein Datenbanksystem eignet sich hervorragend f.r die Datenspeicherung und -abfrage. Um die gespeicherten Daten aber anzuzeigen und damit zu arbeiten, ist eine so genannte Front-End-Anwendung erforderlich. Front-Ends stellen f.r Datenbanken benutzerfreundliche Oberfl$chen zur Verf.gung. Die meisten Firmen arbeiten aber nicht mit einheitlichen Computersystemen. Die Grafik- und Marketingabteilungen verwenden wahrscheinlich Macintosh-Systeme, technische Abteilungen UNIX-Workstations und Verkaufsabteilungen eine Version von Microsoft Windows (Windows 95/98/2000, Windows NT 4, Windows NT 3.51 oder Windows 3.1) auf PCs. Entwickler m.ssen all diesen unterschiedlichen Systemen Rechnung tragen, wenn sie Daten einer Firmendatenbank zug$nglich machen wollen. In diesem Kapitel wird Java als die LGsung f.r die Problematik Datenbank-Front-End beleuchtet: Java stellt mit der Database Connectivity API eine einzelne und konsistente Programmierschnittstelle zur Verf.gung.
Java als ein Datenbank-Front-End Java bietet Entwicklern, die Front-End-Anwendungen f.r einen Datenbankserver erstellen, mehrere Vorteile. Java-Programme kGnnen ohne erneute Kompilierung an alle Computerarchitekturen und Betriebssysteme verteilt werden, die mit der virtuellen Maschine von Java ausgestattet sind. F.r große Unternehmen bedeutet eine einheitliche Entwicklungsplattform eine enorme Kostenreduzierung: Programmierer m.ssen nicht mehr separate Anwendungen f.r alle unterschiedlichen im Unternehmen eingesetzten Plattformen schreiben. Java ist auch f.r Fremdhersteller interessant: Ein einziges Java-Programm kann sowohl f.r die Anforderungen von kleinen als auch von Großkunden geeignet sein. Die Bereitstellung und Wartung der unterschiedlichen Hard- und Softwaresysteme (Clients) bedingen weitere Kosten f.r Unternehmen. Systeme wie Windows-PCs sowie Desktop-zentrierte Macintosh- und UNIX-Clients (Fat Clients) kGnnen sich in einem Kostenrahmen von $10.000 bis zu $15.000 pro Rechnerinstallation bewegen. Die Java-Technologie ermGglicht Unternehmen, kleinere Systeme einzusetzen. Diese Systeme basieren auf einem Java-Chipset und kGnnen s$mtliche Java-Programmme auf einem integrierten Java-Betriebssystem ausf.hren. Java-basierte Clients (Thin Clients), die mit einem Minimum an Hardwareressourcen betrieben werden, aber dennoch die komplette Java-Umgebung ausf.hren, kosten ungef$hr $750 pro Rechnerinstallation. Laut zahlreicher Untersuchungen kGnnte die Kostenersparnis f.r ein Unternehmen, das 10.000 Fat-Client-Systeme in ThinClient-Systeme umwandelt, bei bis zu $100 Millionen pro Jahr liegen. Da PentiumSysteme auch schon f.r weniger als $1.000 erh$ltlich sind, erkl$ren sich die hGheren Kosten f.r diese Systeme haupts$chlich durch die Konfigurations- und Wartungsaufwendungen (nicht zuletzt f.r die lokalen Speicher). 454
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Client/Server-Datenbanken
Daraus folgt, dass der Anreiz, Java-basierte UnternehmenslGsungen zu entwickeln, sehr groß ist. Unternehmen sind $ußerst daran interessiert, ihre Anwendungen von architektur- und betriebssystemspezifischen Modellen auf netzwerkzentrierte Modelle umzustellen. Java stellt eine langfristige Strategie zum Einsparen von Ressourcenkosten dar. F.r Entwickler bedeutet dies eine enorme Marktchance. Es gibt nur sehr wenige, mittlere bis große Organisationen, die nicht zumindest in einigen Unternehmensbereichen Datenbanken einsetzen. Die meisten Unternehmen verwenden Datenbanken f.r s$mtliche gesch$ftliche Aktivit$ten, von der Personal- bis hin zur Verkaufsabteilung. Dieses Kapitel behandelt die Java Database Connectivity (JDBC) einschließlich der Frage, wie Java-Anwendungen und -Applets mit Hilfe der aktuellen JDBC-API mit Datenbankservern verbunden werden kGnnen.
Client/Server-Datenbanken Die Evolution der relationalen Datenspeicherung begann 1970 mit der Arbeit von Dr. E. F. Codd, der zwGlf Regeln zur Identifizierung von Beziehungen zwischen Datenelementen vorschlug. Codds Regeln bildeten die Grundlage bei der Entwicklung von Datenverarbeitungssystemen. Die heutigen Relational Database Management Systems (RDBMS) sind das Ergebnis von Codds Vision. Daten in RDBMS werden als Zeilen von verschiedenartigen Informationen in Tabellen gespeichert. Mit einer strukturierten Sprache (SQL) werden die Daten abgefragt (ermittelt), gespeichert und ge$ndert. SQL (Structured Query Language) ist ein ANSIStandard. Alle großen kommerziellen RDBMS-Anbieter integrieren Mechanismen zum Ausf.hren von SQL-Anweisungen in ihre Systeme. Die ersten RDBMS-Anwendungen benutzten ein integriertes Model von Benutzerschnittstellencode, Anwendungscode und Datenbankbibliotheken. Dieses einschichtige bin$re Modell konnte nur auf lokalen Rechnern, typischerweise Mainframes, ausgef.hrt werden. Die Anwendungen waren einfach, aber leider nicht effizient und arbeiteten nicht in LANs. Das Modell ließ sich nicht normieren und der Anwendungs- und Benutzerschnittstellencode war eng an die Datenbankbibliotheken gekoppelt. Die folgende Abbildung illustriert das monolithische, einschichtige Datenbankmodell. Dar.ber hinaus konnten in dem monolithischen Modell mehrere Instanzen einer Anwendung nicht untereinander kommunizieren. Verschiedene Instanzen einer Anwendung konkurrierten daher oft miteinander. Der wechselweise Einsatz ist f.r RDBMS und DBMS (Database Management System) charakteristisch, weil die meisten großen kommerziellen Datenbanken relational sind und irgendeine Form von SQL unterst.tzen, damit Benutzer Beziehungen zwischen Datentabellen abfragen kGnnen.
Hinweis
455
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java Database Connectivity (JDBC)
Abb. 15.1 Das monolithische, einschichtige Datenbankmodell
Das zweischichtige Datenbankmodell Zweischichtige Modelle tauchten mit der Einf.hrung der Servertechnologie auf. Die Entwicklung von Kommunikationsprotokollen und der umfangreiche Einsatz von LANs (Local Area Network) und WANs (Wide Area Network) ermGglichten es Datenbankentwicklern, ein Anwendungs-Front-End zu erstellen, das .ber eine Verbindung (Socket) zum Back-End-Server auf Daten zugreift. Die folgende Abbildung illustriert ein zweischichtiges Datenbankmodell, in dem die Clientsoftware mit der Datenbank .ber ein Socket verbunden ist.
Abb. 15.2 Das zweischichtige Datenbankmodell
Clientprogramme (die die Benutzerschnittstelle bereitstellen) senden SQL-Anforderungen an den Datenbankserver. Der Server liefert die entsprechenden Ergebnisse zur.ck. Der Client ist dabei f.r die Formatierung und die Anzeige der Daten verantwortlich. Clients verwenden auch in diesem Modell eine vom Hersteller mitgelieferte Bibliothek mit Funktionen, die die Kommunikation zwischen Client und Server verwalten. Die meisten Funktionsbibliotheken sind in C oder Perl geschrieben. Kommerzielle Datenbankanbieter erkannten das Potenzial, das im Hinzuf.gen von Intelligenz zu Datenbankservern lag. Sie entwickelten propriet$re Techniken, mit denen Datenbankdesigner Makroprogramme zur einfachen Datenbearbeitung erstellen konnten. Diese Makros, so genannte Stored Procedures, kGnnen im Bereich der Versionskontrolle und der Programmwartung Probleme verursachen. Da Stored Procedures in der Datenbank vorhandene, ausf.hrbare Programme sind, kGnnten sie versuchen, auf Spalten einer Datenbanktabelle zuzugreifen, nachdem die 456
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Das dreischichtige Datenbankmodell
Tabelle ver$ndert wurde. Wenn z.B. eine Spalte mit dem Namen id in cust_id ge$ndert wird, wird eine Stored Procedure, die f.r den urspr.nglichen Spaltennamen vorgesehen war, nutzlos. Wenn die von einer Abfrage zur.ckgegebenen Daten nicht erwartet werden, kGnnen Trigger diese Probleme sogar noch verst$rken, was wiederum das Ergebnis eines Versuchs sein kGnnte, auf eine ge$nderte Tabellenspalte zuzugreifen. Trigger sind Stored Procedures, die automatisch ausgef.hrt werden, wenn in einer Tabelle (oder mehreren Tabellen) eine Aktion (wie z.B. das Einf.gen von Daten) ausgef.hrt wird. Trotz des Erfolgs von Client/Server-Architekturen weisen zweischichtige Datenbankmodelle die folgenden Schwachstellen auf: Anbieterspezifische Bibliothek: Beim Wechseln von einem Datenbankanbieter zu einem anderen muss ein betr$chtlicher Teil des Codes der Clientanwendung neu geschrieben werden. Versionskontrolle: Wenn ein Anbieter die clientseitigen Bibliotheken aktualisiert, m.ssen auch die Anwendungen, die auf die Datenbank zugreifen, neu kompiliert und verteilt werden. Anbieterbibliotheken arbeiten mit Low-Level-Datenmanipulation. Die Hauptbibliothek arbeitet normalerweise nur mit Abfragen und Aktualisierungen von einzelnen Datenzeilen oder -spalten. Auf der Serverseite kann dies durch eine Stored Procedure erweitert werden, was aber die Komplexit$t des Systems erhGht. Die gesamte Intelligenz, die f.r die Verwendung und Bearbeitung der Daten erforderlich ist, ist in der Clientanwendung implementiert, was auf der Clientseite zu langen Laufzeiten und zu Kostensteigerungen f.hrt.
Das dreischichtige Datenbankmodell Momentan besteht großes Interesse an mehrschichtigen Datenbankmodellen. Bei diesen Architekturen kommuniziert der Client mit einem Zwischenserver, der eine Abstraktionsschicht des RDBMS bereitstellt. Es brauchen nicht nur drei Schichten zu sein, aber konzeptionell stellen drei Schichten den n$chsten Schritt dar. Die folgende Abbildung illustriert ein dreischichtiges Datenbankmodell.
Abb. 15.3 Ein dreischichtiges Datenbankmodell
457
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java Database Connectivity (JDBC)
In der mittleren Schicht erfolgt die Bearbeitung von mehreren Clientanforderungen und die Verwaltung der Verbindung zu einem oder mehreren Datenbankservern. Das dreischichtige Modell weist wegen der mittleren Schicht die folgenden Vorteile gegen.ber dem zweischichtigen Modell auf: Es ist Multithread-f$hig und kann daher mehrere Clientverbindungen gleichzeitig verwalten. Es kann Verbindungen zu Clients .ber eine Vielzahl von herstellerneutralen Protokollen (von HTTP bis zu TCP/IP) aufnehmen, dann die Anforderungen an den passenden herstellerspezifischen Datenbankserver .bergeben und die Antworten schließlich an die entsprechenden Clients zur.ckliefern. Es kann mit einer Reihe von Business Rules programmiert werden, die die Datenbearbeitung verwalten. In die Business Rules kGnnten Regeln f.r Zugriffsbeschr$nkungen f.r bestimmte Datenbereiche bis hin zur wobei <subprotocol> den Treibertyp definiert und <subname> einen kodierten Netzwerknamen enth$lt. Zum Beispiel: jdbc:oracle:products Der Datenbanktreiber ist hier ein Oracle-Treiber und der Subname ist eine lokale Datenbank mit dem Namen Products. Der Treiber ist so konzipiert, dass er den Subnamen bei der Herstellung der Verbindung zu einer Oracle-Datenbank entschl.sseln kann. Anstelle eines bestimmten Datenbanktreibernamens kann als Subprotokoll auch ein Network Naming Service angegeben werden. In diesem Fall w.rde das Subprotokoll den Naming Service definieren: jdbc:localnaming:human-resources Im obigen Beispiel definiert das Subprotokoll einen lokalen Dienst, der den Subnamen human-resources in eine Adresse eines Datenbankservers umwandelt. Wenn der Benutzer von der Eingabe der aktuellen Position und des Namens der Datenbank sowie des Datenbankbenutzernamens und des Datenbankpassworts befreit werden soll, bietet sich dieses Vorgehen an. Die obige URL legt einen Treiber mit dem Namen localnaming fest. Dabei kGnnte es sich um ein Java-Programm handeln, das eine einfache, lineare Suche ausf.hrt und human-resources z.B. in hrdatabase1.eng:888/personnel .bersetzt sowie den Benutzernamen user und das Passwort matilda kennt. Die Einzelheiten der Verbindung bleiben dem Benutzer verborgen. Normalerweise kennt der Anwendungsentwickler den Speicherort der Datenbank und es kGnnte sein, dass er keine Umadressierung verwenden will. In diesem Fall kann die URL mit dem Speicherort des Hosts und speziellen Port- und Datenbankinformationen erg$nzt werden. jdbc:msql://dbserver.eng:1112/bugreports
462
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JDBC-API
Im obigen Beispiel wird mit einem Datenbanktreiber des Typs msql ein Server mit dem Namen dbserver in der Dom$ne eng gesucht und versucht, .ber Port 1112 eine Verbindung mit einem Datenbankserver herzustellen, der die Datenbank bugreports enth$lt. Dabei wird der Standardbenutzername und das Standardpasswort verwendet. Subprotokollnamen kGnnen sich .berschneiden. Um dies zu vermeiden, unterh$lt Sun informell ein Kartei mit reservierten Namen. N$here Informationen .ber das Registrieren von JDBC-Subprotokollnamen finden Sie in der JDBC-Spezifikation.
Hinweis
Die Anbieter der Treiber implementieren die Schnittstelle Driver, indem f.r jede der folgenden Schnittstellenmethoden Methoden erstellt werden: Signatur: public interface java.sql.Driver public abstract Connection connect(String url, Properties info) throws SQLException: Die Treiberimplementierung dieser Methode sollte den im URL-String .bergebenen Subprotokollnamen auf <password>"); System.exit (1); } // Eine Instanz der Klasse erzeugen Example ex = new Example (); // Verbindung initialisieren ex.initdb (arg[0], arg[1], arg[2]); // Verbindung testen - einen Kundendatensatz // schreiben und wieder einlesen ex.testdb (); } // Methode zum Initialisieren der Datenbank// verbindung // Die Connection-Objektreferenz wird global // gehalten public void initdb (String url, String user, String passwd) { // Datenbank Iffnen und Verbindung herstellen
486
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Ein Beispiel fr eine JDBC-Datenbank
try { // Beachten Sie bitte, dass in diesem Beispiel // vorausgesetzt wird, dass die Java// Eigenschaft "jdbc.drivers" den passenden // Treiber (oder die Treiber) f:r die im // Aufruf von getConnection angegebene URL // l[dt. Es kInnte auch explizit eine Instanz // des Treibers erzeugt werden, z.B. // new sybase.sql.driver (); // Eine Verbindung herstellen sybaseConn = DriverManager.getConnection (url, user, passwd); } catch (SQLException e) { System.err.println ( "Database connection failed:"); System.err.println (e.getMessage()); System.exit (2); } } // Eine einfache Methode zum Testen der Methoden // der Klasse Customer public void testdb () { String custID = null; // Die Instanz der Customer-Klasse erzeugen Customer cust = new Customer (sybaseConn); try { // Neuen Kundendatensatz einf:gen custID = cust.insertNewCustomer ( "Jones", "Bill", "555-1234", "5 Main Street", "01234"); } catch (SQLException e) { System.err.println ("Insert failed:"); System.err.println (e.getMessage()); System.exit (3); } try { // Datensatz aus der Datenbank einlesen CustomerInfo info = cust.getCustomer (custID); } catch (SQLException e) { System.err.println ("Read failed:"); System.err.println (e.getMessage()); System.exit (4); } } }
487
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Java Database Connectivity (JDBC)
Kompilieren Sie das Programm Example.java (denken Sie daran, die Pfadangabe durch den Verzeichnispfad zu Ihrer Datenbank zu ersetzen): C:\MasteringJava\Ch21>javac Example.java C:\MasteringJava\Ch21>java Example Example use: java Example <username> <password> C:\MasteringJava\Ch21>java Example jdbc:sybase://dbserver:8080/billing john MyPassword Dieses Beispiel zeigt, wie mit CallableStatement-Objekten Stored Procedures zur setSize(new Dimension(300,75)); setVisible(true); // Warten Sie einen Moment, dann modifizieren Sie // eine der Eigenschaften des Buttons // System.out.println("No need to push that // button I'll do that."); MiscKit.delay(6*1000); aButtonBean.setLabel("anyone can know" + (" about it !"); MiscKit.delay(12*1000); // close window, quit setVisible(false); System.exit(0); } //--------------------------------------------------// propertyChange() ist die Methode, die von der // Schnittstelle des PropertyChangeListeners // implementiert werden muss. Dies ist die Stelle, // wo auf die Eigenschaft OurButton geachtet wird. //--------------------------------------------------public void propertyChange( PropertyChangeEvent pcEvent) { String changedProperty; Object oldPropertyValue, newPropertyValue; changedProperty = pcEvent.getPropertyName(); oldPropertyValue = pcEvent.getOldValue(); newPropertyValue = pcEvent.getNewValue(); System.out.println("OurButton property '" + changedProperty +"'"); System.out.println(".. changed from '" + oldPropertyValue +"'"); System.out.println(".. to '" + newPropertyValue +"'"); } } // Ende der Klasse PropertyChangeDemo Wenn Sie dieses Programm von der Konsole starten, sollten Sie die folgende Textausgabe sehen: C:\MasteringBeans\ch04>javac PropertyChangeDemo.java C:\ MasteringBeans\ch04>java PropertyChangeDemo No need to push that button.. I'll do that. 587
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
OurButton property 'label' .. changed from 'When my properties change...' .. to 'anyone can know about it !' Die folgende Abbildung zeigt das Fenster mit dem Button, den PropertyChangeDemo konstruiert.
Abb. 18.1 OurButton BDK-Demonstration-Bean bereit zum Absenden einer Eigenschafts7nderung
Um den PropertyChangeEvent wahrnehmen zu kGnnen, der durch OurButton erzeugt wird, muss die Klasse PropertyChangeDemo die Schnittstelle PropertyChangeInterface implementieren. Bevor JavaBeans Events absenden kGnnen, m.ssen diese per Beans.instantiate()-Instanzen gebildet werden. Wie bereits in Kapitel 17: JavaBeans: Ein Jberblick angemerkt wurde, sollten Sie niemals eine Instanz von JavaBeans mit einem einfachen new bilden. Die Methode Beans.instantiate() kann zwei gepr.fte Exceptions auswerfen, so dass diese Methode in ein try-catch-Statement eingebettet werden muss, das die entsprechende Fehlerbehandlung enth$lt. Der erste Parameter der Methode instantiate() bezeichnet den ClassLoader, der f.r die Bildung dieser Instanz verwendet werden soll. Solange Sie keine triftigen Gr.nde daf.r haben, einen anderen Klassenlader zu verwenden, als den vom System vorgegebenen, kGnnen Sie dieses Argument auf Null setzen. Das zweite Argument spezifiziert die JavaBean-Klasse selbst als voll qualifizierten Klassennamen. Gegenw$rtig nimmt instantiate() zuerst an, dass die JavaBean als serialisierte Instanz gespeichert wurde, mit der Dateiendung .ser. In diesem Fall ist OurButton als .class-Datei gespeichert. (Als farbige Alternative ist OrangeButton als .ser-Datei gespeichert, so dass Sie die Instanzbildung von serialisierten JavaBeans sehr leicht testen kGnnen, indem Sie den String, der an instantiate() .bergeben wird, in sunw.demo.buttonsOrangeButton $ndern.)
588
Beachten Sie, dass es keine MGglichkeit gibt, Instanzen von JavaBeans in bestimmten Zust$nden zu bilden (es sei denn, Sie haben JavaBeans in der Vergangenheit komplett in einem bestimmten Zustand serialisiert), wie Sie es kGnnten, wenn Sie new verwenden d.rften, um neue, nicht vordefinierte Konstruktoren zu erschaffen (Konstruktoren, die Parameter .bernehmen). Dies ist der Grund, warum Sie setlabel() auf die JavaBean anwenden m.ssen, um das Label des Buttons zu setzen, nachdem es erzeugt wurde. Vergleichen Sie dies mit einem normalen java.awt.Button, dessen Label im Augenblick der Instanzbildung spezifiziert werden kann (aber nicht, falls dies innerhalb einer Bean-Umgebung verwendet wird und als eine ordentliche JavaBean behandelt wird).
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Sobald der Button erzeugt und initialisiert wurde, registrieren Sie das Objekt PropertyChangeDemo bei der JavaBean als einen PropertyChangeListener. Wenn Sie nun eine Eigenschaft von OurButton $ndern (wie zum Beispiel durch ein zweites setLabel()), wird die JavaBean einen PropertyChangeEvent absenden, der von Ihrem Programm mit der Methode propertyChange() abgefangen wird – der einzigen Methode, die implementiert werden musste, um der Schnittstelle PropertyChangeListener zu entsprechen. Hier verwendet es getProperty(), getOldValue() und getNewValue(), um einige Informationen .ber den Event auszugeben. Beachten Sie, dass in diesem einfachen Beispiel PropertyChangeDemo selbst die Eigenschaft ver$ndert, f.r die es sp$ter den Event empf$ngt. In echten Programmen wird es nur selten solche reflektiven Beziehungen zwischen der Entit$t, die die Eigenschaft $ndert, und der, die den Event empf$ngt und daraufhin handelt, geben.
Gebundene Eigenschaften: Die Perspektive des die JavaBeans Implementierenden Nachdem Sie erfahren haben, wie Sie mit gebundenen Eigenschaften umgehen, die von existierenden JavaBeans abgeschickt werden, werden Sie nun sehen, wie gebundene Eigenschaften zu Ihren eigenen JavaBeans hinzugef.gt werden. Um eine einfache Eigenschaft in eine gebundene umzuwandeln, m.ssen Sie eine Reihe von Methoden zu den jeweiligen JavaBeans hinzuf.gen. Zun$chst benGtigen Sie die Methoden des Listener Managements, die Ihre JavaBean-Clients erwarten, wenn die JavaBeans irgendwelche gebundenen Eigenschaften enthalten: public void addPropertyChangeListener( PropertyChangeListener x); public void removePropertyChangeListener( PropertyChangeListener x);
Die Asymmetrie zwischen Event Source und Event Listener Beachten Sie die zwischen Event Source und Event Listener existierende Asymmetrie: Event Listeners mssen (von vornherein) eine Java-Schnittstelle implementieren, Event Sources nicht. Schnittstellen auf der Seite der Event Source sind nicht fr das Funktionieren der Listener-Metapher notwendig, obwohl sie aus einigen Grnden sehr ntzlich sein k"nnen: Event Listener k"nnen Sources ber ihren Schnittstellentyp EventSource auf generischem Wege behandeln statt des eher rigiden Wegs eines konkreten Klassentyps. Wie es immer der Fall bei der Verwendung solcher Schnittstellen ist, wrde Ihnen dies eine flexiblere Programmierung erm"glichen. 589
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Im Augenblick fhrt ein einziger Schreibfehler whrend des Programmierens der Signaturen der Listener-Managementmethoden zu einem Bug. Wenn Schnittstellen mit einbezogen werden, wrde der Compiler sofort den Fehler dadurch kennzeichnen, dass er ausgibt, die Schnittstelle der Event Source sei nicht implementiert. Obwohl der Standard der JavaBeans keine Schnittstellen auf der Seite der Source verwendet, gibt es keinen Grund, warum Sie sich nicht auf diese verlassen sollten, um sich das Leben zu erleichtern.
Als N$chstes m.ssen Sie die Setter-Methode(n) der Eigenschaft(en), die Sie in einen gebundenen Typ wandeln, anpassen, damit alle registrierten Listener von einer Snderung der Eigenschaftswerte erfahren. Beachten Sie, das Eigenschafts$nderungen so genannte multicast Events sind, wodurch Sie die MGglichkeit einer langen Liste von registrierenden Listenern managen m.ssen, die benachrichtigt werden m.ssen. Gl.cklicherweise sind gebundene Eigenschaften sehr h$ufig und es gibt eine unterst.tzende Klasse (analog zu AWTEventMulticaster zum Absenden von AWTEvents), die Ihnen bei der Verwaltung von all diesem hilft, weshalb Sie sich nicht um verkettete Listen und so weiter sorgen m.ssen. Die Klasse PropertyChangeSupport kommt Ihnen zu Hilfe: public class PropertyChangeSupport extends Object implements Serializable { public PropertyChangeSupport(Object sourceBean); // constructor // Bilde Instanzen der Methoden: public synchronized void addPropertyChangeListener (PropertyChangeListener listener); public synchronized void removePropertyChangeListener(PropertyChangeListener listener); public void firePropertyChange(String propertyName, Object oldValue, Object newValue); } Wie Sie sehen kGnnen implementiert PropertyChangeSupport bereits multicast addPropertyChangeListener() und removePropertyChangeListener(), wodurch Sie sich darum nicht mehr zu k.mmern brauchen. Als Sahneh$ubchen stellt es auch ein firePropertyChange() zur Verf.gung, wodurch Ihre Setter-Methode so angepasst werden kann, dass diese das Absenden von Eigenschafts$nderungs-Events durch ein einziges Statement unterst.tzt. Da PropertyChangeSupport eine Klasse und keine Schnittstelle ist, gibt es zwei Wege, auf denen Sie diese verwenden kGnnen: 590
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Sie kGnnen Ihre JavaBeans als Unterklasse davon bilden, Ihre JavaBeans kGnnen eine Instanz von PropertyChangeSupport enthalten und das Eigenschafts$nderungsmanagement dahin delegieren. Die erste Option ist sehr restriktiv und kann in vielen F$llen unmGglich sein (Java erlaubt keine mehrfache Implementierungsvererbung, nur mehrfache Schnittstellenvererbung), weshalb hier ein Beispiel der zweiten Option gezeigt wird: import java.beans.*;
Listing 18.2
public class TestBean {
TestBean.java
// Eine Instanz von PropertyChangeSupport, um ihr die // ganze schwere Arbeit zu :berlassen protected PropertyChangeSupport butler = new PropertyChangeSupport(this); // Die Innereien der Eigenschaft 'glitzyProperty' protected int starValue; //---------------// Constructor //---------------public TestBean() { starValue = 99; // Der Eigenschaft einen Dummy-Startwert geben } //-------------------------------------------------// set()/get() f:r die Eigenschaft 'glitzyProperty' //-------------------------------------------------public void setGlitzyProperty(int newValue) { int oldValue = starValue; starValue = newValue; butler.firePropertyChange("glitzyProperty", new Integer(oldValue), new Integer(newValue)); } public int getGlitzyProperty() { return starValue; } //-------------------------------------------------// Die (De)Registrationsmethoden sind trivial: // Lassen Sie einfach die Klasse // PropertyChangeSupport // die Arbeit machen. //-------------------------------------------------591
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
public void addPropertyChangeListener (PropertyChangeListener listener) { butler.addPropertyChangeListener(listener); } public void removePropertyChangeListener( PropertyChangeListener listener) { butler.removePropertyChangeListener(listener); butler.removePropertyChangeListener(listener); } } // Ende der Klasse TestBean TestBean exportiert eine einzelne gebundene (integer-)Eigenschaft, genannt glitzyProperty. Beachten Sie, dass die Registrierung von Listener f.r Eigenschafts$nderungen auf Pro-JavaBean-Basis und nicht auf Pro-Property-Basis stattfindet. Es gibt deshalb keinen Weg, festzustellen, ob eine bestimmte Eigenschaft gebunden oder schlicht ist. Da das TestBean nur eine einzige Eigenschaft enth$lt und dieser der Außenwelt signalisiert, dass sie Eigenschafts$nderungs-Events absenden kann, folgt daraus, dass glitzyProperty gebunden sein muss. Wenn eine weitere Eigenschaft hinzugef.gt w.rde, h$tte der Client keine MGglichkeit, zu wissen, welche der beiden gebunden ist oder ob sogar beide gebunden sind. Wenn dies ein Problem f.r Ihre JavaBeans ist, dann finden Sie sp$ter in diesem Kapitel unter „Registrieren auf Basis von Eigenschaften“ eine LGsung.
Hinweis
Beachten Sie die Reihenfolge der Aktionen in der Setter-Methode: (1) Die Eigenschaft wird zuerst geupdatet und (2) dann werden die Benachrichtigungs-Events abgeschickt. Diese Reihenfolge ist ein notwendiger Teil einer gebundenen Eigenschaft, die dem Standard der JavaBeans entspricht. Ein weiterer Aspekt von TestBean ist, dass es keine grafische JavaBean ist: es gibt keinerlei sichtbare Repr$sentation. JavaBean-kompatible Umgebungen sollten keine Probleme mit solchen JavaBeans haben. Wenn ein Anwender in der Lage sein muss, unsichtbare JavaBeans zu manipulieren, dann sollte das Werkzeug oder Programm einen Ersatz einer solchen grafischen Darstellung anbieten. Die BeanBox zum Beispiel verwendet die Darstellung des Namens als Handle. Die BeanBox kann ebenfalls alle nicht-grafischen JavaBeans .ber den Men.punkt View>Hide Invisible Beans verstecken. Obwohl unsichtbare JavaBeans im Sinne des Standards vGllig legal sind, werden Sie normalerweise nur solche JavaBeans erstellen, die eine minimale grafische Darstellung haben. Dies wird durch das Erweitern von java.awt.Canvas und die Darstellung von irgendetwas auf dem Canvas erreicht oder durch die Erweiterung von java.awt.Panel und das Hinzuf.gen irgendwelcher AWT- oder eigenen Komponenten zum Panel. Da Sie jetzt verstehen, warum TestBean in dieser Form geschrieben ist, wird jetzt die korrekte Funktion des Event Change-Mechanismus getestet:
592
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
import java.beans.*; import java.io.*; public class TestBeanPropertyChangeDemo implements PropertyChangeListener { protected TestBean ourBean;
Listing 18.3 TestBeanProperty ChangeDemo.java
//--------------------------------------------------// main() Einstiegspunkt //--------------------------------------------------public static void main (String[] args) { new TestBeanPropertyChangeDemo(); } //--------------------------------------------------// TestBeanPropertyChangeDemo Constructor //--------------------------------------------------public TestBeanPropertyChangeDemo() { ourBean = (TestBean) newBean("TestBean"); if ( ourBean == null ) { System.out.println("Could not instantiate" + " TestBean."); System.exit(10); } // Registriere uns als interessiert in `nderungen // der Eigenschaften von Button ourBean.addPropertyChangeListener(this); // Modifiziere eine unserer Bean-Eigenschaften ourBean.setGlitzyProperty(1234); // quit System.exit(0); } //--------------------------------------------------// propertyChange() ist die Methode, die wir // aus der Schnittstelle PropertyChangeListener // implementieren m:ssen. Hier hIren wir von // sich [ndernden OurButton-Eigenschaften. //--------------------------------------------------public void propertyChange(PropertyChangeEvent pcEvent) { String changedProperty; Object oldPropertyValue, newPropertyValue; changedProperty = pcEvent.getPropertyName(); oldPropertyValue = pcEvent.getOldValue(); newPropertyValue = pcEvent.getNewValue();
593
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
System.out.println("TestBean property '"+ changedProperty +"'"); System.out.println(".. changed from '"+ oldPropertyValue +"'"); System.out.println(".. to '"+ newPropertyValue +"'"); } //--------------------------------------------------// Utility-Methode zum Instanzieren von Beans. //--------------------------------------------------public static Object newBean(String beanName) { Object aBean; try { aBean = Beans.instantiate(null, beanName); } catch (ClassNotFoundException noSuchBean) { System.out.println("newBean() failed: "+ noSuchBean); return null; } catch (IOException beanIOerror) { System.out.println("newBean() I/O error while" + " loading bean: " + beanIOerror); return null; } return aBean; } } // Ende der Klasse TestBeanPropertyChangeDemo Wenn Sie dieses Programm von der Konsole aus starten (es Gffnet keine GUI-Komponenten, da TestBean eine nicht-grafische JavaBean ist), kGnnen Sie sehen, dass die gebundenen Eigenschaften korrekt die Außenwelt dar.ber informieren, wie sie sich ver$ndern: C:\MasteringBeans\ch04>javac TestBean.java C:\MasteringBeans\ch04>javac TestBeanPropertyChangeDemo.java C:\ MasteringBeans\ch04>java TestBeanPropertyChangeDe mo TestBean property 'glitzyProperty' .. changed from '99' .. to '1234' Beachten Sie, wie der etwas schwerf$llige Prozess der Instanzbildung (der normalerweise Beans.instantiate() in einem try-catch-Statement einbettet) in eine einzelne Methode newBean() umgewandelt wurde. Diese Methode ist tats$chlich generisch genug, um dem Utilities-Paket hinzugef.gt zu werden. F.r zuk.nftige Wiederverwendung sollten Sie die Methode newBean() in einer neuen Utilities-Klasse genannt BeansKit speichern, die wiederum in einem Unterpaket von utilities.beans gespeichert ist. 594
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Das Utilities-Paket der JavaBeans muss installiert werden, bevor Sie diese Beispiele ausf.hren kGnnen. Hinweis
Testen gebundener Eigenschaften in der BDK-BeanBox Statt ein ganzes Programm zum Testen der gebundenen Eigenschaften von in der Entwicklung befindlichen JavaBeans selbst zu schreiben, kGnnen Sie auch die BDKBeanBox verwenden, um die Funktionsf$higkeit zu testen. Um JavaBeans in der BeanBox zu testen, sollten Sie Ihre zu testenden JavaBeans in eine .jar-Datei verpacken. Verwenden Sie dazu folgende Prozedur: Erzeugen Sie eine Datei mit dem Namen TestBean.mf mit dem folgenden Inhalt: Name: TestBean.class Java-Bean: True Groß- und Kleinschreibung ist hier von Bedeutung, darum achten Sie auf diese Details. Als N$chstes erzeugen Sie die eigentliche .jar-Datei, indem Sie jar auf folgende Art aufrufen: jar cvfm TestBean.jar TestBean.mf TestBean.class Dieser Aufruf von jar erzeugt eine Datei TestBean.jar unter Verwendung von Test Bean.mf als Vorlage und speichert die Datei TestBean.class als einzige Datei in der neu erzeugten .jar-Datei: adding: manifest adding: TestBean.class (in=1002) (out=546) (deflated 45%) Alles was nun noch getan werden muss, ist das Kopieren oder Verschieben der erstellten .jar-Datei in das jars-Verzeichnis des BDK-Verzeichnisbaums. Auf einer DOS-basierten Maschine kGnnte dies mit folgendem Kommando geschehen: copy TestBean.jar \Bdk\jars Dies setzt voraus, dass sich Ihr Arbeitsverzeichnis auf derselben Partition wie Ihr BDK befindet und dass Sie das BDK in das Wurzelverzeichnis dieser Partition installiert haben. Wenn Sie jetzt die BeanBox starten, sollten Sie TestBean im ToolBox-Fenster aufgef.hrt sehen. Die folgende Abbildung 18.2 stellt die Ausgangssituation dar. Ihr n$chster Schritt besteht darin, TestBean auszuw$hlen und eine Instanz davon irgendwo im Designpanel der BeanBox zu platzieren. Um den Event der Eigenschafts$nderung zu testen, m.ssen Sie die JavaBean mit einer BDK ChangeReporter Demonstration Bean verbinden. W$hlen Sie dieses deshalb aus der ToolBox und platzieren Sie es neben dem TestBean. Wenn Sie TestBean 595
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
ausw$hlen, werden Sie sehen, dass das PropertySheet-Fenster die Eigenschaften zusammen mit den aktuellen Werten darstellt. Die .bern$chste Darstellung (Abbildung 18.3) zeigt diese Situation.
Abb. 18.2 Abbildung 18.1: Die BeanBox zeigt TestBean im ToolBox-Fenster
Nun m.ssen Sie ChangeReporter mit TestBean verbinden. Der einzige Zweck von ChangeReporter besteht darin, PropertyChangeEvents in einem Textfeld auszugeben. Die Verbindung wird erstellt, indem der Quelle mitgeteilt wird, mit dem Ziel Verbindung aufzunehmen, nicht umgekehrt (was vielleicht eher der aktiven Rolle des Listeners entspr$che). W$hlen Sie also TestBean und dann den Men.punkt Edit>Events>PropertyChange. Wenden Sie den Men.eintrag PropertyChange an. Abbildung 18.4 zeigt die Navigation durch die Men.s. Die BeanBox l$sst Sie nun das Ziel des Listeners f.r den PropertyChangeEvent von TestBean angeben. Ein Gummiband erlaubt es Ihnen, eine verbindende Linie zwischen den beiden JavaBeans zu ziehen. Abbildung 18.5 zeigt, wo Sie den Endpunkt der Linie platzieren sollten. Klicken Sie (linke Maustaste), um die Linie einzufrieren und die Verbindung zu definieren.
596
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Abb. 18.3 Das Panel der BeanBox mit dem ausgew7hlten TestBean und einem ChangeReporter, bereit, verbunden zu werden
Die BeanBox Gffnet jetzt ein EventTargetDialog-Fenster, das alle mGglichen Methoden im Ziel-Listener auflistet, die mit dem generierten Typ von Event kompatibel sind. Im Fall der Demonstration Bean ChangeReporter enth$lt es nur eine Methode, die an PropertyChangeEvents interessiert ist: reportChange(). W$hlen Sie diese Methode aus und best$tigen Sie mit OK (siehe Abbildung 18.6).
Abb. 18.4 Ausw7hlen des propertyChange-Events von TestBean
597
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Abb. 18.5 Spezifizieren der Verbindung zwischen Event Source und Event Listener
Zu diesem Zeitpunkt ist die Verbindung vollst$ndig und alle Eigenschafts$nderungen in TestBean werden von ChangeReporter in dessen Textfeld ausgegeben. Wenn Sie jetzt TestBean erneut ausw$hlen und die Eigenschaft glitzyProperty im PropertySheet-Fenster ver$ndern, werden Sie sehen, dass die JavaBean diese Snderung erfolgreich per Event an die interessierten Listener weitermeldet (Sie kGnnen weitere ChangeReporter hinzuf.gen, wenn Sie sich davon .berzeugen wollen, ob das Multicasting funktioniert). Abbildung 18.7 ist der Beweis daf.r, dass TestBean korrekt funktioniert.
598
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Abb. 18.6 Der Ziel-Listener kann mehrere kompatible Methoden enthalten, die dazu f7hig sind, bestimmte Events zu empfangen. Das EventTargetDialog-Fenster l7sst Sie die richtige Methode w7hlen.
Registrieren auf Basis von Eigenschaften Bisher haben Sie in diesem Buch gelesen, dass immer dann, wenn sich ein Listener f.r Eigenschafts$nderungs-Events registriert, dieser Mitteilungen .ber Snderungen aller ge$nderten Events gebundener Eigenschaften durch die eine propertyChange()-Methode erh$lt. In den meisten F$llen sind Listener auch nur an einem kleinen Teil der gebundenen Eigenschaften interessiert. Ein Listener kann zum Beispiel an den dimensionsbezogenen Eigenschaften interessiert sein, w$hrend ein anderer nur an den Eigenschaften zur Fehlersuche interessiert ist. Mit dem bislang vorgestellten Schema werden alle Listener benachrichtigt, sobald sich irgendeine gebundene Eigenschaft $ndert, auch wenn sich viele Listener f.r diese spezielle Ver$nderung gar nicht interessieren und diese Benachrichtigung deshalb ignorieren, nachdem einige Prozessorzyklen verschwendet wurden, um dies herauszufinden.
599
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Abb. 18.7 Die Eigenschaft glitzyProperty 1bertr7gt korrekt die Eigenschafts7nderungs-Events an alle interessierten Listener
Um diese (teuren) Snderungs-Events zu reduzieren, die niemanden interessieren, kGnnen JavaBeans Listener-Managementmethoden auf einer Pro-Eigenschaft-Basis anbieten. Das Template der Methode ist: void addListener(PropertyChangeListener p); void removeListener(PropertyChangeListe ner p); oder void addListener(VetoableChangeListener p); void removeListener(VetoableChangeListe ner p); (Die letzten beiden Methoden sind f.r constrained properties gedacht, die im n$chsten Abschnitt n$her betrachtet werden.)
600
Beachten Sie, dass diese Methoden dasselbe ChangeListener Argument als Eingabeparameter benGtigen (PropertyChangeListener respektive VetoableChangeListener). Mit anderen Worten, die Benachrichtigung wird noch immer ausschließlich .ber eine einzelne Change()-Methode aufseiten des Listeners ausgef.hrt. Das Anbieten von Methoden der (De-)Registrierung auf Pro-EigenschaftBasis ist deshalb eine Optimierung der Performance, um so die Anzahl unnGtiger
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Events zu reduzieren, die an Listener .bertragen werden, die sich daf.r nicht interessieren. Das bedeutet aber nicht, dass Listener eine Pro-Eigenschaft Event receiveMethode haben kGnnen. Alle Events treffen nach wie vor in der zentralen Sammelstelle ein, auch bekannt als propertyChange()-Methode, und m.ssen dort bei deren Eintreffen ausgesondert werden. Wenn Snderungen von Eigenschaften multicast sind, kGnnen ein oder mehrere Listener ein starkes Interesse an dem neuen Wert der Eigenschaft haben. Ein bestimmter Listener kGnnte nicht dazu in der Lage sein, diesen neuen Wert der Eigenschaft in seiner BlackBox zu reflektieren, weil – sofern der Listener betroffen ist – der Wert ung.ltig ist oder sich außerhalb des erlaubten Bereichs befindet. Um mit solchen Situationen umgehen zu kGnnen, unterst.tzen die Eigenschaften von JavaBeans ein letztes Feature, das Gegenstand des n$chsten Abschnitts ist.
Beschr5nkte Eigenschaften Beschr$nkte Eigenschaften (constrained properties) sind die am weitesten fortgeschrittenen und – ungl.cklicherweise – komplexesten Eigenschaftstypen. Sie kGnnen das Annehmen bestimmter Werte durch Auswerfen einer java.beans.PropertyVetoException verweigern. Diese Exception hat ihren Ursprung normalerweise nicht innerhalb der JavaBeans selbst, sondern in einem Listener, der dieser Snderung widerspricht. Deshalb sind beschr$nkte Eigenschaften eine um einiges komplexere Form der gebundenen Eigenschaften, weil beschr$nkte Eigenschaften ebenfalls Listeners f.r Eigenschafts$nderungen unterst.tzen, mit der Ausnahme, dass diese der widersprechenden Variante angehGren. Das Methoden-Template beschr$nkter Eigenschaften besteht aus vier Methoden: public <propertyType> get<propertyName>( ); public void set<propertyName>( <propertyType> formalParamName) throws PropertyVetoException; public void addVetoableChangeListener( VetoableChangeListener x); public void removeVetoableChangeListener( VetoableChangeListener x); Die ersten beiden Methoden sind Standardzugriffsmethoden, mit der Ausnahme, dass der Setter eine zus$tzliche throws-Anweisung hat, damit diese die setAnweisung verweigern kann. Die folgenden beiden Methoden sind Listener-Managementmethoden. Sie sind grunds$tzlich identisch mit den add/removeProperty-ChangeListener()-Methoden einfacher (nicht widersprechbarer) gebundener Eigenschaften. Durch Erkennen des Templates der obigen Setter-Methode in einer Definition der Klasse von JavaBeans kGnnen Sie darauf schließen, dass diese JavaBean ein Veto auswerfen kann. Aber wie wirft ein Listener ein Veto aus? Die Antwort liegt in der relevanten Schnittstelle des Listeners VetoableChangeListener:
601
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
public interface VetoableChangeListener extends EventListener { public void vetoableChange(PropertyChangeEvent evt) throwsPropertyVetoException; } Jeder Listener, der daran interessiert ist, etwas .ber beschr$nkte Eigenschaften zu erfahren, muss die Methode vetoableChange() implementieren. Dies ist die Stelle, an der ein Listener durch Auswerfen einer PropertyVetoException sein Veto aussprechen kann.
Hinweis
Beachten Sie, dass das tats$chlich .bertragene Event-Objekt noch immer vom Typ PropertyExchangeEvent ist. Es gibt kein VetoableChangeEvent, um zwei Typen von Events zu unterscheiden. Nur die Listener-Methoden propertyChange() und vetoableChange() machen diese Unterscheidung. Da das Auswerfen von Vetos ein zentrales Element in der Implementierung beschr$nkter Eigenschaften ist, sollten diese ausgeworfenen Vetos n$her untersucht werden: classPropertyVetoException. public class PropertyVetoException extends Exception { // constructor public PropertyVetoException(String mess, PropertyChangeEvent evt); // instance methods public PropertyChangeEvent getPropertyChangeEvent(); } Um einer widersprechbaren Snderung einer Eigenschaft zu widersprechen, muss eine neue Instanz von PropertyVetoException erzeugt werden. Der Konstruktor der Klasse benGtigt eine Nachricht, die den Grund hinter dem Veto erkl$rt, und eine Instanz von dem PropertyChangeEvent, der daf.r gesorgt hat, dass Ihre Methode dieser Snderung widersprechen will. Da Ihnen Letzteres als Argument von vetoableChange() .bergeben wird, bedeutet dies, dass Sie dieses Argument einfach an den Konstruktor der Exception .bergeben kGnnen. Als Beispiel f.r mehrere Listener, die auf eine widersprechbare Ver$nderung einer Eigenschaft zugreifen und der Ver$nderung widersprechen, stellen Sie sich folgendes Szenario vor: Ein kleines aber sehr wichtiges Land mGchte seinen politischen Status $ndern, indem es seine bisherige Neutralit$t aufgibt und einer Supermacht zuwendet. Bei dem n$chsten hypothetischen Treffen der Vereinten Nationen (UN) stimmen die Mitglieder .ber diese neue, sehr komplizierte Situation ab. Das folgende Programm PrimitiveGames simuliert dieses Szenario, indem es sich auf den Mechanismus der beschr$nkten Eigenschaften verl$sst. Die erste Komponente des Programms ist die Klasse Country, die als JavaBean mit den folgenden beiden exportierten Eigenschaften implementiert wird:
602
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
countryName countryStatus CountryName ist eine einfache gebundene Eigenschaft, w$hrend countryStatus die beschr$nkte Eigenschaft ist, um die herum die ganze Simulation aufgebaut ist. Hier die Implementierung der Klasse: import java.beans.*; public class Country { // Instanzen der Property- und VetoableChangeSupport, // um die harte Arbeit des Listener-Managements abzuge// ben. protected PropertyChangeSupport changesButler; protected VetoableChangeSupport vetosButler;
Listing 18.4 Country.java
// Die Innereien der widersprechbaren Eigenschaft // 'countryStatus' protected String countryStatus; // Die Innereien der Eigenschaft 'countryName' protected String countryName; //--------------------------------------------------// Country Constructors //--------------------------------------------------public Country() { // Alle beans brauchen vorgegebene Konstruktoren! this("Atlantis", "hidden"); } public Country(String name, String status) { this.countryName = name; this.countryStatus = status; changesButler = new PropertyChangeSupport(this); vetosButler = new VetoableChangeSupport(this); } //--------------------------------------------------// set()/get() f:r 'CountryName'-Eigenschaft //--------------------------------------------------public void setCountryName( String newValue) { String oldName = countryName; countryName = newValue; changesButler.firePropertyChange("countryName", oldName, newValue); } 603
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
public String getCountryName() { return countryName; } //--------------------------------------------------// set()/get() f:r widersprechbare 'CountryStatus'// Eigenschaft //--------------------------------------------------public void setCountryStatus(String newValue) throws PropertyVetoException { // Zuerst nachsehen, ob es Listener-Objekte gibt. // Beachten Sie, dass die Eigenschaft sich bisher // noch nicht ver[ndert hat. vetosButler.fireVetoableChange("countryStatus", countryStatus, newValue); // Wenn ein Listener der `nderung widersprochen // hat, wird diese Zeile niemals ausgef:hrt: // Die Veto Exception h[tte die Methode abgebrochen // und w[re zum Caller von setCountryStatus() // zur:ckgekehrt. // Wenn kein Listener widerspricht, wird der Wert // der Eigenschaft ge[ndert. countryStatus = newValue; } public String getCountryStatus() { return countryStatus; } //--------------------------------------------------// Die (De)Registrationsmethoden sind trivial: // Lassen Sie einfach die Klasse // PropertyChangeSupport // die Arbeit machen. //--------------------------------------------------public void addPropertyChangeListener ( PropertyChangeListener l) { changesButler.addPropertyChangeListener(l); } public void removePropertyChangeListener ( PropertyChangeL istener l) { changesButler.removePropertyChangeListener(l); }
604
public void addVetoableChangeListener ( VetoableChange Listener l) {
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
vetosButler.addVetoableChangeListener(l); } public void removeVetoableChangeListener ( VetoableChangeListener l) { vetosButler.removeVetoableChangeListener(l); } } // Ende der Klasse Country
Das Herz der Klasse (im Kontext der Diskussion beschr$nkter Eigenschaften) ist setCountryStatus(), die Setter-Methode der Eigenschaft countryStatus. Jeder Setter einer beschr$nkten Eigenschaft benachrichtigt zuerst alle registrierten Listener .ber die anstehende Snderung (w$hrend die eigentliche Snderung noch gar nicht durchgef.hrt wurde). Wenn kein Listener der Snderung widerspricht, kann nur die interne Eigenschaft ge$ndert werden.
Vort5uschung falscher Tatsachen Die algorithmische Sequenz des Tnderns, nachdem die Listener von der bevorstehenden Tnderung benachrichtigt wurden, bedeutet, dass die JavaBeans die Listener anlgen, wenn sie denen mitteilen, dass eine Tnderung bereits durchgefhrt wurde. Die Verz"gerung aufseiten der JavaBeans zwischen dem Belgen der Listener ber eine durchgefhrte Tnderung der Eigenschaft und der tatschlichen Tnderung der Eigenschaft bedeutet, dass sich Listener vollkommen auf den neuen Wert verlassen sollten, der von dem Objekt PropertyChangeEvent getragen wird und niemals auf die „ordentliche“ Getter-Methode, weil der Getter nicht dazu in der Lage sein kann, den tatschlichen Wert zu reflektieren. Getter-Methoden widersprechbarer Eigenschaften sollten nicht innerhalb der Methoden der Event-Benachrichtigung verwendet werden, die sich mit diesen Eigenschaften beschftigen. Eine weitere Quelle rgerlicher Bugs wre fr einen Listener die Verwendung des alten Werts aus einem PropertyChangeEvent. Wie Sie sehen werden, wenn die Simulation PrimitiveGames ausgefhrt wird, kann der Parameter old Value auf legale Art Werte annehmen, denen ein Listener widersprochen htte, wenn diese als neue Werte prsentiert worden wren. Deshalb verwenden Sie nicht die alten Werte, sondern beschrnken Sie Ihren Code darauf, ausschließlich die neuen Werte zu betrachten.
605
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Wie bei der Snderung einfacher Eigenschaften wurde auch hier eine JavaBeansAPI-Hilfsklasse verwendet, VetoableChangeSupport: public class VetoableChangeSupport extends Object implementsSerializable { public VetoableChangeSupport(Object sourceBean); public synchronized void addVetoableChangeListener (VetoableChangeListener listener); public synchronized void removeVetoableChangeListener (VetoableChangeListener listener); public void fireVetoableChange(String propertyName,Object oldValue, Object newValue) throws PropertyVetoException; } Diese Unterst.tzungsklasse, wie auch PropertyChangeSupport, managt die Details der unteren Ebenen wie das Registrieren der Listener und das Iterieren durch eine Liste von Listenern, wenn eine widersprechbare Snderung einer Eigenschaft abgeschickt werden muss. Allerdings macht in diesem Fall die Methode VetoableChangeSupport.fireVetoableChange() eine Menge mehr als die verwandte Methode PropertyChangeSupport.firePropertyChange(), die f.r nicht widersprechbare Snderungen benutzt wird. W$hrend letztere Methode einfach alle Listener durchgeht und diesen jeweils einen PropertyChangeEvent zuschickt, muss die Veto-bewusste Variante Folgendes machen, in Pseudo-Code: vetoed = false while (listeners) { send listener a PropertyChangeEvent (old, new) if listener vetoed change vetoed = true break out of while loop } if (vetoed) { reset iterator while (listeners) { send listener a PropertyChangeEvent (new, old) } } Auf gut Deutsch bedeutet dies, dass die Methode genau so beginnt wie das nicht beschr$nkte Gegenst.ck, aber aus seiner Event-sendenden Schleife ausbricht, sobald ein Listener der Snderung widerspricht. Dann muss die Methode wieder alle Listener durchgehen, um alle dar.ber zu informieren, dass die Eigenschaft auf den urspr.nglichen Wert zur.ckgesetzt wurde. Da Sie jetzt verstehen, wie die beschr$nkte Eigenschaft countryStatus in die JavaBean Country implementiert ist, soll nun die Klasse SuperPower n$her untersucht werden, wo auf die Snderungen der Eigenschaften geachtet wird und bedingtes Widersprechen auftritt. 606
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
import java.beans.*; import java.util.*; public class SuperPower extends Country implements VetoableChangeListener { protected static Vector bigGuys = new Vector(); protected static final int SALT_LIMIT = 2000000; // S.A.L.T // Einige zus[tzliche Attribute, die ein Land // besonders machen protected int numNuclearWarHeads;
Listing 18.5 SuperPower.java
//--------------------------------------------------// SuperPower Constructors //--------------------------------------------------public SuperPower() { // Alle Beans brauchen vorgegebene Konstruktoren! this("Unnamed superpower", 0); } public SuperPower(String name, int destructivePower) { super(name, "Independent"); this.numNuclearWarHeads = destructivePower; // F:ge neue Supermacht zur Liste der // Superm[chte hinzu bigGuys.addElement(this); } //--------------------------------------------------// set()/get() f:r Eigenschaft 'ArsenalSize' //--------------------------------------------------public void setArsenalSize(int size) { numNuclearWarHeads = size; } public int getArsenalSize() { // Wenn das tats[chliche Arsenal kleiner ist, als // viele glauben, passe dies nach oben an. if ( numNuclearWarHeads < 500000 ) { return (int) (numNuclearWarHeads * 2.5); } // Wenn das tats[chliche Arsenal grIsser ist, als // per Vertrag erlaubt, passe dies nach unten an. if ( numNuclearWarHeads > SALT_LIMIT ) { return (int) (SALT_LIMIT * 1.1); } return numNuclearWarHeads; } //---------------------------------------------------
607
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
// Die Methode vetoableChange() ist [hnlich der // Methode propertyChange(), mit der Ausnahme, dass // der Listener der `nderung widersprechen kann. // Dies wird durch Auswerfen einer PropertyVeto// Exception realisiert. //--------------------------------------------------public void vetoableChange( PropertyChangeEvent countryChanged) throws PropertyVetoException { String howChanged=""; // Extrahiere Details der Eigenschafts[nderung howChanged = (String) countryChanged.getNewValue(); System.out.print("UN member "+ countryName + "assesses the situation.. '"); System.out.println(countryChanged.getOldValue() + "' -> '"+howChanged+"'"); // Wenn ein sensitives Land seinen unabh[ngigen // Status [ndern will, dann passen alle Super// m[chte auf: if ( ! howChanged.equals("Independent") ) {
608
// Wenn das Land eine Allianz mit einer anderen // Supermacht bilden will und die Supermacht // eine grIssere Schlagkraft hat als das Land // selbst, dann widerspricht die kleinere // Supermacht dem Wechsel. int allyPosition = howChanged.indexOf("ally of"); if ( allyPosition != -1 ) { for (int i=0; i < bigGuys.size(); i++) { String allyName = howChanged.substring (ally Position+8); SuperPower ally = (SuperPower) (bigGuys.elementAt(i)); if ( ! ally.getCountryName(). equals(allyName) ) { continue; } if ( ally.getArsenalSize() > numNuclearWarHeads ) { System.out.println(countryName + "vetos change!"); String reason = countryName + " will notallow Kuwait to become " + howChanged; throw new PropertyVetoException(reason, countryChanged); }
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
} // endfor } // endif schwieriges Land will Farbe wechseln } // endif Geopolitischer Trigger } } // Ende der Klasse SuperPower Die Klasse SuperPower soll nun n$her betrachtet werden. SuperPower deklariert sich selbst als Unterklasse von Country, so dass die Eigenschaften countyName und countryStatus geerbt werden. Zus$tzlich deklariert SuperPower, dass sie ein VetoableChangeListener ist, was bedeutet, dass die Methode vetoableChange(PropertyChangeEvent x) throwsPropertyVetoException implementiert wird. SuperPower verwendet einen static (das bedeutet von allen Instanzen der Klasse gemeinsam genutzt) java.util.Vector, um die Referenzen zu jedem SuperPower-Objekt zu speichern, das es erzeugt. Das einzige zus$tzliche Instanzfeld, das hinzugef.gt wird, ist NumNuclearWarHeads, ein int, das die Feuerkraft von SuperPower enth$lt. Zu der Feuerkraft wird eine Klassenkonstante assoziiert, SALT_LIMIT, die eine Obergrenze f.r den Vorrat nuklearer SprengkGpfe darstellt. Der Konstruktor SuperPower ist unkompliziert: Wird der Name eines Landes und die jeweilige Feuerkraft .bergeben, werden diese Details aufgezeichnet und eine Referenz zu dem neu erzeugten Objekt in dessen bigGuys-Datenbank (dem statischen Vektor) gespeichert. Als N$chstes f.gt SuperPower eine eigene Schreib-/Leseeigenschaft, arsenalSize, hinzu, f.r die auch die entsprechenden Zugriffsmethoden bereitgestellt werden. Die Methode getArsenalSize() ist ein wenig verschlagen und es soll Ihnen selbst .berlassen bleiben, diese zu analysieren. Abschließend gibt es die Methode vetoableChange(), das Herz der Klasse SuperPower. Hier stimmt SuperPower als ein VetoableChangeListener dar.ber ab, ob eine Country-Bean ihre beschr$nkte Eigenschaft countryStatus $ndern darf. Der Snderungs-Event ist in einem normalen PropertyChangeEvent-Objekt eingekapselt, weshalb ein Aufruf von getNewValue() dazu f.hrt, dass der neue Wert der Eigenschaft countryStatus .bermittelt wird. Der Rest der Logik l$sst sich reduzieren auf das Herausfinden, ob der neue B.ndnispartner des ehemals unabh$ngigen Landes ein grGßeres Waffenarsenal hat und, wenn ja, dann wird dem Wechsel widersprochen (dies ist exakt dieselbe Art verr.ckter „Logik“, die von unserer Rasse angewandt wird, seit wir die GrGße des Kn.ppels unseres Gegners beurteilen kGnnen). Sobald die Klassen Country und SuperPower definiert sind, wird noch das eigentliche Programm benGtigt, das die Szenarien der Vereinten Nationen erstellt und die Superm$chte abstimmen l$sst:
609
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Listing 18.6
import java.beans.*; import utilities.beans.*;
PrimitiveGames.java
610
public class PrimitiveGames extends Object { //--------------------------------------------------// main()-Einstiegspunkt //--------------------------------------------------public static void main (String[] args) { new PrimitiveGames(); } //--------------------------------------------------// PrimitiveGames Constructor //--------------------------------------------------public PrimitiveGames() { Country valuable; SuperPower a,b,c; // Erzeuge ein kleines Land und drei Superm[chte valuable = (Country) BeansKit.newBean("Country"); a = (SuperPower) BeansKit.newBean("SuperPower"); b = (SuperPower) BeansKit.newBean("SuperPower"); c = (SuperPower) BeansKit.newBean("SuperPower"); // Gib jedem Land seine Attribute valuable.setCountryName("Kuwait"); try { valuable.setCountryStatus("Independent"); } catch (PropertyVetoException impossibleAtThisStage) { System.out.println("Caught impossible PropertyVetoException!"); System.exit(10); } a.setCountryName("Britain"); a.setArsenalSize(600000); b.setCountryName("France"); b.setArsenalSize(3000000); c.setCountryName("China"); c.setArsenalSize(12000000); // Alle Superm[chte beobachten das kleine Land // ganz genau country valuable.addVetoableChangeListener(a); valuable.addVetoableChangeListener(b); valuable.addVetoableChangeListener(c); System.out.println(""); // und nun der Moment der Wahrheit... // Kuwait will ein Verb:ndeter von China werden try { System.out.println("Attempting to have Kuwait" + " become an ally of China\n"); valuable.setCountryStatus("ally of China"); } catch (PropertyVetoException notAcceptable) {
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
System.out.println(""); System.out.println("Kuwait not allowed to " + change status because: "); System.out.println(notAcceptable); } } } // Ende der Klasse PrimitiveGames Der Kern des Programms ist das erfolgreiche Registrieren von SuperPower a, b und c als Listener beliebiger widersprechbarer Eigenschafts$nderungen, die von valuable versucht werden, zusammen mit dem Versuch von valuable, countryStatus in „ally of China“ zu $ndern. Wird das Programm von der Konsole gestartet, sehen Sie in etwa folgende Ausgabe: C:\MasteringBeans\ch04>javac PrimitiveGames.java C:\MasteringBeans\ch04>java PrimitiveGames Attempting to have Kuwait become an ally of China UN member Britain assesses the situation.. 'Independe nt' ->'ally of China' Britain vetos change! UN member Britain assesses the situation.. 'ally of C hina' ->'Independent' UN member France assesses the situation.. 'ally of Ch ina' ->'Independent' UN member China assesses the situation.. 'ally of Chi na' ->'Independent' Kuwait not allowed to change status because: java.beans.PropertyVetoException: Britain will not allowKuwait to become ally of China Diese Ausgabe kann wie folgt erkl$rt werden: Britain war das erste Land, das .ber die Ver$nderung informiert wurde und sofort widersprach (weil China mehr Feuerkraft hat). VetoableChangeSupport.fireVetoableChange() hat dann nicht mehr alle anderen registrierten Listener informiert, weil bereits ein Listener der Snderung widersprochen hat. Es wurden dann alle Listener dar.ber informiert, dass die eingeleiteten Snderungen der Eigenschaft wieder r.ckg$ngig gemacht werden und der urspr.ngliche Wert wiederhergestellt wird. Hier ist deutlich zu erkennen, dass ein Listener .ber einen Wertewechsel alt-nachneu informiert werden kann, wobei der alte Wert niemals akzeptiert worden w$re, ohne dass der Snderung widersprochen worden w$re. Dies ist der Grund, warum Ihr Code die alten Werte eines PropertyChangeEvents nicht betrachten – oder benutzen – soll. Beachten Sie, dass die Reihenfolge, in der die Listener informiert werden, nicht spezifiziert ist. Die Ausgabe des Programms h$tte deshalb auch so aussehen kGnnen:
611
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
UN member China assesses the situation.. 'Independent' ->'ally of China' UN member France assesses the situation.. 'Independen t' ->'ally of China' UN member Britain assesses the situation.. 'Independe nt' ->'ally of China' Britain vetos change! UN member Britain assesses the situation.. 'ally of C hina' ->'Independent' UN member France assesses the situation.. 'ally of Ch ina' ->'Independent' UN member China assesses the situation.. 'ally of Chi na' ->'Independent' Wenn der widersprechende Listener als Letztes informiert wird, wie in diesem Beispiel, dann wird eine Menge Arbeit durch die vorhergehenden Listener verschwendet, die die Snderung bereits in ihren Code und die Datenstrukturen propagiert haben, nur um einige Augenblicke sp$ter angewiesen zu werden, diese Snderungen wieder zur.ckzunehmen. Eine Technik, diesen Effekt zu verringern, besteht darin, eine kurze VerzGgerung in alle Aktionen einzubauen, die von einer widersprechbaren (vetoable) Snderung ausgehen, um abzuwarten, ob nicht kurz darauf diese Snderungen wieder zur.ckgenommen werden sollen. Ist dies der Fall, kGnnen beide Events als sich gegenseitig aufhebend betrachtet werden und es muss keine Snderung durchgef.hrt werden. Sie sollten jedoch mit einer solchen ProblemlGsung sehr vorsichtig sein, weil diese Technik nur dann funktionieren kann, wenn weder die Aktion noch die Zur.cknahme irgendwelche Nebeneffekte auslGsen. Falls doch, m.ssen die Aktionen individuell ausgef.hrt werden, damit diese Nebeneffekte (vorausgesetzt, es handelt sich um vom Design erw.nschte Nebeneffekte) eintreten kGnnen. Ein weiteres wichtiges Problem bei dieser verzGgernden Technik besteht darin, dass die Performance der Interaktivit$t leidet. Wie in allen anderen F$llen auch m.ssen Sie wieder einen mGglichst optimalen Mittelweg zwischen den mGglichen Wegen finden.
Hinweis
Als die Ingenieure von JavaSoft .ber die verschwenderischen Schritte des Ausf.hrens und Zur.cknehmens in Bezug auf Widerspr.che (Vetos) befragt wurden, teilten diese mit, dass widersprechbare Eigenschaften eine extrem spezialisierte Form der Eigenschaften sind und diese deshalb nur mit Bedacht verwendet werden sollten. Bei der Mehrzahl der JavaBeans werden Sie wahrscheinlich nie auch nur in Betracht ziehen, eine Unterst.tzung f.r widersprechbare Eigenschaften hinzuzuf.gen.
Testen der beschr5nkten Eigenschaften in der BDK-BeanBox Das BDK enth$lt eine Demonstration JavaBean, Voter, die jeder widersprechbaren Eigenschaft entweder widersprechen oder zustimmen kann, abh$ngig vom Zustand der booleschen Eigenschaft vetoAll. Der Zustand der wiedersprechbaren Eigenschaft countryStatus von Country kann deshalb auch in der BeanBox getestet werden. 612
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
Um Country zur BeanBox hinzuzuf.gen, m.ssen Sie so verfahren, wie im Abschnitt „Testen gebundener Eigenschaften in der BDK-BeanBox“ beschrieben: Erstellen Sie eine Datei Country.mf mit folgendem Inhalt: Name: Country.class Java-Bean: True Erzeugen Sie die .jar-Datei: jar cvfm Country.jar Country.mf Country.class Kopieren Sie Country.jar in das Verzeichnis BeanBox jar: copy Country.jar \Bdk\jars Befolgen Sie dann folgende Schritte: 1
Nehmen Sie die JavaBean Country aus der ToolBox und platzieren Sie sie auf der Designoberfl$che.
2
Nehmen Sie die Demonstration Bean Voter und platzieren Sie sie neben Country.
3
Verbinden Sie Voter und Country:
4
W$hlen Sie Country.
5
W$hlen Sie vetoableChange aus dem Men. Events.
6
Verbinden Sie die beiden mit dem Gummiband.
7
W$hlen Sie die Methode vetoableChange im EventTargetDialog.
Wenn Sie jetzt Country w$hlen und versuchen, die Eigenschaft countryStatus zu ver$ndern, wird ein Veto Error-Dialog geGffnet, was bedeutet, dass der Snderung widersprochen wurde. Abbildung 18.8 zeigt diese Situation. Wenn Sie den Dialog schließen, werden Sie sehen, dass die Eigenschaft nicht ver$ndert wurde. Sie kGnnen die Eigenschaft vetoAll von Voter von true auf false $ndern, woraufhin Voter alle widersprechbaren Snderungen zulassen wird.
613
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Abb. 18.8 Die BDK Demonstration Bean Voter widerspricht dem Versuch, die Eigenschaft countryStatus von Country zu ver7ndern (obwohl der Grund daf1r eher simpel ist)
4berprfen von Eigenschaftswerten durch beschr5nkte Eigenschaften Das Design des Systems der beschr$nkten Eigenschaften ist deutlich auf die Listener konzentriert: Es existiert, um alle registrierten Listener einer Eigenschaft zur Akzeptanz eines neuen Wertes zu befragen. Dieses System kann aber auch f.r einen etwas anderen Zweck benutzt werden: JavaBeans kGnnen der Snderung einer eigenen Eigenschaft widersprechen. Bisher haben beschreibbare Eigenschaften alle g.ltigen Werte innerhalb der Dom$ne des eigenen Typs akzeptiert. Eine Integer-Eigenschaft zum Beispiel wird alle mGglichen Java-int-Werte zwischen minus 4 Milliarden und plus 4 Milliarden akzeptieren. Dies gilt f.r alle anderen Typen entsprechend, woraus die Notwendigkeit entstehen kann, diesen Bereich etwas zu begrenzen, den Eigenschaften akzeptieren. Nehmen Sie zum Beispiel eine JavaBean, die eine Eigenschaft Alter exportiert. Ein Alter kann immer nur positive Werte annehmen und da es in Java keine vorzeichenlosen Integerwerte gibt, w.rde die Verwendung des Typs int dazu f.hren, dass Clients – wenn der Code keine entsprechenden Tests enth$lt – den internen Zustand korrumpieren kGnnten, indem sie einen negativen Wert setzen. Dem kGn-
614
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Kategorien der JavaBean-Eigenschaften
nen Sie entgegenwirken, indem Sie den Mechanismus der beschr$nkten Eigenschaften verwenden und so Eigenschaften der JavaBean „selbstbeschr$nkt“ machen, indem der Snderung widersprochen wird. Eine elegant wirkende LGsung w$re es, eine JavaBean einen VetoableChangeListener f.r ihre eigenen widersprechbaren Eigenschaften sein zu lassen. Die JavaBean kGnnte die benGtigte vetoableChange()-Methode implementieren, mit der sie die Snderungen der Eigenschaften validiert und sich selbst als ihr eigener Listener registriert. Diese „clevere“ LGsung hat einen schwer wiegenden Fehler: Sie w.rde bedeuten, dass jeder wirkliche externe Listener mindestens einmal, im ung.nstigen Fall zweimal (bei Widerspruch der Snderungen und Wiederherstellung des urspr.nglichen Zustands) benachrichtigt werden m.sste. Dies liegt daran, dass die JavaBean notwendigerweise als Erstes .ber die Snderung informiert w.rde, der sie selbst widersprochen hat. Dies kann sich im ung.nstigen Fall zu einer enormen Belastung der CPU aufsummieren, die verschwendet w$re, weil kein einziger externer Listener f.r die Snderung wirklich befragt werden muss. (Eine Benachrichtigung .ber einen Event kann eine Lawine von weiteren Events auslGsen, die durch das System propagiert werden, und jeder Event kann einige sehr teure Aktionen bedeuten, die vom Empf$nger ausgef.hrt werden.) Stattdessen sollte eine JavaBean einfach ein altmodisches if-Statement an den Anfang einer Setter-Methode einer Eigenschaft hinzuf.gen und dem Wert sofort widersprechen (also eine Exception auswerfen), wenn dieser nicht akzeptabel ist. Nur der Aufrufer wird die Effekte des Widerspruchs bemerken und alle registrierten Listener bleiben von der gescheiterten Snderung des Wertes verschont. Sich auf einige einfache if- 200) { PropertyChangeEvent pcEvt = new PropertyChangeEvent(this, "age", age, newAge); throw new PropertyVetoException( "age has to be positive and less than 200 years",pcEvt); } vetoChangeSuppObj.fireVetoableChange("age", age, newAge); // Wenn wir hier ankommen, sind keine Vetos aufge// treten, also [ndere die Eigenschaft age = newAge; }
615
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Wenn Sie Schwierigkeiten hatten, diesem letzten Abschnitt .ber beschr$nkte Eigenschaften zu folgen, werden Sie sich daran erinnern wollen, dass es eine gute Daumenregel ist, Ihre Designs so einfach wie mGglich zu halten (was bedeutet, nach MGglichkeit gar keine widersprechbaren Eigenschaften zu verwenden). Dies wird umso deutlicher, wenn Sie die Komplexit$t von Javas omnipr$sentem Multithreading ber.cksichtigen. Die Probleme, die mit Eigenschaften und Multithreading zusammenh$ngen, werden im n$chsten Abschnitt erkl$rt.
Eigenschaften und Multithreading Java ist eine sehr dynamische Sprache und enth$lt einfach zu verwendende Multithreading-Sprachkonstrukte und -Unterst.tzungsklassen. Viele Java-Programme verlassen sich auf Multithreading, um so die Applikation intern zu parallelisieren, die Netzwerkanbindung zu verbessern oder das Antwortverhalten zum Anwender zu beschleunigen. Die meisten Java-Laufzeitumgebungen verwenden Multithreading, um die Garabage Collection von Java zu implementieren. Zus$tzlich verl$sst sich das AWT f.r seine Funktionalit$t ebenfalls auf separate Threads. Kurz gefasst: Selbst die einfachsten Java-Programme werden in einer aktiven MultithreadingUmgebung geboren. JavaBeans werden deshalb in solchen dynamischen Umgebungen mit mehreren Threads eingesetzt und hier liegt die klassische Gefahr so genannter race conditions. Solche race conditions sind vom Timing abh$ngige Szenarios des Programmablaufs, die zur Korruption des Status (Programmdaten) f.hren kGnnen (im n$chsten Abschnitt werden Sie ein solches Szenario im Detail kennen lernen). Jede JavaBean muss bereits im Design solche race conditions ber.cksichtigen, damit sie die gleichzeitige Benutzung durch mehrere Client-Threads aush$lt.
Probleme des Multithreadings mit einfachen Eigenschaften Implementierungen von JavaBeans m.ssen davon ausgehen, dass mehrere Threads gleichzeitig auf eine Instanz zugreifen und/oder diese ver$ndern. Als Beispiel einer nicht korrekt implementierten JavaBean (soweit es das Multithreading betrifft) soll das folgende BrokenProperties zusammen mit dem assoziierten MTProperties-Testprogramm dienen: Listing 18.7 BrokenProperties.java
import java.awt.Point; // Demonstration Bean, die nicht vor der Verwendung // durch multiple Threads gesch:tzt ist. public class BrokenProperties extends Point { //--------------------------------------------------// set()/get() f:r Eigenschaft 'Spot' //--------------------------------------------------public void setSpot(Point point) { // 'spot' Setter
616
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
this.x = point.x; this.y = point.y; } public Point getSpot() { // 'spot' Getter return this; } } // Ende von Bean/Klasse BrokenProperties
import java.awt.Point; import utilities.*; import utilities.beans.*;
Listing 18.8 MTProperties.java
public class MTProperties extends Thread { protected BrokenProperties myBean; // Die Ziel-Bean, die getroffen werden soll... protected int myID; // Jeder Thread tr[gt eine ID //--------------------------------------------------// main() Einstiegspunkt //--------------------------------------------------public static void main (String[] args) { BrokenProperties bean; Thread thread; bean = (BrokenProperties) BeansKit.newBean( "Broken Properties"); for (int i=0; i < 20; i++) { // starte 10 Threads, um das Bean zu testen thread = new MTProperties(bean, i); // Threads erhalten Zugriff auf das Bean thread.start(); } } //--------------------------------------------------// MTProperties Constructor //--------------------------------------------------public MTProperties(BrokenProperties bean, int id) { // Notiere das zu adressierende Bean this.myBean = bean; // Notiere wer wir sind this.myID = id; } //--------------------------------------------------// Die Hauptschleife des Threads: // Wiederhole unendlich
617
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
// Erzeuge einen zuf[lligen neuen Punkt mit x == y // Teile Bean mit, den Punkt als neue Eigenschaft // 'spot' zu :bernehmen // Frage Bean nach aktuellem Zustand von 'spot' // Gib eine Mitteilung aus, wenn spot x ungleich // spot y ist //--------------------------------------------------public void run() { int someInt; Point point = new Point(); while ( true ) { someInt = (int) (Math.random()*100); point.x = someInt; point.y = someInt; myBean.setSpot( point ); point = myBean.getSpot(); if ( point.x != point.y ) { System.out.println("Bean corrupted ! x= " + point.x +", y= " + point.y); System.exit(10); } System.out.print( (char) ('A' + myID) ); System.out.flush(); } } } // Ende der Klasse MTProperties Die beiden Quellcodes definieren eine JavaBean, genannt BrokenProperties, und eine Klasse MTProperties, die benutzt wird, um die JavaBean in 20 Threads auszuf.hren. Beginnend mit dem main()-Einstiegspunkt von MTProperties soll der Ablauf dargestellt werden: Eine Instanz von BrokenProperties wird gebildet, gefolgt von der Erzeugung und dem Starten von 20 Threads. Die Klasse MTProperties erweitert die Klasse java.lang.Thread, weshalb die Klasse MTProperties durch Implementieren der Methode run() in einen Thread umgewandelt werden kann (vergleiche mit Schnittstelle java.lang.Runnable). Der Konstruktor der Threads nimmt zwei Argumente: das JavaBean-Objekt, mit dem kommuniziert wird und eine eindeutige Identifikation, damit die einzelnen Threads w$hrend der Laufzeit leicht unterschieden werden kGnnen. Der aktive Teil dieser Demo ist die Methode run() in der Klasse MTProperties. Hier wird eine Endlosschleife gebildet, die zuf$llige (x,y)-Punkte erzeugt, die aber einer bestimmten Charakteristik folgen: Die x-Koordinate entspricht immer der y-Koordinate. Diese zuf$lligen Punkte werden der Methode setSpot() der JavaBean .bergeben und dann sofort mit der Methode getSpot() wieder ausgelesen. Eigentlich sollten die ausgelesenen Eigenschaften identisch mit dem wenige Millisekunden zuvor erzeugten Punkt sein. Hier eine Beispielausgabe des Programms, wenn dieses von der Kommandozeile aufgerufen wird: 618
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
C:\MasteringBeans\ch04>javac MTProperties.java C:\MasteringBeans\ch04>java MTProperties ABBBBBBBBBBBBBBBBBBDJJJJJJJJJJJJJJJJJJJJEGHHHHHHHHHHH HHHHHHHSSSSSSSSSSSSSS IICCBBBBBBBBBBBBBBBBBKBDLJMBOPLQNRTPHHHHHHHHFFFFFFFFF FFFSSSSSSSSSSSSSSSSSS FFFFFFFFFFFFFFFAAAAAACCCCCCCKKKKKKKKKKKKKKKKKMMMMMMMM MMMMMMMMMMMMMMMMMMMDD JEOQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRBBBBBBBBBBBBBBBTTT TTTTTTTTTTTTTLPPPPPPP PPPPGGHHHFFFFFFFFIIIIIIIIIIIIIISSSSSSSSSSSSSSSSSSSSAC CCCCCCCCCCCCCCCCCCKMD QQQQQQNNNNNNNNNNNNNNNNRRRRRTRRHHHHHHHHHFFFFFFFFFFFFFF FFFFIIIIIIIIIIIIIIIII MMMJEEEEEEEEEEDDDDEEEEEEEEEOOOOOOOOOOOOOOOOOOOOOOOOOO OQNNNNNNNNBTLPLRGFFFF FFFFFFFFFIIAAAAAAAAAAAAAAAAASSSSSSSSSSSSSSSSSSKKKKKKK KKKKKKKKKCCCCCCCMMJAA AACBean corrupted ! x = 67, y = 13 OOOOOOOOOOOOOOOOOOO Die Ausgabe zeigt die 20 Threads, die parallel ablaufen (soweit dies f.r einen menschlichen Beobachter feststellbar ist). Jeder Thread verwendet die ihm bei der Erstellung zugewiesene ID, um einen der Buchstaben zwischen ‚A‘ und ‚T‘ (die ersten 20 Buchstaben des Alphabets) auszugeben. Sobald ein Thread feststellt, dass die ausgelesene Eigenschaft nicht mit dem programmierten Charakteristikum x = y .bereinstimmt, gibt der Thread die Mitteilung „Bean corrupted“ aus und stoppt das Experiment. Was Sie sehen kGnnen, ist der den Status korrumpierende Seiteneffekt einer race condition innerhalb des setSpot()-Codes. Hier noch einmal die Methode: public void setSpot(Point point) { // 'spot' setter this.x = point.x; this.y = point.y; } Was kann an einem so einfachen St.ck Code falsch funktionieren? Stellen Sie sich vor, ein Thread A ruft setSpot()mit einem Argument f.r den Punkt (67,67) auf. Wenn nun die Zeit stark verlangsamt wird, kGnnten Sie sehen, dass die JVM jedes einzelne Statement ausf.hrt. Thread A f.hrt das Kopieren der x Koordinate (this.x = point.x;) aus ... und dann wird Thread A plGtzlich vom Betriebssystem eingefroren und Thread C wird eine gewisse Zeit lang ausgef.hrt. Im seinem vorherigen Ablaufzustand hatte Thread C gerade seinen eigenen Punkt (13,13) erzeugt, setSpot() aufgerufen und wurde dann eingefroren, um Platz f.r Thread M zu schaffen, nachdem die x-Koordinate auf 13 gesetzt wurde. Die wiederaufgenommene Ausf.hrung von Thread C setzt die programmierte Logik fort, setzt die y-Koordinate auf 13 und .berpr.ft dann, ob der Punkt der Koordinate (13,13) entspricht – aber hier wird fest-
619
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
gestellt, dass dies auf mysteriGse Art nicht mehr der Fall ist, sondern eine ung.ltige Koordinate (67,13) eingetragen ist. Dies entspricht zur einen H$lfte dem Status von Thread A, der dabei war, den Punkt (67,67) zu setzen, und zur anderen H$lfte dem Thread C, der den Punkt (13,13) setzen wollte. Das Resultat ist, dass BrokenProperties mit einem intern inkonsistenten Zustand endet: einer besch$digten Eigenschaft (engl. broken property). Wann immer eine nicht-atomare Datenstruktur (eine Struktur, die aus mehr als einem Teil besteht) von mehr als einem Thread gleichzeitig ver$ndert werden kann, m.ssen Sie diese Struktur sch.tzen. In Java wird dies mit dem Schl.sselwort synchronized erreicht.
Hinweis
Anders als alle anderen Java-Typen, garantiert Java bei long und double nicht, dass diese als atomar behandelt werden! Dies liegt daran, dass long und double 64 Bits benGtigen, was die doppelte Wortl$nge der meisten modernen CPU-Architekturen ist (32 Bits). Das Laden oder Speichern einzelner MaschinenwGrter sind intrinsisch atomare Operationen, aber das Bewegen von 64-Bit-Elementen benGtigt zwei solche Bewegungen und diese werden von Java aus den .blichen Gr.nden nicht gesch.tzt: Performance. (Einige CPUs erlauben dem Systembus, dass dieser automatisch gesichert ist, w$hrend so genannte multiword transfers ausgef.hrt werden, aber dies gilt nicht f.r alle CPUs und w$re außerdem unglaublich teuer in der Anwendung auf alle long- und double-Manipulationen!) Selbst wenn eine Eigenschaft nur aus einem einzigen long oder einem einzigen double besteht, sollten Sie deshalb immer alle Maßnahmen ergreifen, um diese long- und double-Werte davor zu sch.tzen, plGtzlich korrumpiert zu werden. Das Schl.sselwort synchronized kennzeichnet einen Block des Codes als einen atomaren Schritt. Der Code kann nicht „geteilt“ werden, wie es der Fall w$re, wenn ein anderer Thread den Code unterbricht, um dann eventuell denselben Block auszuf.hren (daher der Ausdruck reentrant Code; jeder Java-Code ist reentrant). Die LGsung f.r BrokenProperties ist trivial: Ersetzen Sie einfach die Methode setSpot() mit folgendem Code: public void setSpot(Point point) { // 'spot' setter synchronized (this) { this.x = point.x; this.y = point.y; } } oder alternativ: public synchronized void setSpot(Point point) { // 'spot' setter this.x = point.x; this.y = point.y; }
620
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
Beide Ersetzungen sind $quivalent, obwohl h$ufig die erste Methode bevorzugt wird, weil diese deutlicher zeigt, was die exakte Funktion des Schl.sselwortes synchronized ist: Ein sychronisierter Block ist immer an ein Objekt gebunden, das gesichert wird. Mit gesichert ist in diesem Falle gemeint, dass die JVM zuerst versucht, das Objekt zu sichern (den exklusiven Zugriff darauf zu erhalten) oder wartet, bis das Objekt entsichert wird, wenn es bereits gesichert ist. Der Prozess des Sicherns garantiert, dass ein Objekt nur von einem Thread zur Zeit gesichert (oder besessen) werden kann. Die Syntax synchronized (this) gibt eindeutig den internen Mechanismus wieder: Das Argument innerhalb der Klammern ist das Objekt, das gesichert werden soll (das gegenw$rtige Objekt), bevor der Codeblock ausgef.hrt wird. Die alternative Syntax, in der das Schl.sselwort synchronized als Modifikator in der Signatur der Methode verwendet wird, ist einfach eine Abk.rzung der ersten Variante. Wenn statische (static) Methoden als synchronized gekennzeichnet werden, gibt es f.r diese Methoden kein gegenw$rtiges Objekt, das gesichert werden kGnnte. Nur Instanzen von Methoden werden mit einem gegenw$rtigen Objekt assoziiert (die Objektinstanz this). Wenn also Methoden von Klassen durch synchronized gesichert werden, wird stattdessen das Objekt java.lang.Class gesichert. Dies hat weitreichende Auswirkungen auf die Performance, da eine Sammlung von Instanzen einer Klasse sich ein einzelnes assoziiertes Class-Objekt teilen. Sobald dieses Class-Objekt gesichert wird, wird verhindert, dass irgendein anderes Objekt der Klasse (egal ob 3, 50 oder 1000!) diese statische Methode aufruft. Das im Hinterkopf sollten Sie es sich gut .berlegen, ob Sie die Synchronisation auf statische Methoden anwenden wollen.
Hinweis
In der Praxis sollten Sie sich immer an die explizite synchronized-Form erinnern, da diese es Ihnen erlaubt, den kleinsten mGglichen Block innerhalb einer Methode zu „atomisieren“. Die abgek.rzte Form „atomisiert“ die ganze Methode und dies ist aus Gr.nden der Performance nicht immer das, was Sie erreichen wollen: W$hrend ein anderer Thread einen atomaren Blockcode ausf.hrt, kann kein anderer Thread auf diesen Teil zugreifen. Wenn ein Objekt gesichert wird, wird der gesamte synchronisierte Code der Klasse des Objekts atomar. Sollte Ihr Code also mehr als eine Datenstruktur enthalten, die atomar behandelt werden muss, w$hrend diese Datenstrukturen ansonsten unabhGngig voneinander sind, kann ein anderer Flaschenhals in der Performance auftreten. Clients, die synchronisierte Methoden aufrufen, die eine interne Datenstruktur manipulieren, blockieren alle anderen Methoden, die mit anderen atomaren Datenstrukturen der Klasse arbeiten. Selbstverst$ndlich sollten solche Situationen vermieden werden, indem die Klasse in kleinere Klassen aufgeteilt wird, die sich mit nur jeweils einer atomar zu behandelnden Datenstruktur zur Zeit befassen.
Hinweis
Die JVM behandelt dies, indem Warteschlangen aus Threads gebildet werden, die darauf warten, dass ein Objekt entsichert wird. W$hrend dies aus der Perspektive des Schutzes der Konsistenz zusammengesetzter Datenstrukturen eine sehr begr.ßenswerte Sache ist, kann dies zu Staus bei den Threads f.hren, wenn ein Teil des Codes, der „less-than-efficient“ ist, als synchronized gekennzeichnet ist. 621
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
Achten Sie deshalb immer genau darauf, welchen Code Sie synchronisieren: Dies sollte immer nur das absolut notwendige Minimum sein. Stellen Sie sich zum Beispiel vor, dass die urspr.ngliche setSpot()-Methode wie folgt ausgesehen h$tte: public void setSpot(Point point) { // 'spot' setter log.println("setSpot() called on " + this.toString() ); this.x = point.x; this.y = point.y; } Obwohl das Statement println logisch zur Methode setSpot() gehGrt, ist es nicht Teil des Statements, das atomar gruppiert werden muss. Deshalb w$re in diesem Fall die korrekte Anwendung des Schl.sselwortes synchronized wie folgt: public void setSpot(Point point) { // 'spot' setter log.println("setSpot() called on " + this.toString() ); synchronized (this) { this.x = point.x; this.y = point.y; } } Und nicht der „bequeme“ Weg, wie hier gezeigt: public synchronized void setSpot(Point point) { // 'spot' setter log.println("setSpot() called on " + this.toString() ); this.x = point.x; this.y = point.y; } Der erste Ansatz wird alle anderen Threads f.r das absolut notwendige Minimum an Zeit ausschließen, w$hrend der zweite Ansatz alle Threads dazu zwingt, auf etwas zu warten, das vGllig irrelevant ist: das println-Statement. Wenn Sie sich unter dem Druck der modernen Produktzyklen f.r den bequemen Weg entschlossen haben, und alle Methoden in G$nze synchronisieren, werden Ihre Anwender eine $hnlich „bequeme“ (mit geringer Performance) JavaBean erhalten.
622
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
Listener von Eigenschaften und Multithreading Multithreading f.hrt das ganze Spektrum mGglicher Probleme ein, die Ihnen das Leben als Entwickler von JavaBeans schwer machen. Hier ein weiteres Szenario, das Sie beachten sollten: Race conditions (schon wieder) kGnnen zu unerwartetem Verhalten f.hren, das aus inkorrekten Erwartungen resultiert, die mit der Reihenfolge von Aufrufen von add- und remove und dem tats$chlichen Timing der eingehenden Events zusammenh$ngen. Stellen Sie sich eine Reihe von Threads und eine einzelne JavaBean mit einer gebundenen Eigenschaft vor. Wenn diese Threads kontinuierlich die eine Eigenschaft registrieren, deregistrieren und modifizieren (die Gr.nde hierf.r sind im Augenblick nebens$chlich), kann es passieren, dass ein Thread einen g.ltigen Event einer Eigenschafts$nderung erh$lt, obwohl er sich gerade deregistriert hat (und deshalb nicht erwartet, Events zu empfangen). Die folgende JavaBean UnexpectedEvents und das Testprogramm MTListeners demonstrieren dieses Ph$nomen: import java.beans.*;
Listing 18.9
public class UnexpectedEvents { protected PropertyChangeSupport butler; // butler does all the work //--------------------------------------------------// UnexpectedEvents Constructor //--------------------------------------------------public UnexpectedEvents() { butler = new PropertyChangeSupport(this); }
UnexpectedEvents.java
//--------------------------------------------------// set()/get() f:r 'Property' Dummy Eigenschaft //--------------------------------------------------public void setProperty( int value) { System.out.println("Bean changing property." + " Firing PC event."); butler.firePropertyChange("property", new Integer(0), new Integer(1)); } public int getProperty() { return 1; } //--------------------------------------------------// Listener Registrierungsmethoden //--------------------------------------------------public void addPropertyChangeListener( PropertyChange Listener l) { butler.addPropertyChangeListener(l); }
623
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
public void removePropertyChangeListener( PropertyChangeListener l) { butler.removePropertyChangeListener(l); } } // Ende von Bean/Klasse UnexpectedEvents
Listing 18.10 MTListeners.java
import java.beans.*; import utilities.*; import utilities.beans.*; public class MTListeners extends Thread implements PropertyChangeListener { protected UnexpectedEvents myBean; // Das zu testende Bean ... protected int myID; // Jeder Thread hat eine eigene ID protected boolean readyForEvents = false; // Sind wir schon registriert? //--------------------------------------------------// main()-Einstiegspunkt //--------------------------------------------------public static void main (String[] args) { UnexpectedEvents bean; Thread thread; bean = (UnexpectedEvents) BeansKit.newBean( "UnexpectedEvents"); for (int i=0; i < 5; i++) { // Starte N Threads um Bean zu testen thread = new MTListeners(bean, i); // Threads erhalten Zugriff auf Bean thread.start(); } } //--------------------------------------------------// MTListeners Constructor //--------------------------------------------------public MTListeners(UnexpectedEvents bean, int id) { this.myBean = bean; // notiere das zu // adressierende Bean this.myID = id; // notiere, wer wir sind } //--------------------------------------------------// Die Thread-Hauptschleife: // Wiederhole endlos
624
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
// Registriere als Listener, setze flag, um Events // zu akzeptieren // Deregistriere als Listener, setze flag, um Events // abzulehnen // `ndere Bean-Eigenschaft // // Falls wir jemals einen Event erhalten, w[hrend // wir eigentlich keinen erhalten sollten, // teile dies mit und halte an. //--------------------------------------------------public void run() { while ( true ) { // Registriere bei Bean, das bedeutet, wir // kInnten von jetzt an Events erwarten. synchronized (this) { System.out.println(myID +" registering."); myBean.addPropertyChangeListener(this); readyForEvents = true; } // Lasse andere Threads f:r einige Zeit laufen randomSleep(); // Deregistriere uns jetzt, das bedeutet, wir // sollten eigentlich keine weiteren Events mehr // von der Bean bekommen. synchronized (this) { System.out.println(myID +" un-registering."); myBean.removePropertyChangeListener(this); readyForEvents = false; } // Lasse andere Threads f:r einige Zeit laufen randomSleep(); // dann modifiziere die Eigenschaft der Bean: System.out.println(myID + " about to change bean p roperty.."); myBean.setProperty( (int) (Math.random()*50)); } } //--------------------------------------------------// Die Implementierung der Schnittstelle // PropertyChangeListener //--------------------------------------------------public void propertyChange( PropertyChangeEvent pcEvent) { if ( readyForEvents == false ) { System.out.println("I ("+ myID + ") got an event while I did not" + " expect to receive one!!"); System.exit(0);
625
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
} System.out.println(myID + " heard of property change."); } //--------------------------------------------------// Hilfsfunktion, die einen Thread f:r eine // zuf[llige Zeitspanne (kleiner 1 Sekunde) // einschl[fert //--------------------------------------------------protected void randomSleep() { MiscKit.delay( (int) (Math.random()*1000)); } } // Ende der Klasse MTListeners Wie bei der schon vorher gezeigten Multithreading-Demonstrationsklasse MTProperties ist das Herz der Klasse die MTListener-Methode run(), in der sich die Logik des Threads verbirgt. Was diese Methode macht, ist ziemlich banal: Sie registriert und deregistriert fortlaufend ihre Threads als Listener f.r die Quelle des Events der Eigenschafts$nderung, w$hrend gleichzeitig die Bean-Eigenschaft ver$ndert wird und eine Menge zuf$lliger Pausen eingelegt werden. Wenn Sie MTListener von der Konsole ausf.hren, kGnnte die Ausgabe zum Beispiel so aussehen: C:\MasteringBeans\ch04>javac MTListeners.java C:\MasteringBeans\ch04>java MTListeners 0 registering. 2 registering. 1 registering. 3 registering. 4 registering. 4 un-registering. 4 about to change bean property.. Bean changing property. Firing PC event. 0 heard of property change. 2 heard of property change. 1 heard of property change. 3 heard of property change. 1 un-registering. 4 registering. 0 un-registering. 3 un-registering. 2 un-registering. 2 about to change bean property.. Bean changing property. Firing PC event. 4 heard of property change. 2 registering. 1 about to change bean property.. Bean changing property. Firing PC event. 4 heard of property change. 626
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
Eigenschaften und Multithreading
2 heard of property change. 1 registering. 0 about to change bean property.. Bean changing property. Firing PC event. 4 heard of property change. 1 un-registering. 2 heard of property change. I (1) got an event while I did not expect to receive one!! Das Programm beginnt damit, dass Klone von Threads erzeugt werden, damit die Ausgabe mit einer Reihe von Threads beginnt, die mitteilen, dass diese sich als Listener bei den JavaBeans registrieren. Beachten Sie, dass die Ausgabe bereits durcheinander gew.rfelt ist, obwohl die Threads in einer strikten 0-1-2-3 ... Reihenfolge gestartet werden. Dies liegt an den vom darunter liegenden Betriebssystem in diesem Augenblick getroffenen Entscheidungen .ber die Zeitplanung der Tasks oder Prozesse (woraus folgt, dass bei Ihnen die Ausgabe des Programms mit an Sicherheit grenzender Wahrscheinlichkeit anders aussehen wird) und ist auch genau der Grund f.r die h$ufig unvorhersagbare Reihenfolge prGziser Events in Multithreading-Systemen. (Selbstverst$ndlich sind diese Systeme in ihrer Gesamtheit deterministisch, wie auch vGllig sequenzielle Systeme, aber dies liegt auch nur an dem Vertrauen auf bestimmte kritische Synchronisationspunkte.) Die n$chste Ausgabe ist Thread 4, der das Gl.ck hatte, lange genug laufen zu kGnnen, um sich in nur einer einzigen Zeitscheibe zu registrieren, zu deregistrieren und die Eigenschaft zu $ndern. Die Snderung der Eigenschaft lGst das Aussenden eines PropertyChangeEvents an alle augenblicklich registrierten Listener aus (Threads 0,1,2 und 3). Sie sehen dies in den aufeinander folgenden Zeilen „x heard of property change.“ W$hrend die Zeit vergeht zeigen die Threads ihren frei umherlaufenden Charakter, indem sie zunehmend mit Pausen ineinander verschachtelt (interleaved) ablaufen (siehe Ausgabe des Programms). Sehen Sie sich nun wieder die Zeile „0 about to change bean property ...“ an. An dieser Stelle sind die Threads 1,2 und 4 registriert und kurz darauf hGrt Thread 4 schon von der Snderung, aber Thread 1 deregistriert sich bereits, bevor er etwas von der Snderung gehGrt hat. Als N$chstes erf$hrt Thread 2 von der Snderung und Peng! ... Thread 1, der in diesem Augenblick gar kein Interesse mehr an den Snderungen hat, wird von der Snderung der Eigenschaft informiert, die Thread 0 einige Schritte zuvor ausgelGst hatte. Thread 1 war nicht als Listener f.r diesen Event registriert und wurde trotzdem ein Event, den dieser Thread in diesem Augenblick gar nicht erwartet hatte. Wenn dies ein Bug in der Methode PropertyChangeSupport.firePropertyChange() w$re, w.rde hier nicht in solcher Breite und Tiefe darauf eingegangen. Das Problem ist in diesem Fall, dass dies ein g.ltiger Nebeneffekt der Freiheit der Implementierung ist, die den implementierenden der Event-auslGsenden Methoden einger$umt wurde. W$hrend durch die Liste der Listener iteriert wird, kann (nicht: muss!) eine Event-absendende Methode die Liste sperren, um so Snderungen zu verhindern, w$hrend
627
H:/Sybex/Java_2_Buch/DasBuchNeu.3d from 4.1.2001 Page size: 168,00 x 240,00 mm
JavaBean-Eigenschaften
die Listener benachrichtigt werden. Es ist klar, dass im Fall eines PropertyChangeSupport.firePropertyChange() die Liste gesperrt wird (mittels clone() auf den Vektor, der alle Listener enth$lt). Dies erkl$rt, warum Thread 1 sich selbst als Listener entfernen konnte und trotzdem Augenblicke sp$ter den Event erhielt.
Hinweis
628
Es ist klar, dass Multithreading die Implementierung von JavaBeans sehr stark belasten kann. Deshalb ist es von kritischer Bedeutung, dass Sie Ihre JavaBeans immer ausreichenden Belastungstests aussetzen. Verwenden Sie dazu aggressive, weit hergeholte und bewusst falsch verwendete Szenarios. Die Realit$t ist meistens noch sehr viel kreativer, wenn es darum geht, unwahrscheinliche Szenarios zu finden. Wenn Sie versucht haben, die Ausgaben der Testprogramme zu reduzieren, haben Sie wegen der Unvorhersagbarkeit der Zeitplanung des Multithreadings gesehen, wie unmGglich dies ist. Die beiden Testprogramme kGnnen f.r einige Minuten laufen, ohne dass der „Fehler“ auftritt. Dieser Grund alleine sollte Sie davon .berzeugen, dass Sie Ihre JavaBeans immer umfangreichen Tests in vollst$ndig multithreadeten Umgebungen unterziehen. Lassen Sie den Simulationen ausreichend Zeit, um solche Probleme zu entdecken.
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
! + (Verkettungsoperator) 141 . (Punktoperator) 14, 32, 123 .class-Dateien 4, 479 .java-Dateien 3 // (Kommentarzeichen) 32 2-D-API 495 Bzier-Kurven 524 Clipping 513 Fllungen 508 Fraktale 528 Kreise und Ellipsen 501 Kurventypen 499 Linienattribute 504 Polygone 521 selbstdefinierte Kurven 519 Transformationen 515 Zeichenoperationen 504 2-D-Grafik 496 = = (Gleichheitsoperator) 44
A , HTML 229 abgeleitete Klasse 12 Ableiten, Konzept 12 abnorme Zust6nde 236 absolute Werte 250 abstrakte Klassen 206-207, 499 Action, Ereignis 366 action (Methode) 40 ActionEvent 563 Ereignis 394 ActionListener (Schnittstelle) 40 implementieren 41, 74 actionPerformed (Methode der Schnittstelle ActionListener) 42 berschreiben 42 actionPerformed (Methode) 74 ActionPerformed(), Methode 351 activeCount(), Methode 420 activeGroupCount(), Methode 420, 422 add-Methoden 322 addActionListener (Methode der Klasse Button) 39, 42 addActionListener (Methode der Klasse TextField) 24 addAdjustmentListener (Methode der Klasse Scrollbar) 133, 137
Adder-Applet 68 erstellen 74 Listing 78 Adder2-Applet, Listing 84 addImpl (Methode der Klasse ScrollPane) 155 addItemListener (Methode der Klasse Checkbox) 89, 92, 105 addMenu(), Methode 378 addNotify (Methode der Klasse Button) 39 addNotify (Methode der Klasse Checkbox) 89, 155 addNotify (Methode der Klasse Label) 70 addNotify (Methode der Klasse Scrollbar) 133 addNotify (Methode der Klasse ScrollPane) 155 addNotify (Methode der Klasse TextArea) 61 addNotify (Methode der Klasse TextField) 25 addTab() berladen 380 Methode 380-381 addTabbedPane(), Methode 379 Adjustment-Ereignisse 137, 335, 350 AdjustmentEvent (Klasse) 138,335 adjustmentValueChanged (Methode der Klasse AdjustmentEvent) 138 adjustmentValueChanged (Methode der Klasse Scrollbar) 148 ADK 167 AffineTransform (Klasse) 515 Methoden 515 Aktionsereignisse, von Schaltfl6chen 39 append (Methode der Klasse TextArea) 61 appendText (Methode der Klasse TextArea) 61 Applet 161, 163, 185-186 als Listener-Objekt 42 ausfhren 7 Definition 2 Gr(ße *ndern 18 initialisieren 28 kompilieren 4 Layoutkontrolle 68 neu zeichnen 13 nummerische Eingaben 68
Platzieren von Steuerelementen 68 Applet (Klasse) 11 Applet Viewer 7 -Tag Einbetten von Applets 17 Syntax 18 Applet-Beispiele Adder 68 Checkpanels-Applet 110 Radios-Applet 101 Sandwich-Applet 116 Scrollborder 144 Scroller 132 Scrpane 154 Applet-JavaBean-Hybriden 560 appletviewer 165, 189 Applikationen 160-163 Arc2D (Klasse) 499-500 Arc2D.ARC (Konstante) 501 Arc2D.CHORD (Konstante) 501 Arc2D.PIE (Konstante) 501 Argument, an ein Applet Ebergeben 19 argv 170 ArithmeticException 227 ArrayIndexOutOfBoundsException 222, 227 ArrayList 255 Arrays 580 atomare Datenstruktur 620 AusfEhrungskontext 406 Ausgabestrom 259 Autoflushing 309 AWT 265, 559 AWT (Abstract Window Toolkit) 11 AWT Container 268 AWT-Klassen 24
B Back-End-Server 456 BasicStroke (Klasse) 504 Konstruktor 504 BasicStroke.BEVEL (Konstante) 504 BasicStroke.BUTT (Konstante) 504 BasicStroke.MITER (Konstante) 504 BasicStroke.ROUND (Konstante)504 BasicStroke.SQUARE (Konstante) 504 Basisklasse 12, 204 berschreiben 12
629
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
BDK 561 Bean Deelopment Kit 561 BeanBox 561-562, 568, 595 Beans.instantiate() 588 Benutzerereignisse 40 beschr6nkte Eigenschaften 601 BezLab (Beispielprogramm) 524 Listing 526 Bibliotheken 8, 11 Bildlauf, mit Scrollpane 158 Bildlauffeld 136 positionieren 139 Bildlaufleisten Ausrichtung 135 einrichten 135 Ereignisbehandlung 137, 139 hinzufgen 131 mit BorderLayout 144 synchronisieren 149 Typen 132 Wertebereich 136 BlackBox 553-554 BlueButton 562 boolean properties 580 Boolsche Eigenschaften 580 BorderFactory, Klasse 387 BorderLayout 144 Layoutmanager 354 Positionieren von Steuerelementen 146 BorderLayout-Manager 143 Borland JBuilder 177 bound properties 582 Box 277 Breakpoints 177 Browser 479 Browserkompatibilit6t 161 Button (Klasse) 38, 385 Konstruktoren 38-39 Methoden 38 ButtonGroup 277 Bytecode 6 BHzier-Kurven 524
C C 196 C++ C-Header-Dateien CallableStatement Objekt Objektinstanz
630
196 165 469 468
Schnittstelle 474 -Tag 17 CGI 285, 493 ChangeEvent, Ereignis 392 ChangeListener 600 ChangeReporter 565 CharArrayWriter 296 charAt (Methode der Klasse String) 46 Checkbox (Klasse) 87 Konstruktoren 88-89, 90 CheckboxGroup (Klasse) 100 Konstruktoren 102 Methoden 102 CheckBoxMenuItem, Klasse 379 checker (Applet), Listing 96 checker-Applet 87 Checkpanels-Applet 110 Listing 114 Choice, Klasse 390 class (SchlEsselwort) 12 class-Anweisung 4 clearParameters(), Methode 472 CLI 460 clicker-Applet erstellen 37 Listing 50 clickers-Applet 52 Listing 58 Client/Server-Architekturen 457 Client/Server-Datenbanken, Entwicklung 455 Clients, Java-basierte 454 clip (Methode der Klasse Graphics2D) 498, 513 ClipDemo (Beispielprogramm) 514 Listing 514 Clipping 513 closePath (Methode der Klasse GeneralPath), Methoden 520 closing 262 COBRA 192 code (HTML-SchlEsselwort) 18 CODEBASE (HTML-SchlEsselwort) 19 CodeblIcke 77 Collection 255 Collections Framework 254 com.sun.*-API 277 commit(), Methode 468-469 Common Gateway Interface 493 Common Object Request Broker Architecture 491 compareTo (Methode der Klasse String) 46
compareToIgnoreCase (Methode der Klasse String) 46 Component Klasse 324-325, 327, 330 Unterklassen ableiten 324-325, 327 component container 267 concat (Methode der Klasse String) 46 connect(), Methode 463-464, 467 Connection Schnittstelle 461, 463, 465-465, 468 Schnittstellendefinition 468 Schnittstellenmethoden 468-469 constrained properties 601 Container Klasse 324-325, 345, 350 Unterklassen ableiten 324-325, 345 Content Pane, Containerebene 378 copyValueOf (Methode der Klasse String) 46 CORBA 491, 557 Core-API 164, 182 countryName 603 countryStatus 603 Cubic2D (Klasse) 499 CubicCurve2D (Klasse) 500 currentThread(), Methode 419 currentTimeMillis(), Methode 407 curveTo (Methode der Klasse GeneralPath) 524 Customer.java, Beispielprogramm 482 CustomerInfo.java, Beispielprogramm 485
D Data Hiding 202 Database Management System 455 DatabaseMetaData Objekt 469 Schnittstelle 477 DatagramPacket 282 DatagramSocket 282 DataInputStream 288 DataOutputStream 289 Dateiformat, Java-Code 3 Datenbank-Front-Ends erstellen 458
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
Datenbanken Anweisungen 470 Anwendungsebene 460, 467 API-Komponenten 460 Auto-Commit 468 Commit 468 Connectivity-Strategien 491 Datenbl(cke empfangen 478 Datenbl(cke senden 478 Ergebnismengen 469 In-Parameter 469, 472, 474 Inout-Parameter 469 Java-Beispiel 481 JDBC-ODBC-Brckentreiber 488, 490 Klassen 461 native Bibliothek-zu-Java-Treiber 489 native Protokoll-Java-Treiber 489 Netzwerkprotokoll-Java-Treiber 489 Out-Parameter 469, 474 Rollback 468 Schnittstellen 461 SQL-Anweisungen 470 Transaktionen 468 Treiber 459, 461, 488 Treiber entladen 461 Treiber laden 461 Treiberebene 460 Verbindungen herstellen 461 Web-basierte 493 Zugriffsinformationen ermitteln 469 Datenbankmodelle anbieterspezifische Bibliotheken 457 Business Rules 458 dreischichtige 457 einschichtige 455 herstellerneutrale Protokolle 458 mehrschichtige 457 monolithische 455 Multithread-f*hige 458 Versionskontrolle 457 zweischichtige 456-457 Datenelemente, Definition 13 Datenspeicherung, relationale 455 Datentyp 196 DBMS 455 delegationsbasiertes Ereignismodell 40
deleteRow(), Methode 477 Demonstration Beans 562 dependency network 258 Deposit.java, Beispielprogramm424, 428, 430 destroy() 187 digitale Signatur 192 DirectColorModel 497 Disassembler 165 doLayout (Methode der Klasse ScrollPane) 155 double 620 draw (Methode der Klasse Graphics2D) 498 drawString (Methode der Klasse Graphics) 14 Driver Klasse 461 Schnittstelle 461 Schnittstellenmethoden 463-464 DriverManager Klasse 461, 465 Klassenmethoden 465-466 DriverPropertyInfo, Klasse 463-464
E echoCharIsSet (Methode der Klasse TextField) 25 Echozeichen 393 Eigenschaften 555, 574 Eingabefelder, hinzufEgen 377 Eingabestrom 259-260 Elemente einer Klasse 13 Ellipse2D (Klasse) 499-500 enableEvents(), Methode 323 endsWith (Methode der Klasse String) 46 enumerate(), Methode 420, 422 EOFException 227 equals (Methode der Klasse String) 46 equalsIgnoreCase (Methode der Klasse String) 46 Ereignisbehandlung ActionEvent-Objekt 43 Adjustment-Ereignisse 137 mit Listener-Objekten 41 Unterschiede zwischen Java 1.0 und Java 2 40 Ereignisdelegation, Modell 320
Ereignisempf6nger Kategorien 320 Konzept 320 Ereignisempf6ngerschnittstellen 321 Typen 322 Ereignisempf6ngertypen 320 Ereignisklassen, Hierarchie 320 Ereignisse 555-556 anwendungsspezifische 321 AWT 321 Bean 321 explizit erkennen 323, 366 Ereignistypen 320 Error 252 Event, Klasse 321 Event Listener 589 Event Source 589 EventMonitor 568 EventObject, Klasse 321 events 555-556, 623 Example.java, Beispielprogramm 486 exception 220, 229-231, 234, 252 Exception Handling 221, 229 execute(), Methode 468, 471 executeQuery(), Methode 471 executeUpdate(), Methode 470 exit(), Methode 408 ExplicitButton 562 Exponenzialfunktion 250
F Farbenmodell von Java 497 Farbr6ume 497 Farbverlauf 508-509 Fat Clients 454 FileInputStream 222 FileNotFoundException 222, 227 FileOutputStream 222 fill (Methode der Klasse Graphics2D) 498 FilledBox.class 188 FilledBox.java 188 FilledBox.java-Applet 180 fillInStackTrace() 234 fillRect (Methode der Klasse Graphics) 515 FilterInputStream 261 finalize() 217 Finalizer 213, 217 Firewalls 491
631
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
FlowLayout-Manager 68, 72, 81 ersetzen 82 flushing 262 Formen, darstellen 497 FracLabTriangle (Beispielprogramm) 528 Listing 543 Fraktale zeichnen 528 Frame, Klasse 378 Frames Beispielprogramm 376 Eingabefelder hinzufgen 377 hinzufgen 377 Mens hinzufgen 377 Registerseiten hinzufgen 379 Symbole hinzufgen 381 Front-End-Anwendungen 454 erstellen 454, 456 Funktionsweise von Java 6
G Gadgets 266 garbage collection 213 gebundene Eigenschaften 582 GeneralPath (Klasse) 519 Konstruktoren 520 Methoden 520 GeneralPath2D (Klasse) 499 geschweifte Klammern, try-catch-finally-Konstrukt 229 geschweifte Klammern ({}) 176 get(), Methode 440 getAccessibleContext (Methode der Klasse Button) 39 getAccessibleContext (Methode der Klasse TextField) 25 getActionCommand (Methode der Klasse Button) 39 getAdjustable (Methode der Klasse AdjustmentEvent) 138 getAlignment (Methode der Klasse Label) 70 getBlockIncrement (Methode der Klasse Scrollbar) 133 getBytes (Methode der Klasse String) 47 getBytes(), Methode 478 getChars (Methode der Klasse String) 47 getCheckboxGroup (Methode der Klasse Checkbox) 89
632
getColumns (Methode der Klasse TextArea) 61 getColumns (Methode der Klasse TextField) 25 getConnection(), Methode 465, 467-468 getContentPane(), Methode 378 getCurrent (Methode der Klasse CheckboxGroup) 102 getEchoChar (Methode der Klasse TextField) 25 getHAdjustable (Methode der Klasse ScrollPane) 155 getHScrollbarHeight (Methode der Klasse ScrollPane) 155 getIconHeight(), Methode 381 getIconWidth(), Methode 381 getInstanceOf() 571 getItemSelectable (Methode der Klasse ItemEvent) 94, 106 getKeyCode(), Methode 321 getLabel (Methode der Klasse Button) 39 getLabel (Methode der Klasse Checkbox) 89 getLineIncrement (Methode der Klasse Scrollbar) 133 getListeners (Methode der Klasse TextField) 25 getLocalizedMessage() 234 getMaxFieldSize(), Methode 478 getMaximum (Methode der Klasse Scrollbar) 134 getMaxPriority(), Methode 419 getMessage() 234 getMetaData(), Methode 469 getMinimum (Methode der Klasse Scrollbar) 134 getMinimumSize (Methode der Klasse TextArea) 62 getMinimumSize (Methode der Klasse TextField) 25 getMoreResults(), Methode 470-471 getName(), Methode 419 getOrientation (Methode der Klasse Scrollbar) 134 getPageIncrement (Methode der Klasse Scrollbar) 134 getParent(), Methode 419 getPreferredSize (Methode der Klasse TextArea) 62 getPreferredSize (Methode der Klasse TextField) 25 getPriority(), Methode 419
getResultSet(), Methode 470-471 getRows (Methode der Klasse TextArea) 62 getScrollbarDisplayPolicy (Methode der Klasse ScrollPane) 155 getScrollbarVisibility (Methode der Klasse TextArea) 62 getScrollPosition (Methode der Klasse ScrollPane) 156 getSelectedCheckbox (Methode der Klasse CheckboxGroup) 102 getSelectedObjects (Methode der Klasse Checkbox) 89 getShearInstance (Methode der Klasse AffineTransform) 515 getSize() 188 getSource (Methode der Klasse ActionEvent) 43, 55 getSource(), Methode 321 getState (Methode der Klasse Checkbox) 89, 91, 97 getString(), Methode 478 Getter-Methode 577 getText (Methode der Klasse Label) 70 getText (Methode der Klasse TextField) 26, 75 getText(), Methode 366 getThreadGroup(), Methode 419 getUnitIncrement (Methode der Klasse Scrollbar) 134 getUpdateCount(), Methode 470-471 getVAdjustable (Methode der Klasse ScrollPane) 156 getValue (Methode der Klasse Scrollbar) 134, 139 getValue(), Methode 335, 349 getViewportSize (Methode der Klasse ScrollPane) 156 getVisible (Methode der Klasse Scrollbar) 134 getVisibleAmount (Methode der Klasse Scrollbar) 134 getVScrollbarWidth (Methode der Klasse ScrollPane) 156 getXXX() 575 GIF 182 GIF89a 182 glitzyProperty 592 globale Klassenvariablen 26-27 GradientLab (Beispielprogramm) 509 Listing 510
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
GradientPaint (Klasse), Konstruktoren 509 Graphics (Klasse) 11, 497 Graphics2D (Klasse) 497-498 Methoden 498 GridBagLayout, Layoutmanager 354 GridLayout-Manager 80-81, 113, 121 installieren 82 verwenden 81 Groß- und Kleinschreibung bei Dateinamen 4 bei Namen von Webseiten 7 Gruppen 68 Gruppen von Steuerelementen 100 Gruppierung von Komponenten 324-325 GUI 559 visuelle Aspekte 496 GUI-Ereignisse 320
H hashCode (Methode der Klasse String) 47 HashMap 255 HashSet 255 Hashtabellen 255 , HTML 181 -Tag 17 HEIGHT (HTML-SchlEsselwort) 19 hello-Applet 2 -Tag 18 HTML (HyperText Markup Language) 16, 180, 181, 185, -Tag 17 HTML-Dokumentation 175
I , HTML 180 ICC (International Color Consortium) 497 Icon, Schnittstelle 381, 386 IDL 192, 492 if-Anweisung 44 IllegalArgumentException, Exception 444 IllegalMonitorStateException, Exception 437 Implementieren, Schnittstellen 40
implements (SchlEsselwort) 63 import-Anweisung 9 IndexColorModel 497 indexed properties 580, 581 indexOf (Methode der Klasse String) 47 indizierte Eigenschaften 580 init (Methode) 27 init() 187 Initialisieren, Applet 27 initialValue(), Methode 449 InputStream 261, 290 insert (Methode der Klasse TextArea) 62, 64 insertText (Methode der Klasse TextArea) 62 Installieren des Java JDK 4 Integer (Klasse) 75 interface 212 interfacing 211 interleaved 627 intern (Methode der Klasse String) 47 Internationalisierungstechniken 50 interne Klassen 499 interrupt(), Methode 413 InterruptedException, Exception 413 IntTextField.java, Beispielprogramm 368 IOException 222 isAlive(), Methode 418-419 isDaemon(), Methode 419 isInstanceOf() 571 Item-Ereignisse, Kontrollk6stchen 89 ItemEvent, Ereignis 389 ItemEvent (Klasse) 94, 106 ItemListener (Schnittstelle) 91, 93, 105, 122 itemStateChanged (Methode der Schnittstelle ItemListener) 93-94, 105-106, 123
J jar jarsigner java Kommandozeilenoptionen Java 1.0, Ereignisbehandlung Java 2, Ereignisbehandlung Java Database Connectivity
165 165 164 173 40 40 455
Java Foundation Classes 320, 376 Java IDL 166 Java Interface Definition Language 492 Java Language Specification 560 Java Runtime Environment 191 Java Virtual Machine Specification 560 Java-Anwendungen 479 Sicherheit 480 Java-Applets 479 Ausfhrungsmodell 479 Einsatzm(glichkeiten 479 Nachteile 480 Online-Hilfe 479 Sicherheit 480 Versionskontrolle 479 Vorteile 479 Java-Archive 192 Java-Bibliotheken 8 Java-Code ausfhren mit Webbrowser 6 bearbeiten 3 Dateiformat 3 Java-Compiler 6 Java-Dokumentation 5-5 Java-Ereignisse, Definition 40 Java-f6hige Browser 19 Java-Interpreter 479 Java-Klassen, Konzept 10 Java-Layout 68 FlowLayout 79-80 GridLayout 80 Standardlayout 79 Java-Objekte 9 Java-Pakete 11 Java-Vererbung, Konzept 12 Java-Zugriffsmodifizierer 13 java.applet 246, 283 java.applet.Applet 283, 553 java.awt 246, 265 java.awt (Paket) 11 java.awt.Button 563 java.awt.color 283, 497 java.awt.Color (Klasse) 508 java.awt.datatransfer 284 java.awt.dnd 284 java.awt.event 284 Package 321 java.awt.event (Paket) 41 java.awt.font 283, 496 java.awt.geom 283 java.awt.geom (Paket) 499
633
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
java.awt.geom.AffineTransform (Klasse) 515 java.awt.geom.GeneralPath (Klasse) 519 java.awt.GradientPaint (Klasse) 508 java.awt.Graphics (Klasse) 498 java.awt.Graphics2D (Klasse) 498 java.awt.im 284 java.awt.image 284 java.awt.peer 284 java.awt.print 284 java.awt.swing, Package 377 java.awt.TexturePaint (Klasse) 508 java.beans 284, 569 java.beans.beancontext 284 java.beans.PropertyVetoException 601 java.io 246, 259, 288, 294 java.lang 164, 245-246, 248-249 Package 407-408 java.lang.ref 284 java.lang.reflect 284 java.math 284 java.net 246, 281 java.rmi 285 java.rmi.activation 285 java.rmi.dgc 285 java.rmi.registry 285 java.rmi.server 285 java.security 285 java.security.acl 285 java.security.cert 285 java.security.interfaces 285 java.security.spec 285 java.sql 285 java.swing.plaf.* 276 java.text 258, 285 java.util 246, 253 java.util.mime 285 java:, Profiler 173 JavaBeans 552-559, 569, 574, 576 javac 164, 171-172 javadoc 165, 175, 190 javah 165, 177, 190 javap 165, 178 JavaScript 581-582 javax.servlet 285 javax.swing 246 javax.swing.accessibility 283 javax.swing.border 276 javax.swing.event 276 javax.swing.table 276 javax.swing.text 277 javax.swing.tree 277
634
javax.swing.undo 277 JButton 277 Klasse 377, 385, 387 Jcheckbox 277 Klasse 389 JCheckBoxMenuItem 277 Klasse 379 JColorChooser 277 JComboBox 278 Klasse 390 jdb 165, 177 JDBC 285, 455 API 458 JDBC-ODBC-BrEcke 460 JDBC-URL Network Naming Service 462 Portangabe 462 reservierte Namen 463 Syntax 462 Ziele 461 jdbc.drivers, Java-Eigenschaft 466 JDBCSelect 568 JDesktop 278 JDesktopIcon 278 JDesktopPane 278 JDialog 278 JDK 163-164, 167, 191 Homepage im Internet 5 Installationshinweise im Internet 5 installieren 5 Installieren der Dokumentation 5 PATH-Umgebungsvariable festlegen 5 Standardklassen 164 JDK 1.1, Grafikmodell 496-497, 504 JDK:, Macintosh 167, 168 JEditorPane 278 JellyBean 566 JFC 320, 376 JFC-Klassen 376 JFileChooser 278 Jframe 278 Klasse 376, 378 JInternalFrame 278 JLabel 277 Klasse 385 JLayeredPane 278 JList 278 JMenu 277 JMenuBar 277 JMenuItem 277 Klasse 379
join(), Methode
408, 413-414, 417, 436 JOptionPane 278 JPanel 277 JPasswordField 278 Klasse 393 JPEG 182 JpopupMenu 277 JProgressBar 278 JRadioButton 277 Klasse 390 JRadioButtonMenuItem 277 jre 164, 191 JScrollBar 278 JScrollPane 278 JSDK 166 JSeparator 277 JSlider 278 Klasse 392 JSplitPane 278 JTabbedPane 278 Klasse 379 JTable 278 JTextArea 278 JTextComponent 278 JTextField 278 Klasse 376-377, 393 JTextPane 278 JToggleButton 277 JToolBar 278 Klasse 394 JToolTip 278 JTree 278 Juggler 563 JViewPort 278 JVM (Java Virtual Machine) 6 JVM-Klassenlader 7 JWindow 278
K KeyEvent, Klasse keyPressed(), Methode keytool Kippschalter, hinzufEgen Klasse Applet definieren Definition von Throwable Klasse AbstractAction Klasse Authenticator
321 321 165, 192 384 160 10 201 226 280 283
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
Klasse Beans 570 Klasse BitSet 258 Klasse BorderFactory 280 Klasse BorderLayout 269 Klasse BoxLayout 279 Klasse BufferedInputStream 301 Klasse BufferedOutputStream 302 Klasse BufferedReader 302 Klasse BufferedWriter 302 Klasse Button 266 Klasse ByteArrayInputStream 296-297 Klasse ByteArrayOutputStream 296-297 Klasse CardLayout 269 Klasse CharArrayReader 296 Klasse CharArrayWriter 296 Klasse Checkbox 266 Klasse CheckboxGroup 266 Klasse Choice 266 Klasse Color 272 Klasse Component 266 Klasse ComponentOrientation 275 Klasse Container 268 Klasse Cursor 275 Klasse DataInputStream 303 Klasse DataOutputStream 305 Klasse Date 257 Klasse Dialog 268 Klasse FileDialog 268 Klasse FileInputStream 288, 294 Klasse FileOutputStream 295 Klasse FileReader 295 Klasse FileWriter 296 Klasse FlowLayout 269 Klasse Font 272 Klasse FontMetrics 272 Klasse Frame 268 Klasse GradientPaint 273 Klasse GrayFilter 281 Klasse GridBagLayout 269 Klasse GridLayout 269 Klasse Image 272 Klasse ImageIcon 280 Klasse InetAddress 282 Klasse InputStream 260, 290 Klasse InputStreamReader 313 Klasse Insets 269 Klasse KeyStroke 280 Klasse LineNumberInputStream 307 Klasse LineNumberReader 306 Klasse Locale 257 Klasse LookAndFeel 280 Klasse Math 249
Klasse MediaTracker 275 Klasse Menu 270 Klasse MenuBar 270 Klasse MenuComponent 270 Klasse MenuShortcut 270 Klasse Observable 258 Klasse OutputStream 261, 291 Klasse OutputStreamWriter 313 Klasse OverlayLayout 279 Klasse Panel 268 Klasse PipedInputStream 296, 299 Klasse PipedOutputStream 296, 299 Klasse PipedReader 296 Klasse PipedWriter 296 Klasse Point 274 Klasse PopupMenu 270 Klasse PrintJob 275 Klasse PrintStream 307 Klasse PrintWriter 308 Klasse RandomAccessFile 263, 314 Klasse Reader 262, 290, 292 Klasse RenderingHints 273 Klasse ScrollPane 268 Klasse ScrollPaneLayout 279 Klasse SequenceInputStream 312 Klasse Server 282 Klasse ServerSocket 282 Klasse SizeRequirement 279 Klasse StreamTokenizer 263, 315 Klasse StringReader 296, 298 Klasse StringWriter 296, 298 Klasse SwingUtilities 281 Klasse System 252 Klasse SystemColor 272 Klasse TextArea 267 Klasse TextComponent 267 Klasse TextField 267 Klasse TexturePaint 273 Klasse Thread 250 Klasse ThreadGroup 251 Klasse Throwable 252 Klasse Timer 281 Klasse Toolkit 275 Klasse URL 282 Klasse ViewportLayout 279 Klasse Writer 262, 290, 292-293 Klassen 172 ableiten 12 Dimension 274 einbinden 11 innere 386-387 Polygon 274 Reader 292 Rectangle 274
Thread 250 ThreadGroup 250 Klassenbibliotheken 11 Klickereignisse, Identit6t des Steuerelements ermitteln 55 Kodierregeln 15 Kombinationsfelder hinzufEgen 390 Kommentare in HTML-Seiten 17 Kommentare in Java 32 Kommunikationsprotokolle 456 Kompilieren von Java-Code 6 Komponenten benutzerdefinierte 320 eigene entwickeln 320 Komponentenentwicklung Aussehen *ndern 329, 348 Design 326 Designberlegungen 327-329, 346-347, 364 Ereignisse behandeln 334, 350, 366 Ereignistypen entwickeln 335 Gltigkeitsprfungen 364, 370 Gr(ßen*nderungen 338, 353 Hintergrundfarbe 330 IntTextField 364 Multithread-Verhalten 337, 353 Polar 327 Schriftart 330 Strategien 324, 326, 329, 347 ThreeWay 345 ValidatingTextField 370 Vektoren klonen 337-338, 353 Vordergrundfarbe 330 Werte abrufen 331-332, 349, 365 Werte beschr*nken 330, 348, 365 Werte setzen 331-332, 349, 365 Werte speichern 331, 349, 365 Komponentenmodell 552 Konstruktor 213-215 Konstruktoren Definition 29 Label-Steuerelement 70 Kontrollfelder, hinzufEgen 384, 387 Kontrollk6stchen 68, 87 beschriften 90 deklarieren 87 Ereignisbehandlung 92-93 erzeugen 88 hinzufgen 90 identifizieren 94 Status bestimmen 89
635
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
Status ermitteln 91, 97 Status festlegen 90 verwenden 67 Kontrollk6stchen-Gruppe 101 Koordinatensystem 15, 500, 515 normalisieren 536 transformieren 532 Koordinatentransformationen 515 Koordinieren, Steuerelemente 68 Kurven 2. Ordnung 501 3. Ordnung 501 Bzier-Kurven 524 selbstdefinierte 499, 519 Sttzpunkte 501
Methoden 520 Linienattribute 504 LinkedList 256 List 266 Listener 583, 599, 601-602, 614 Listener-Objekte 41 verknpfen mit Applets 41 Local Area Network 456 Locale (Klasse) 50 Locale.FRENCH (Konstante) 50 Locale.GERMAN (Konstante) 50 LocalThreadVars.java, Beispielprogramm 449 Logarithmus 250 Lokalisierung, mit der Klasse Locale 50 long 620
L Label 266 Label (Klasse) 69 Konstanten 70 Konstruktoren 69-70, 83 Methoden 69 Label-Steuerelemente 69 als Alternative zum Textfeld 23 als Platzhalter 81 ausrichten 70 deklarieren 71 erzeugen 72 hinzufgen 72 Text ausrichten 70-70 Text zentrieren 83 Verwendungszweck 73 Label.CENTER (Konstante) 70, 83 Label.LEFT (Konstante) 70 Label.RIGHT (Konstante) 70 Labels, hinzufEgen 384 lastIndexOf (Methode der Klasse String) 48 Laufzeitumgebung 191 layout (Methode der Klasse ScrollPane) 156 Layoutmanager 68, 327, 354 length (Methode der Klasse String) 48 Leser 259 Lightweight Process 406 Line2D (Klasse) 499-500 LineNumberedInputStream 260 LineNumberInputStream 307 lineTo (Methode der Klasse GeneralPath) 521
636
M main() 170 Methode 410, 418, 433 Makros fEr Datenbanken 456 mango.utilities.Bubble 244 Maschinensprache 6 Math, Klasse 331 mathematische Funktionen 249 Maximalfunktion 250 MAX_VALUE (Konstante der Klasse Integer) 76 mehrfache Vererbung 245 Mehrfachvererbung, implementieren 41 MenEs hinzufEgen 377 MenuItem, Klasse 379 Methoden 201 Definition 13 rekursive 535 Methodenaufruf, Syntax 32 MethodTest.java, Beispielprogramm 414 Middleware 459 MIME 281, 285 Minimalfunktion 250 minimumSize (Methode der Klasse TextArea) 62 minimumSize (Methode der Klasse TextField) 25 MIN_VALUE (Konstante der Klasse Integer) 76 @missbiligtes Tag 192 Molecule 567
Monitormodell 427 MouseListener, Schnittstelle 321 MouseMotionListener, Schnittstelle 321 move (Methode der Klasse GeneralPath), Methoden 520 moveTo (Methode der Klasse GeneralPath) 521, 524 Multithread 556 Multithread-Umgebungen 337, 353 Datenverf*lschung 337 Multithreading 557, 616, 623, 626 =berblick 406 Vorteile 406
N Namensgebung 576 native2ascii 165 Network Naming Service 462 Network Naming System 462 new, Anweisung 410-411, 416, 418 new-Operator 28 verwenden 28 Normalisierung 536 notify(), Methode 413-414, 417, 436-437, 440 notifyAll(), Methode 417, 436 NoWaitMonitor, Klasse 437 NoWaitPandC.java, Beispielprogramm 437 NullPointerException 227 nummerische Datentypen 27
O Obergrenze Object Request Broker Objektdatenbanken Objekte als Ereignisempf*nger registrieren Konzept Objekte und Klassen objektorientierte Programmierung ODBC ODBC-Treiber ODMG OOP
250 492 492
321 9 9 9, 196 460 490 492 196
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
OOP (Objektorientierte Programmierung) 9 Open Database Connectivity 460 Optionfelder Optionsfelder 68, 98, 99 bestimmen der Startauswahl 104 Ereignisbehandlung 123 gruppieren 103 gruppieren in Panels 110 Optionsfelder und Kontrollk6stchen 100 kombinieren 116 Unterschied 100 Optionsfeldergruppen hinzufEgen 387 OrangeButton 562 ORB 492 OurButton 562 OutOfMemoryError 226 OutputStream 290
P
, HTML 180 Packages 11 paint (Methode der Klasse Applet) 13 Paint (Schnittstelle) 508 paint(), Methode 332 paint(Graphics g) 187 paintIcon(), Methode 381 PandC.java, Beispielprogramm 441 Panel erstellen 110 Komponente 354 Panel (Klasse) 109 Panel-Objekte 109 185-186 PARAM (HTML-SchlEsselwort) 19 paramString (Methode der Klasse Button) 39 paramString (Methode der Klasse Checkbox) 89 paramString (Methode der Klasse Label) 70 paramString (Methode der Klasse Scrollbar) 134 paramString (Methode der Klasse ScrollPane) 156 paramString (Methode der Klasse TextArea) 62
paramString (Methode der Klasse TextField) 25 parseInt (Methode der Klasse Integer) 76 parseLong (Methode der Klasse Integer) 76 parseNumbers (Methode der Klasse Integer) 76 Pascal 196 PasswordAuthentication 283 Passwortfelder, hinzufEgen 393 Pfade transformieren 521 verallgemeinerte 519 Pi 250 PipedInputStream 299 Platzieren, Steuerelemente 68 Polar.java, Beispielprogramm 339 Polarkoordinaten 327 PolarTest.html, Testprogramm 344 PolarTest.java, Testprogramm 344 policytool 165 Poly (Beispielprogramm), Listing 523 Polygone, zeichnen 521 polymorphe Funktionen 208-209 Potenzierung 250 preferredSize (Methode der Klasse TextArea) 62 preferredSize (Methode der Klasse TextField) 25 prepareCall(), Methode 468 PreparedStatement Objektinstanz 468 Schnittstelle 471 printAllThreadInfo(), Methode 420 printComponents (Methode der Klasse ScrollPane) 156 PrintGraphics 271 println 622 println(), Methode 430 printStackTrace() 234 printStackTrace(PrintStream s) 234 PrintStream, Objekt 466 PriorityTest.java, Beispielprogramm 445 private (SchlEsselwort) 27 private-Deklaration 13 processActionEvent (Methode der Klasse Button) 39 processActionEvent (Methode der Klasse TextField) 26 processActionEvent(), Methode 324, 367
processAdjustmentEvent (Methode der Klasse Scrollbar) 134 processEvent (Methode der Klasse Checkbox) 89 processEvent (Methode der Klasse Scrollbar) 134 processEvent (Methode der Klasse TextField) 26 processItemEvent (Methode der Klasse Checkbox) 90 processKeyEvent(), Methode 324 ProgressMonitor 280 ProgressMonitorInputStream 280 properties 555, 574 Klasse 463 Properties(info), Objekt 465 PropertyChangeDemo 584 PropertyChangeEvent 583 PropertyChangeListener 583 PropertyChangeSupport 590 PropertyChangeSupport. firePropertyChange() 606 PropertySheet 561 PropertyVetoException 602 propriet6re Algorithmen 161 protected (SchlEsselwort) 27 protected Finalizer 217 protected-Deklaration 13 Pseudozufallszahlen 250 public (SchlEsselwort) 27 public-Deklaration 13 Punktoperator 14, 32, 123
Q QuadCurve2D (Klasse) Quadratwurzel Quellcode QuoteMonitor
499-500 250 186 569
R race conditions 616, 619, 623 Radios-Applet 101 Listing 107 random() 250 Rasterlayout 84 RDBMS 455 Rechteck, abgerundetes 502 Rectangle2D (Klasse) 499-500
637
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
regionmatches (Methode der Klasse String) 48-48 Registerseiten, hinzufEgen 379 Rekursion 535 Relational Database Management Systems 455 Remote Method Invocation 491, 569 Remote Procedure Calls 491 RemoveActionListener (Methode der Klasse Button) 39 RemoveActionListener (Methode der Klasse TextField) 26 removeAdjustmentListener (Methode der Klasse Scrollbar) 134 removeItemListener (Methode der Klasse Checkbox) 90 repaint(), Methode 330, 336 replace (Methode der Klasse String) 48 replaceRange (Methode der Klasse TextArea) 62 replaceText (Methode der Klasse TextArea) 62 resize (Methode der Klasse Applet) 18 Ressourcenkosten, einsparen 454 ResultSet Objekt 468, 470 Objektreferenz 469 Schnittstelle 461, 468, 475 Schnittstellenmethoden 476-477 ResultSetMetaData, Schnittstelle 477 resume(), Methode 413-414, 417-418, 436 RMI 193, 491, 569 rmic 165 rmid 165 rmiregistry 165 rollback(), Methode 468-469 rotate (Methode der Klasse Graphics2D) 498 RoundRectangle2D (Klasse)499-500 RPC 491 REckgabetyp einer Methode 14 run(), Methode 407-408, 410-411, 413, 416-417 Runnable, Schnittstelle 410-411 RunnableThread.java, Beispielprogramm 411 Runtime Exception 227 RuntimeException, Exception 437
638
S Sandwich-Applet 116 Listing 127 scale (Methode der Klasse Graphics2D) 498 Schaltfl6chen 36 beschriften 39 deklarieren 38 hinzufgen 38, 384-385, 387 Identit*t ermitteln 43, 52 in Applets 36 mehrere handhaben 51 verwenden 35-36 Schaltfl6chenereignisse 42 Scheduler 413, 416 Schieberegler hinzufEgen 392 Schnittstelle Action 280 Schnittstelle Comparable 256-257 Schnittstelle Comparator 257 Schnittstelle Composite 273 Schnittstelle Iterator 256 Schnittstelle Observer 258 Schnittstelle Shape 274 Schnittstelle Stroke 273 Schnittstellen 211 als Mittel zur Programmstrukturierung 41 implementieren 40, 321 Schnittstellenbildung 208, 211 Schnittstellenebenen Anwendungsebene 460 Treiberebene 460 Schnittstellenereignisse 40 Schnittstellenmethoden 322 Schreiber 259 Schriftarten in Java 496 Scriptumgebungen 581 Scrollbar 267 Klasse 348, 353, 390, 392 Scrollbar (Klasse) 133 Konstruktoren 133 Methoden 133 Scrollbar.HORIZONTAL (Konstante) 133 Scrollbar.VERTICAL (Konstante) 133 Scrollborder-Applet 144 Listing 151 Scroller-Applet 132 Listing 142 Scrollpane (Klasse) 154 Konstruktoren 155 Methoden 155
Scrpane-Applet 154 Listing 157 SecurityException, Exception 409 serialver 165 Server-Technologie 456 servletrunner 166 Servlets 160, 166, 193 set(), Methode 440, 449 setActionCommand (Methode der Klasse Button) 39 setAlignment (Methode der Klasse Label) 70 setBackground(), Methode 330, 348, 364 setBlockIncrement (Methode der Klasse Scrollbar) 134 setCheckboxGroup (Methode der Klasse Checkbox) 90 setColumns (Methode der Klasse TextArea) 63 setColumns (Methode der Klasse TextField) 26 setCurrent (Methode der Klasse CheckboxGroup) 102 setDaemon(), Methode 451 setDragColor(), Methode 330 setEchoChar (Methode der Klasse TextField) 26 setEchoChar(), Methode 393 setEchoCharacter (Methode der Klasse TextField) 26 setEditable (Methode der Klasse TextField) 23 setFont(), Methode 330, 348, 364 setForeground(), Methode 330, 348, 364 setLabel (Methode der Klasse Button) 39 setLabel (Methode der Klasse Checkbox) 90 setLayout (Methode der Klasse ScrollPane) 83, 156 setLineIncrement (Methode der Klasse Scrollbar) 134 SetLocation (Methode), synchronisieren 151 setLocation() 274 setMajorTickSpacing(), Methode392 setMaximum (Methode der Klasse Scrollbar) 134 setMaximumRowCount(), Methode 391 setMaxPriority(), Methode 444
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
setMinimum (Methode der Klasse Scrollbar) 134 setMinorTickSpacing(), Methode392 setOrientation (Methode der Klasse Scrollbar) 135 setPageIncrement (Methode der Klasse Scrollbar) 135 setPaint (Methode der Klasse Graphics2D) 498 Fllung 508 setPaintTicks(), Methode 392 setPriority(), Methode 444 setRendering (Methode der Klasse Graphics2D) 498 setRows (Methode der Klasse TextArea) 63 setScrollPosition (Methode der Klasse ScrollPane) 156 setSelectedCheckbox (Methode der Klasse CheckboxGroup) 102 setShowText(), Methode 330 setSize(), Methode 353 setState (Methode der Klasse Checkbox) 90, 125 setStroke (Methode der Klasse Graphics2D) 498, 504 Setter 601 Setter-Methode 577 setText (Methode der Klasse Label) 70 setText (Methode der Klasse TextField) 26, 75, 94 setText(), Methode 365 setTransform (Methode der Klasse Graphics2D) 515 setType, Methoden 472, 474 setUnitIncrement (Methode der Klasse Scrollbar) 135 setValue (Methode der Klasse Scrollbar) 135-136, 139 setValues (Methode der Klasse Scrollbar) 135-136 setVisibleAmount (Methode der Klasse Scrollbar) 135 setXXX() 575 Shape (Schnittstelle) 497-498 Implementierung 498 ShapeSampler (Beispielprogramm) 502 Listing 502 shear (Methode der Klasse Graphics2D) 498 showElapsedTime(), Methode 407 Sicherheitsrichtlinien 192
single-threaded 406 size() 188 sleep(), Methode 413-414, 417, 444 Smalltalk 247 Socket 282, 456 sosoft.utils.Bubble 244 Speicherplatzreservierung 28 Speicherverwaltung mit dem new-Operator 28 SQL 455 SQLException, Exception 463 StackOverflowErrror 226 Standard-Layoutmanager 68, 72, 80 Listing 79 Standarddatentypen 10 Standardtastenkombinationen, in Textfeldern 34 start() 187 Methode 408, 410-411, 413, 416 startsWith (Methode der Klasse String) 48 Statement Objekt 468 Objektinstanz 468 Schnittstelle 461, 468, 470 Schnittstellenmethoden 470 Steuerelemente 22 beschriften 73 erzeugen 28 gruppieren in Panels 110 in Rasterform anordnen 81 koordinieren 68 platzieren 68 positionieren 151 Verwendung in Applets und Programmen 22 stop() 187 Methode 413, 417-418 Stored Procedures 456, 468 Stored-Procedures aufrufen 474 String 249 Klasse 249 String (Klasse) 45, 77 Konstruktoren 45-46 Methoden 45 StringBuffer 249 Klasse 249 StringBufferInputStream 260 StringIndexOutOfBoundsException 227 StringReader 260 StrIme 259, 288, 290 StrokeLab (Beispielprogramm) 505 Listing 505
Structured Query Language 455 StuffContainer 574 substring (Methode der Klasse String) 48 sun.server.util, Package 449 suspend(), Methode 413, 417-418, 436, 444 Swing Set 376 Swing-Komponenten 376 Beispielprogramm 376 SwingDemo, Beispielprogramm376, 396 Symantec CafH 177 Symbole hinzufEgen 381 Symbolleisten hinzufEgen 394 synchronized 620-621 Schlsselwort 415, 427 SyncTest.java, Beispielprogramm 433 System, Klasse 407-408
T TabIcon, Klasse 381 Tags 17 TCP 281 TCP/IP 281 Text anzeigen mit Label-Steuerelement 73 anzeigen mit Textfeld 23 einfgen mit der Methode insert() 64 text-Applet 24 Listing 33 TextArea (Klasse) 60 Konstruktoren 61 Methoden 61 Textbereich, erzeugen 60 Textbereiche 59 Textfelder 21 Auslesen nummerischer Daten 75 Breite festlegen 29 deklarieren 23, 24 einfgen 23 hinzufgen 30 initialisieren 30 mit Schreibschutz 23 Text einfgen mit setText() 31 TextField (Klasse) 24, 364 Konstruktoren 29
639
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
Methoden 24 TexturePaint (Klasse), Konstruktor 508 Texturmuster 508 Thin Clients 454 this 215 this (SchlEsselwort) 42 Thread-Gruppen 418 Informationen ermitteln 419 Priorit*ten 444 Thread-Methoden 251 ThreadGroup, Klasse 418, 444 ThreadInfo.java, Beispielprogramm 420 Threads 298, 557, 622 ausfhrbare 416 ausfhren 410, 416 blockierte 416-417 Daemon451 Deadlocks 412-413, 427, 436 Dienst451 erzeugen 410-411, 416 gemeinsam genutzte Daten 436 gleichzeitige 406 Gruppen 418 in Multithread-Umgebungen 337, 353 Informationen ermitteln 419-420 initialisieren 416 Klasse 408, 410, 412, 418, 433, 444 klassenbasierte Synchronisierung 433 Kommunikation 436 Lebensdauer 416 lokale Variablen 449 Monitore einsetzen 427 neu erzeugte 416 objektbasierte Synchronisierung 433 parallele 406 preemptive Rechenzeitzuteilung 444-445 Priorit*ten 443-445, 448 starten 410 Steuerung 412 Steuerungsmethoden 436 synchronisieren 423, 427 Synchronisierungstechniken433 tote 413, 416-417 Variablen gemeinsam nutzen 451
640
veraltete Methoden 413 wartende 436 Zeitscheibenverfahren 444 Zuteilung von Rechenzeit 443 THREADS_FLAG, Umgebungsvariable 445 ThreeWay.html, Testprogramm 363 ThreeWay.java, Beispielprogramm 356 ThreeWayTest.java, Testprogramm 363 throw 235 throws 236 Klausel 413 TickTock 564 <TITLE>, HTML 181 -Tag 17 tnameserv 166 toCharArray (Methode der Klasse String) 49 Token 263 toLowerCase (Methode der Klasse String) 49 ToolBox 561-562 ToolTipManager 280 toString (Methode der Klasse CheckboxGroup) 102 toString (Methode der Klasse String) 49, 102 toString() 234 toUpperCase (Methode der Klasse String) 49 transform (Methode der Klasse GeneralPath) 521 transform (Methode der Klasse Graphics2D) 498 Transformationen affine 515, 521 Pfade 521 Rotation 515 Scherung 515 Skalierung 515 Translation 515 wiederholte 528 TransformLab (Beispielprogramm) 516 Listing 518 TransitionalBean 569 translate (Methode der Klasse Graphics2D) 498 TreeMap 256 TreeSet 256 Treiber 459, 488 JDBC-ODBC-Brcken 488, 490
Klassennamen definieren 466 native Bibliothek-zuJava-Implementierung 489 native Protokoll-Java 489 Netzwerkprotokoll-Java 489 registrieren 465-466 Registrierung aufheben 465 Trigger 457 trigonometrische Funktionen 250 trim (Methode der Klasse String) 49 try 229 try-catch, Anweisung 413 try-catch-finally-Konstrukt 231 txtarea-Applet 60 Listing 65
U Sberladen 208-209, 214 Unterschied zu =berschreiben 30 Sberladen von Java-Methoden 30 Sberschreiben 12 Unterschied zu =berladen 30 UDP 281-282 UDP/IP 281 Umwandeln Double-Wert in Text 78 Float-Wert in Text 78 Integer in Text 77 Long-Wert in Text 78 Text in Gleitkommawert 76 Text in Zahlen 75 Untergrenze 250 Unterklassen von Standardkomponenten ableiten 325-326, 364 update(), Methode 330 URL 281 User Datagram Protokol 282 UTF 304
V ValTextFieldTest.html, Testprogramm 374 ValTextFieldTest.java, Beispielprogramm 372 valueOf (Methode der Klasse String) 49-50, 77-78
H:/Sybex/Java_2_Buch/IndexDB.3d from 3.1.2001 Page size: 168,00 x 240,00 mm
Index
Variablen 26, 196 deklarieren 26, 77 deklarieren in Codebl(cken 77 Namensvergabe 338 Vector, Klasse 338 Vererbung 12, 208, 244 Vererbungshierarchie 244 Verkapseln 10 vetoableChange() 602, 615 VetoableChangeListener 609 vordefinierte Klassen 11 Voter 566
W wait(), Methode
413-414, 417, 436-437, 440, 444 161
Webbrowser Webbrowser mit Java-UnterstEtzung 7 Webseite, Einbetten von Applets 16
Werte als Ganzzahl setzen 365 als String setzen 365 in Komponenten anzeigen 327, 346 neue festlegen 328, 347 while-Schleife 316, 417 Wide Area Network 456 Widgets 266 WIDTH(HTML-SchlEsselwort) 19 Windows 3.1x 167 WithoutTread.java, Beispielprogramm 407 WithThread.java, Beispielprogramm 409
X
Y yield(), Methode 414, 416, 444-445, 447-448
Z Zeichenoperationen Clipping Fllung Transformationen Zeichnen, Linien Zeitdifferenzen ausgeben Zeitscheibenverfahren Zugriffsmodifizierer zweidimensionale Darstellung
X/Open SQL Command Level Interface 460, 490
641
513 508 515 504 407 444 13 496