Frank Koch, M.B.A., Dipl.-Inf. [email protected] Frank Koch 1 Inhaltsverzeichnis 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 2 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3 3.1 3.2 3.3 3.4 3.5 3.6 4 4.1 4.2 4.3 4.4 4.5 5 5.1 5.2 5.3 5.4 6 7 7.1 7.2 7.3 7.4 7.5 7.6 EINLEITUNG Administration Einführung Entwicklung von Java Ziele von Java Java Architektur Java Security Java Applications versus Applets Java Entwicklungsumgebung Java Syntax Unterschiede zwischen Java und C++ Struktur von Applets und Applications Kommentare Variablen Operatoren Kontrollstrukturen Arrays Objektorientierung Einleitung Klassen und Objekte Wiederverwendung Finale Klassen Abstrakte Klassen Object Wrappers Sprachkonzepte Literale Parameter Operatoren Objektorientierung Befehlszeilenargumente Exception Handling Einführung Exception Syntax Checked Exceptions Unchecked Exceptions Interfaces Threads Einführung Erzeugen von Threads Ein Beispiel für Threads Synchronisation von Threads Kommunikation zwischen Threads Interfaces Frank Koch 8 8.1 8.2 9 9.1 9.2 9.3 9.4 9.5 9.6 10 10.1 10.2 10.3 10.4 10.5 11 11.1 11.2 11.3 12 12.1 12.2 12.3 13 13.1 13.2 13.3 14 15 15.1 15.2 15.3 16 16.1 16.2 16.3 17 Java API: Die Standard Java Packages Packages Java Core Packages User Interface Einführung Container und Layouts Menüs Kontrollelemente The Java Event Model Interne Klassen / Nested Classes Applet-Programmierung Einführung Kontrollmethoden Events Übung Applets und Threads Input/Output Klassenübersicht System.in und System.out File I/O Kommunikation über das Internet Zugriff auf eine URL Client/Server Programmierung mit Sockets POP3-MailClient JDBC JDBC – Datenbankzugriff in Java JDBC – Anwendungsbeispiel JDBC – Übung CGI Servlets Sinn und Zweck Installation Servlet-Demonstrationen JavaScript Positionierung Beispiel Bedeutung für Java Javadoc 2 Java Literaturempfehlung Java in 21 Tagen • Laura Lemay, Rogers Cadenhead • Markt & Technik Buch und Softwareverlag • ISBN 382726281X • erschienen am 15. November 2001 • 864 Seiten plus CD mit J2SE und HTMLBuchtext • EUR 44,95 Weitere Empfehlungen: • The Java Tutorial: Object-Oriented Programming for the Internet, Mary Campione and Kathy Walrath (Dieses Buch brauchen Sie nicht kaufen. Es steht Ihnen komplett auf dem Internet (java.sun.com) zur Verfügung. • The Java Programming Language, Ken Arnold, James Gosling, Addison Wesley, ISBN-0-201-63455-4 • Java in a Nutshell, David Flanagan, 39 DEM, O'Reilly & Associates, Inc., ISBN 3-930673-46-0 • Java bis ins Detail, G.Cornell, C.S. Horstmann, HeiseVerlag, ISBN 3-88229-087-0 • Instant Java,I.A. Pew, Heise-Verlag, ISBN 3-88229-084-6 • Java pur, P.v.d. Linden, Heise-Verlag, ISBN 3-88229-086-7 • Java Primer Plus, Paul Tymon, 39.99 USD, Wait Group Press, ISBN 1-57169-062-x • Programmieren in Java, Brian Stark, Franzis Verlag, ISBN 37723-4432-1 Frank Koch 3 Java Online Quellen JAVA Standardwerke • http://java.sun.com/nav/read/whitepapers.html Die White Papers. Die Entwicklungs- und Hintergrunddokumentationen der Javaentwickler • http://java.sun.com/doc/api_documentation.html Die Java Klassenbibliothek von SUN Microsystems. Ein Listing aller im JDK zur Verfügung stehenden Klassen • http://java.sun.com/nav/read/tutorial.html Das Java Tutorial von SUN. Eine sehr ausführliche Dokumentation für alle Lebenslagen. Datei kann als ZIP-file (Größe ca.1,7 MB) geladen werden. Zum Entkomprimieren benötigen Sie einen Entpacker, der lange Dateinamen berücksichtigt (z.B. WinZip). • http://java.sun.com/doc/language_specification.html The Java Language Specification. Eine Dokumentation der Programmiersprache Java Java. • http://java.sun.com/doc/language_vm_specification.html The Java Virtual Machine Specification. Beschreibung der Java VM und deren Befehlssatzes • http://java.sun.com/products/JDK/debugging/index.html The The Java Language Debugging. Anleitung zur Verwendung des Java Debuggers (JDB) Interessante Java Seiten • http://www.java.de/ Java User Group Deutschland. Artikel und Links, sowie Aktuelles zum Thema • http://acc.de/java Kaffee & Kuchen. Artikel und Links, sowie Aktuelles zum Thema • http://www.javaworld.com/ Javaworld. Eine monatliche Zeitschrift, die nur im Internet erscheint. Artikel rund um Java und andere Internettechnolgien. Sehr gut! • http://www.jars.com/ Die Jars Page. Hier werden die besten Javapages gekürt. Hier findet man die besten und kuriosesten Javaapplets, manchmal auch mit Sourcecode!! Newsgroups • news://de.comp.lang.java Die Deutsche Java Newsgroup. Hier kann man Neuigkeiten erfahren, Fragen stellen und Tips erhalten. • news://comp.lang.java.announce • news://comp.lang.java.advocacy • news://comp.lang.java.programmer • news://comp.lang.java.tech • news://comp.lang.java.setup Frank Koch 4 Java Entwicklungsgeschichte • 1991: Beginn der Java Entwicklung (im gleichen Jahr, als das WWW entstand) in Hause SUN. Der Java-Entwickler (James Gosling) dachte zunächst nicht an das Internet. Sein Ziel war es eine gemeinsame Entwicklungsplattform für elektronische Konsumgüter (set-top boxes für interaktives TV, PDA, etc) zu erstellen. Dazu benötigte sein Team eine Pgmiersprache, mit der diese Produkte gesteuert werden konnten und die leicht von einem Gerät auf ein anderes portiert werden konnte. Zunächst benutzte das Java Entwicklungsteam C++ als Sprache. Sie realisierten schnell, dass sie eine robustere Sprache mit mehr Unterstützung für Sicherheit und Portabilität benötigten. Diese Bemühungen führten zur Entwicklung der Sprache Oak (die 1995 aus produktrechtlichen Gründen in Java umbenannt wurde). Diese Sprache ist stark an die C++-Syntax angelehnt, dabei aber einfacher und plattformunabhängiger. • 1992: Das Oak-Team war soweit den Projektstatus SUN zu präsentieren, was zur Gründung eines eigenen Unternehmens mit dem Namen FirstPerson führte. Der Plan war es Oak den wichtigsten Herstellern von Consumerelektronikgeräten nahezubringen. Doch der Markt war noch nicht reif für das, was FirstPerson anzubieten hatte. • 1994: kam das Aus für FirstPerson; niemand wollte Oak lizensieren. Zu dieser Zeit war die Welt bereits vom Internet-Fieber erfasst und SUN verstärkte seine Bemühungen auf diesem Gebiet. Das OakTeam realisierte ein fundamentales Problem mit Web-Pages: sie sind „flat“, d.h. sie erlauben dem Surfer keine Interaktion mit den Daten, die auf einer Seite dargestellt werden. „Das Web braucht Interaktivität“, ist die Idee, die dem Oak-Team neuen Anstoss gab. • 1994: Sun released WebRunner und HotJava, zwei in Java entwickelte Browser. Diese neue Technologie fand das Interesse von Netscape, die ankündigten, mit ihrem populären Browser Netscape Navigator künftig Java zu unterstützen. • 1995: Oak wird aus urheberrechtlichen Gründen in Java umgetauft. • 1996: Der verbreitete Netscape Navigator unterstützt Java • 1997: JDK 1.1; viele neue Klassen unterstützen den Entwicklungsprozess1998: JDK 1.2 • Java IDL und RMI (wird für Client/Sever Entwicklungen benötigt) • Swing (GUI Library) • 2001: Present version: 1.3.1 (subset of J2SE) • 2002: J2SE (with SDK) 1.4 Frank Koch 5 Java Entwicklungsziele Hauptziele • Portabilität / Plattformunabhängigkeit Das gleiche Programm läuft auf allen Plattformen, die einen JavaInterpreter besitzen. Für Anwendungen im Internet ein Muss! • Verteilte Anwendungen Neben normalen Applikationen erlaubt Java die Erstellung von Applets, welche durch einen Web-Browser geladen werden können. Diese Applets werden in die HTML-Seiten integriert und über das Internet von den Hostrechnern geladen. Damit ist die Realisierung von verteilten Anwendungen möglich. • Robustheit / Sicherheit Durch mehrstufiges Sicherheitskonzept. Nebenziele • Objektorientierung Im Gegensatz zu C++ kann in Java nicht mehr konventionell programmiert werden. • Evolution Anlehnung an den Industriestandard C und C++ bei gleichzeitiger Verbesserung der C/C++-Schwächen. • Hohe Performance Durch parallele Prozesse (Threads). Trotzdem: als interpretierte Sprache ist Java etwa um den Faktor 20 langsamer als C++. • Java stellt Mechanismen zur Einbindung von InternetRessourcen (z.B. URL) zur Verfügung. Frank Koch 6 Java Architektur Java Architecture Traditional 3GL Architecture Source Code Hello.java Source Code Hello.c Java Compiler Compiler Object Code Byte Code Hello.class Linker Machine Code JVM Frank Koch OS OS CPU CPU 7 Java Security Developer Platform Source Code Hello.java Security Level 1 Language and Compiler Internet Client-Platform Bytecode Hello.class JVM Security Level 2 Bytecode Verifier Security Level 3 Class Loader Security Level 4 Sandbox Model Frank Koch 8 Java Sandbox Model • Für Applets ist kein lokaler Dateizugriff erlaubt (delete, read, write to local files) • Applets dürfen keine Betriebssystembefehle aufrufen (z.B. können keine Verzeichnisse erstellt werden bzw der Inhalt von Verzeichnissen gelesen werden) • Applets dürfen keine lokalen Programme ausführen oder DLLs aufrufen • Applets dürfen keine Netzwerkverbindungen öffnen, ausser zu dem Host, von dem sie geladen wurden. Damit ist es dem Benutzer möglich, Dateien zu speichern. Zwar nicht auf seiner Disk aber auf der des Applet-Hosts. Auf diese Weise kann mittels Applets eine wahre Client/Server Architektur gebaut werden. Frank Koch 9 Application versus Applet Unterschiede: • Eine Application verhält sich wie ein Stand Alone-Programm. • Applets können nur innerhalb eines Java-kompatiblen Containers (z.B. ein Browser) ausgeführt werden. Applikationen hingegen können mittels einer kleinen Boot Utility (JAVA.EXE) von der Command Line ausgeführt werden. Applets werden unter strikten Sicherheitsbeschränkungen (SandboxModel) ausgeführt. Applikationen haben keine solchen Sicherheitsbeschränkungen. • Applets können in eine HTML Page eingebunden (embedded) werden, über das Internet oder ein Intranet verteilt werden und innerhalb eines Browsers ausgeführt werden. Applikationen haben keine Unterstützung für HTML-Embedding oder Downloading. Gemeinsamkeiten: • Beide Programme werden aus einem oder mehreren Dateien mit der .CLASS extension erstellt und enthalten maschinenunabhängigen Java-Bytecode. • Beide Programme erfordern eine installierte Java Virtual Machine (JVM). Die JVM lädt das Programm, interpretiert es und stellt dem Programm die Java core packages (the standard library) zur Verfügung. • Application public class FirstApplication { public static void main(String Args[]) { // Java source code goes here. } } Applet import java.applet.*; public class FirstApplet extends Applet { //Java source code goes here. } Frank Koch 10 HTML APPLET-Tag <APPLET CODE=MyApplet.class CODEBASE=“http://www.zhwin.ch/swk“ ID=FirstApplication WIDTH=320 HEIGHT=240 > </APPLET> CODE CODEBASE ID WIDTH HEIGHT Spezifiziert die zu ladende Java Bytecode Datei. Optional: Eine gültige URL, die auf das Verzeichnis verweist, in dem sich die .CLASS-Datei des Applets befindet. Dieses Tag wird notwendig, wenn sich die .CLASS-Datei in einem anderen Verzeichnis befindet als die HTMLDatei. Unter diesem Namen kann das Applet in dem HTMLDokument referenziert werden. Optional: Spezifiziert die Breite des Applet Windows. Optional: Spezifiziert die Höhe des Applet Windows. PARAM-Tag Hiermit können dem Applet Parameter aus der HTML-Datei übergeben werden <APPLET CODE=MyApplet.class ID=FirstApplication WIDTH=320 HEIGHT=240 > <PARAM name=Message value=“Hello“> </APPLET> Alternate HTML Alternativer Text für nicht-javafähige Browser <APPLET CODE=outline.class HEIGHT=150 WIDTH=200> You're missing a Java outline applet. <UL> <LI><A HREF="default.htm">Internal Training Home Page</A></LI> <LI><A HREF="States.htm">Location Courses are Offered</A></LI> </UL> </APPLET> Frank Koch 11 Erstellen einer Java Application Erstellen eines Java Source Files Erstellen Sie mit einem Editor die Datei Hello.java mit dem folgenden Java code: /** * The Hello class implements an application that * simply displays "Hello World!" to the standard output. */ class Hello { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } Compilation des Sources Compilieren Sie die Source mit dem Java Compiler. javac Hello.java Bei fehlerfreier Compilation erstellt der Compiler die Datei Hello.class (gleiches Verzeichnis wie Hello.java). Diese Datei enthält den plattformunabhängigen Java Bytecode, der von einem Java runtime system interpretiert werden kann. Starten der Applikation Starten Sie das Programm mittels des Java Interpreters. java Hello Die Ausgabe "Hello World!" sollte erscheinen. Frank Koch 12 Erstellen eines Java Applets Erstellen eines Java Source Files Erstellen Sie mit einem Editor die Datei HelloApp.java mit dem folgenden Java code: import java.applet.Applet; import java.awt.Graphics; public class HelloApp extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); } } Compilation des Sources Compilieren Sie die Source mit dem Java Compiler. javac HelloApp.java Bei fehlerfreier Compilation erstellt der Compiler die Datei HelloApp.class (gleiches Verzeichnis wie HelloApp.java). Diese Datei enthält den plattformunabhängigen Java Bytecode. Erstellen einer HTML-Datei, die das Applet einbindet Erstellen Sie mit einem Editor die Datei Hello.html mit dem folgenden HTML code: <HTML> <HEAD> <TITLE> A Simple Program </TITLE> </HEAD> <BODY> Here is the output of my program: <APPLET CODE="HelloApp.class" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML> Starten des Applets Um das Applet zu starten müssen Sie die HTML-Datei in eine Applikation laden, die Java Applets ausführen kann. Dazu können Sie einen Javakompatiblen Browser oder ein anderes Java Applet Darstellungsprogramm (z.B. AppletViewer aus dem JDK) benutzen. Um die HTML-Datei zu laden geben Sie der Applikation die URL der HTML-Datei an, z.B.: file:/d:/Java/Src/Hello/HelloApp.html Um das Applet mit dem AppletViewer anzusehen, wechseln Sie in das AppletVerzeichnis und geben ein: appletviewer HelloApp.html Frank Koch 13 Übung Application versus Applet Erstellen (Codierung, Compilierung, Ausführung) Sie die Java-Application Hello.java sowie das Java-Applet HelloApp.java gemäss der Beschreibungen "Erstellen einer Java Application" sowie "Erstellen eines Java Applets" weiter oben im Skript. Legen Sie die Codeteile im Verzeichnis java\Src\Fundamentals\Hello an. Frank Koch 14 Unterschiede zwischen Java und C++ • Java stellt Unterstützung für Kommunikation und verteilte Verarbeitung zur Verfügung • Java Compiler erstellen maschinenunabhängigen Bytecode, der eine Java Virtual Machine erfordert. C++ Compiler hingegen erstellen Maschinencode. • Java kann stand-alone-Applikationen erstellen oder aber Applets, die über das Internet zugänglich auf HTML Web Pages aktiviert werden. Mit C++ hingegen kann man nur standalone Applikationen erstellen. • Java Applikationen linken alle notwendigen Klassen dynamisch zur Laufzeit. C++ Applikationen hingegen linken die Klassen statisch zur Compilierzeit. • Java unterstützt nur „named references“ auf Speicheradressen. C++ hingegen unterstützt named references sowie pointers und damit Pointerarithmetik. Klartext: Java kennt keine Pointer. • Java hat automatische Garbage Collection. In C++ hingegen muss diese vom Pgmierer besorgt werden. Frank Koch 15 Definition von Variablen /* Single variables */ byte myAge; String myTitle; // Multiple variable declared on a single line int myAge, yourAge, herAge; /* Constant */ final boolean isSmart = true; Variablen sollten initialisiert werden, denn nicht-initialisierte Variablen können nicht gelesen werden. //0 is used to initialize numeric variables int x=0; //null is used to initialize objects String person = null; //null character is used to initialize characters char x='\0'; //false is used to initialize Booleans boolean isMarried = false; Datentypen von Variablen Der Datentyp einer Variablen kann einer der acht primitiven Datentypen, eine build-in oder user-defined Klasse oder ein Array sein. float x; Float x; Student x; int[] x; Frank Koch //float is a primitive data type //Float is a built-in object //Student is a user-defined class //int[] is an array of Integers 16 Primitive Datentypen Java bietet acht primitive Datentypen zur Behandlung von Ganzzahlwerten, Fliesskommawerten, Zeichen und Boolschen Werten. Diese Datentypen sind Bestandteil der Sprache Java und keine Objekte. Allerdings bietet Java Object Wrappers für diese Typen, so dass primitive Datentypen wie Objekte benutzt werden können. Reserved Word byte Data Type Size Range of Values 1 byte -128 to 127 short int Byte-length integer Short integer Integer 2 bytes 4 bytes long Long integers 8 bytes float Single precision numbers Real numbers with double precision Character (16bit Unicode) Has value 4 bytes -32,768 to 32,767 -2,147,483,648 to 2,147,483,647 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 1.40239846e-45 to 3.40282347e+38 4.94065645841246544e-324 to 1.7976931348623157e+308 double char boolean 8 bytes 2 bytes N/A true oder false Ein Boolscher Wert true oder false (nicht wie in C++: 1 oder 0) Beachten Sie, dass char als Unicode benutzt wird. Unicode ist ein 16-bit character set, welches eine Standardzuordnung aller weltweit bekannten Zeichen definiert. WindowsNT benutzt ausschliesslich Unicode auf der Systemebene. Frank Koch 17 Operatoren für primitive Datentypen Arithmetische Operatoren +, -, *, /, % Zuweisungsoperatoren =, +=, -=, *=, /=, %= Inkrement- und Dekrement (Post- und Präfix) ++, -Relationale Operatoren (liefern boolean) ==, !=, <, <=, >, >= Frank Koch 18 Arten von Kontrollstrukturen Niklaus Wirth: „Programme bestehen aus Daten und Algorithmen“ Drei unterschiedliche Befehlsabläufe sind möglich: Sequentielle Abläufe Vergleichende Abläufe / Selektion ? Ja Nein Wiederholende Abläufe / Iteration ? Ja Nein Frank Koch 19 Kontrollstrukturen Selektion: if (<bedingung>) { <true-statement> } else { <false-statement> } switch (<ausdruck>) { case 1: <statement> case 2: <statement> ... case N: <statement> default: <statement> } Iteration: while (<bedingung>) { <statements> } do { <statements> } while (<bedingung>) for (<initialisierung>;<bedingung>;<inkrement/dekrement>) { <statements> } Frank Koch 20 Kontrollstrukturen • Klammert man die Befehle innerhalb einer Kontrollstruktur nicht zu einem Block, so wird nur der erste auf die Kontrollstruktur folgende Befehl abhängig von der Kontrollstruktur ausgeführt. • Kontrollstrukturen können ineinander geschachtelt werden. Was passiert im folgenden Beispiel? int b = 0; int a = ?; // ? muss ersetzt werden if (a > 1) if (a > 2) b = 1; else b = 2; a sei Dann wird b zu 1 2 3 Oder aber… Frank Koch 21 Logische Operatoren Logische Operatoren &&, ||, !, ^^ (XOR) Mit den logischen Operatoren lassen sich Bedingungen verknüpfen, z.B.: if ((alter > 16) && (alter < 40)) System.out.println(“Voller Preis“); Die Entscheidungstabellentechnik hilft beim Aufbau der Bedingungen. • Es sitzen drei Zauberer im Theater, der eine in der ersten Reihe, der Zweite gleich hinter ihm, in der zweiten Reihe und der Dritte in der dritten Reihe, hinter dem Zweiten. Der erste Zauberer sieht also keinen, der Zweite sieht den Ersten und der Dritte sieht beide. • Es gibt 5 Kappen im Theater, 3 schwarze und 2 weisse. Die Zauberer wissen das. Man hat allen drei je eine schwarze Kappe aufgesetzt, ohne dass die Zauberer selbst das gesehen haben. • Wer von den Zauberern ruft als erster aus, dass seine Kappe schwarz ist? • Natürlich dürfen die Zauberer nicht nach hinten schauen oder miteinander reden. Frank Koch 22 Weitere Operatoren Bitwise Operators Bitwise operators manipulate the individual binary digits (bits) of a value as it is actually stored in computer memory. For example, the decimal number 32 would be represented as 0010000 in base 2-bit values. Using the bitwise operators shown in the table below, you can work with these values directly. Operator & | ^ ~ Description AND bitwise operator OR bitwise operator XOR bitwise operator Bitwise complement Example x = y & 64 x = y | 24 x=y^z x=~y Logical Assignment Operators The logical assignment operators are really shorthand for the regular assignment operator (=) and the Boolean bitwise operator.. Operator &= |= ^= <<= >>= >>>= Description AND assignment OR assignment XOR assignment Left shift assignment Right shift assignment Unsigned right shift assignment Example x&=y x|=y x^=z x=<<y x=>>z x>>>=y Shift Operators The left and right shift operators move all of the bits in an integral value to the left or right. In an expression of the form of x<<y, x is the number being shifted and y is the distance to shift x. For example, 10<<1 is equal to 20. In other words, leftshifting a number by y is equivalent to multiplying the number by 2y. Conversely, right-shifting a number is equivalent to dividing a number by 2y. The computer's processor is actually faster at performing shift operations than at multiplying or dividing a number by 2y. Operator << >> >>> Frank Koch Description Left shift Right shift Unsigned right shift Example x<<y x>>z x>>>y 23 Operatoren Rangfolge The following table contains a listing of Java operators in descending order of precedence. The operators with the highest precedence are at the top. Operator [] () . Operator Type array index parameter list method invocation ++,-arithmetic +, arithmetic ~ integral ! Boolean (type) any *, /, % arithmetic +, arithmetic + string << integra >> integra >>> integra <, <= arithmetic >, >= arithmetic instanceof object, type == primitive != primitive == object != object & integral, Boolean ^ integral, Boolean | integral, Boolean && Boolean || Boolean ?: Boolean, any, any = variable, any *=, /=, %=, +=, -=, variable, <<=, >>=, >>>=, any &=, ^=, |= Frank Koch Description Used to access elements of an array Denotes a list of parameters Used to specify a method within an object (or its hierarchy) Pre- or post-increment/decrement Unary plus, unary minus Bitwise complement (unary) Logical complement (unary) Cast Multiplication, division, remainder Addition, subtraction String concatenation Left shift Right shift with sign extension Right shift with zero extension Less than, less than or equal Greater than, greater than or equal Type comparison Equal (have identical values) Not equal (have different values) Equal (refer to the same object) Equal (refer to different objects) Bitwise AND, Boolean AND Bitwise XOR, Boolean OR Bitwise OR, Boolean OR Conditional AND Conditional OR Conditional (ternary) Assignment Assignment with operation 24 Literals 1 Literals are used to indicate explicit values in your programs. Java has four kinds of literals: numbers, characters, strings, and booleans. Numeric Literals There are two types of numeric literals: integers (numbers without decimals) and floating-point numbers (numbers with decimals). Integer literals can be in decimal, octal, or hexadecimal format. Decimal integers are the most common format, and Java assumes all numbers to be decimal unless otherwise noted. Octal integers, which are far less common, are distinguished by a zero in front of the number: 0123. Hexadecimal numbers have a 0x or 0X in front of them: 0xFFFF. Java stores integer literals as 4-byte integers by default. However, if you place the letter l or L after the number, Java will store it as an 8-byte integer. Floating-point literals represent numbers with decimals. In addition to standard notation, you can use scientific notation to represent very large or very small numbers: 5.67 or 2.0467e-22 or 3.5999e94 or -4.2370e96 Normally, a floating point literal is 4 bytes long. For double-precision values with an 8-byte length, you can add the letter d or D after the number. Character Literals A character literal is a Unicode character enclosed in single quotation marks. Any character in the 16-bit character set may be used. A backslash is used to denote non-printing characters, such as carriage returns and tabs. Some of the more commonly used escape sequences are shown in the following table. Description Line feed Carriage return Horizontal tab Backspace Backslash Single quote Double quote Frank Koch Escape Sequence \n \r \t \b \\ \' \" 25 Literals 2 String Literals String literals are characters enclosed in double quotation marks. They can have the same escape sequences as single character literals. Java uses a String class to implement strings, whereas C and C++ use an array of characters. Example: “Hello World“ Boolean Literals Boolean literals can have two possible values: true or false. In Java, true and false do not correspond to the numeric values 1 and 0, as do Booleans in C and C++. Boolean literals are often used as flags for program flow control. For example, the following code sample will change the status bar if the isScrolling() method returns true. boolean x=false; Marquee m = new Marquee("Scrolling message"); x = m.isScrolling(); //If x is true then change the status bar to this message if (x) showStatus("Text is scrolling"); Frank Koch 26 Parameter und Local Variables Im folgenden Pgm ist g eine Parameter-Variable und i eine lokale Variable. Eine Parameter-Variable hat den Scope der Methode, während eine lokale Variable den Scope des Blockes hat, in dem sie definiert wurde. import java.awt.*; public class twos extends java.applet.Applet { public void paint(Graphics g) {//g is local to the paint method for (int i=0;i<100;i+=2) { //i is local to the for statement g.drawString("Number: "+i,10,5*i); } // i dies here } } Frank Koch 27 Arrays Arrays sind Referenzvariablen, die einen für die Aufnahme der Variablen bereitgestellten Speicherbereich referenzieren. Beispiel für die Definition einer Array-Referenzvariablen: int[] intArray; In der eckigen Klammer darf keine Zahlenangabe für die Anzahl Elemente eingegeben werden. Mit dieser Anweisung wird lediglich die Referenzvariable definiert; ein Speicherbereich für die Arrayelemente steht damit noch nicht zur Verfügung. Das eigentliche Array muss erst noch dynamisch geschaffen werden und die Array-Referenzvariable mit dessen Adresse initialisiert werden. int[] intArray; intArray = new int[4]; Damit werden vier Speicherplätze vom Typ int angelegt, auf welche nun die Array-Referenzvariable zeigt. Die Speicherplätze sind von 0 bis n-1 indexiert: intArray[0]; intArray[1]; intArray[2]; intArray[3]; Die Feldgrösse kann über die öffentliche Variable length gelesen (nicht geschrieben!) werden: intArray.length; Im Gegensatz zu C prüft Java zur Laufzeit, ob die Arraygrenzen eingehalten werden! Frank Koch 28 Strings Strings sind Objekte. Beispiel für die Definition eines String-Objektes: String str; str ist nun zwar definiert, enthält aber noch keine gültige Objektreferenz. Erst durch eine Zuweisung wird der Bezug zur Zeichenkette hergestellt: str = "Irgendwas"; Das folgende Programm zeigt die Verwendung der auf Stringobjekte anwendbaren Methoden: class TestString { public static void main(String[] args) { String str; str = "Java"; System.out.println(str.length()); str = str + " ist objektorientiert"; System.out.println(str.length()); System.out.println(str.charAt(11)); System.out.println(str.indexOf("orient")); System.out.println(str.substring(20, 24)); System.out.println(str); } } Ausgabe: 4 25 j 15 tier Java ist objektorientiert Frank Koch 29 Übung Sort Erstellen Sie ein Java-Programm, in dem Sie ein Array mit 10 Elementen mit Werten initialisieren. Sortieren Sie die Zahlenfolge anschliessend in aufsteigender Reihenfolge. Geben Sie die Werte vor und nach dem Sortieren aus. Benutzereingaben sind nicht erforderlich! Die Lösung finden Sie im Anhang. Übung Zeichenkette Konvertieren Sie die Zeichen in einem String in GROSSBUCHSTABEN und kehren Sie die Reihenfolge der in dem String befindlichen Buchstaben. Die Klasse String stellt Ihnen hierzu hilfreiche Methoden zur Verfügung. Suchen Sie in der Online-Hilfe nach der Dokumentation zu dieser Klasse. Die Lösung finden Sie im Anhang. Frank Koch 30 Anhang: Lösung Sort public class Sort { public static void main ( String[] args ) { final int size = 10; int i, j, tmp; int[] array = new int[size]; // Init Array for (i=0; i<size; i++) array[i]=size-i; // Ausgabe for (i=0; i<size; i++) System.out.println(array[i]); // Bubble-Sort for (i=0; i<size-1; i++) { for (j=i+1; j<size; j++) { if (array[i] > array[j]) { tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } } // Ausgabe for (i=0; i<size; i++) System.out.println(array[i]); } } Frank Koch 31 Anhang: Lösung Zeichenkette public class Zeichenkette { public static void main ( String[] args ) { String str = "Zeichenkette"; String tmp = ""; // In Grossbuchstaben konvertierte Ausgabe System.out.println(str.toUpperCase()); // Reversierte Ausgabe (algorithmische Lösung) for(int i=str.length()-1; i>=0; i--) tmp = tmp + str.charAt(i); System.out.println(tmp); // Reversierte Ausgabe (objektorientierte Lösung) StringBuffer sb = new StringBuffer(str); sb.reverse(); System.out.println(sb); } } Frank Koch 32 OO (Klassen und Objekte) Klasse Point • • • • • x-Koordinatenwert y-Koordinatenwert Setzen der Koordinatenwerte Lesen der Koordinatenwerte Ausgabe der Koordinatenwerte Objekt a (1, 3) Objekt c (3, 3) Objekt b (1, 1) Datei Point.java class Point { // Datenteil private static int s_no; // Klassenvariable = 0 private int m_x, m_y; // Information Hiding! } // Methodenteil public Point(int x, int y) { // Konstruktor! s_no++; setX(x); setY(y); } public void setX(int x) {if(x>0) m_x=x; else x=0;} public void setY(int y) {if(y>0) m_y=y; else y=0;} public int getX() {return m_x;} public int getY() {return m_y;} public void print() { System.out.print("Punkt: "); System.out.print("x:" + m_x); System.out.println(" y:" + m_y); } public static void printNo() { // Klassenmethode System.out.println("Anzahl: " + s_no); } public static void main (String[] args ) { Point a=new Point(1,3); Point b=new Point(1,1); Point c=new Point(3,3); c.setX(10); c.setY(-5); System.out.println(c.getX() + " " + c.getY()); a.print(); b.print(); c.print(); System.out.println("Wir fragen ein Objekt"); a.printNo(); System.out.println("Wir fragen die Klasse"); Point.printNo(); } Klasse: Kopplung von Daten und Funktionen zu einem Typ. Ist eine Deklaration / Schablone. Objekt / Instanz / Exemplar: Instanz der Klasse. Ist eine Definition / Speicherreservation. Instanzvariable / Membervariable / Objektvariable: In der Klasse definierte Daten. Methode: In der Klasse definierte Funktionen. Frank Koch 33 OO (Wiederverwendung 1) Arten der Beziehungen zwischen Klassen: Beziehung Beispiel Syntaktische Lösung "Besteht aus"Beziehung (Stückliste) "Ist ein"Beziehung Ein Dreieck (Triangle) besteht aus drei Punkten (Point). Ein gefülltes Dreieck (FilledTriangle) ist ein Dreieck mit zusätzlichen Eigenschaften (Farbe). Objekte als Instanzvariablen Vererbung Notation: "B esteht aus" P oint "Ist ein" P oint Triangle Triangle P oint P oint FilledTriangle Vererbung: FilledTriangle Triangle getA print setA a, b, c getB setC setB getC color setColor print Frank Koch getColor 34 OO (Wiederverwendung 2) Datei Triangle.java class Triangle { // Datenteil private Point m_a, m_b, m_c; } // Methodenteil public Triangle() { m_a = new Point(0,0); m_b = new Point(0,0); m_c = new Point(0,0); } // Overloading Constructor public Triangle(Point a, Point b, Point c) { m_a = a; m_b = b; m_c = c; } public void setA(Point a) {m_a = a;} public void setB(Point b) {m_b = b;} public void setC(Point c) {m_c = c;} public Point getA() {return m_a;} public Point getB() {return m_b;} public Point getC() {return m_c;} public void print() { System.out.println("Triangle: "); m_a.print(); m_b.print(); m_c.print(); } public static void main (String[] args ) { Point p1 = new Point(1,1); Point p2 = new Point(2,2); Point p3 = new Point(3,3); Triangle t1 = new Triangle(p1, p2, p3); Triangle t2 = new Triangle(); t1.print(); t2.print(); } Regeln für mehrere Klassen in einer .JAVA-Source: • Genau eine Klasse kann public deklariert sein. In diesem Fall muss die .java-Datei den Namen dieser Klasse tragen. • Jede Klasse kann eine eigene main()-Methode besitzen • Der Compiler generiert zu jeder Klasse ein .class-File Frank Koch 35 OO (Wiederverwendung 3) Datei FilledTriangle.java class FilledTriangle extends Triangle { // Datenteil String m_color; } // Methodenteil public FilledTriangle() { super(); m_color = "white"; } // Overloading Constructor public FilledTriangle( Point a,Point b,Point c,String col){ super(a, b, c); m_color = col; } public void setColor(String c) {m_color = c;} public String getColor() {return m_color;} // Overriding method print() public void print() { System.out.println("FilledTriangle: "); super.print(); System.out.println(m_color); } public static void main (String[] args ) { Point p1 = new Point(1,1); Point p2 = new Point(2,2); Point p3 = new Point(3,3); FilledTriangle ft1 = new FilledTriangle(p1, p2, p3, "red"); FilledTriangle ft2 = new FilledTriangle(); ft1.print(); ft2.print(); } Frank Koch 36 Übung Objektorientierung Aufgabe 1 Sie erhalten die Source zu den Klassen Line und GraficLine. Untersuchen Sie diesen Code und wiederholen Sie daran die vorgestellten objektorientierten Konzepte (Polymorphismus, Encapsulation, Inheritance, Constructor, ...). Aufgabe 2 Erweitern Sie den Code gemäss folgender Aufgabenstellungen: • Setzen Sie die Farbe eines FilledTriangle-Objekts auf „blue“. • Es soll sichergestellt werden, dass ein Punkt nur innerhalb eines Koordinatensystems mit der Ausdehnung x=100 und y=100 erstellt werden kann. Wird ein grösserer Wert von dem Benutzer der Klasse spezifiziert, so muss dieser auf den maximal möglichen Wert 100 gekürzt werden. • Inkrementieren Sie den x-Wert eines Punktes eines konkreten FilledTriangle-Objekts um den Wert 1 (sofern der Wert 100 nicht überschritten wird). • Ermöglichen Sie, dass ein FilledTriangle-Objekt Auskunft über die Anzahl instanziierter Objekte seiner Klasse Auskunft geben kann. Frank Koch 37 Method Overloading Method overloading allows you to supply the same name for two or more methods within the same class. Each method signature in an overloaded set must differ in the number and/or types of its parameters. General methods and constructors can be overloaded. Following an example that demonstrates overloading in the constructor and bark method of the Dog class: public class Dog { Float m_height, m_weight; StringBuffer m_breed; } Dog() { m_height=0; m_weight=0; m_breed = null; } Dog(float height, float weight, String breed) { m_height= height; m_weight= weight; m_breed = new StringBuffer(breed); } void bark() { //Plays default bark sound file. } void bark(int tone, float sec) { //Plays bark sound of given tone and durration. } Because a call to an overloaded method is resolved at compile time, method overloading is also sometimes referred to as static polymorphism. Frank Koch 38 Method Overriding Method overriding is used to elicit different behaviors from objects related by an inheritance hierarchy. To support polymorphism through overriding, the following two conditions must exist: • An inheritance relationship must exist between two or more classes. • A similar method must be implemented in both the super class and one or more of its subclasses. The method must have a consistent signature — name, return type, and parameter list — in all classes. public class Mammal { boolean m_isAsleep; void sleep(boolean b) { m_isAsleep = b; } } public class Dog extends Mammal { boolean m_isOnGuard; void sleep(boolean b) { //Dog sleeps if not on guard duty and b == true. if (m_isOnGuard == false) super.sleep(b); } } Note the use of the super keyword in the subclass to invoke its parent class version of the same method. Even though overriding normally hides the super class's version of a method, the super keyword can be used to force access to it from within the subclass. Now that the sleep method has been properly overridden, it can be invoked through a reference to the base class, as shown in the following code: Mammal mam1 = new Mammal(), dog1 = new Dog(); mam1.sleep(); //calls Mammal.sleep dog1.sleep(); //calls Dog.sleep polymorphically Although the variable dog1 has the data type of Mammal, the call to sleep invokes the proper method Dog.sleep, because it really references a Dog object. Because a call to an overridden method may be resolved at run time, method overriding is also sometimes referred to as dynamic polymorphism. Frank Koch 39 Garbage Collection Java führt selbständig eine Garbage Collection durch und entlastet den Programmierer damit von der Notwendigkeit, Objekte explizit freizugeben. Die Garbage Collection arbeitet weitgehend autark. Je nach Auslastung des Speichers wird diese Komponete aktiv und sucht Objekte, die nicht mehr referenziert werden und damit defacto nutzlos geworden sind. Der von solchen Objekten belegte Speicherplatz wird zurückgewonnen und kann von neuen Objekten genutzt werden. Zur Aktivierung der Garbage Collection kommt es in der Regel, wenn die Speicherverwaltung einen Speicherengpass vorhersieht. So können Programme mit geringem Speicherbedarf ablaufen, ohne je die Garbage Collection benötigt zu haben.1 Bevor die Garbage Collection den Speicher eines Objektes zurüchgewinnt, wird die finalize()-Methode dieses Objektes aufgerufen (sofern diese Methode existiert). Mit System.gc() können Sie die Garbage Collection auch explizit aufrufen. Dies gilt als ‚Vorschlag‘ an die Java Virtual Machine, unbenutzte Objekte zu recyclen. Ob die Garbage Collection dann wirklich alle nichtreferenzierte Objekte zurückgewinnt, hängt von den Laufzeitbedingungen des konkreten Falls ab. Wenn Sie ein Objekt nicht mehr benötigen, hören Sie einfach auf, es zu referenzieren. Dazu kann seine Referenz auf ein anderes Objekt oder auf null gerichtet werden, oder aber eine Methode wird abgeschlossen, so dass lokale Referenzvariablen ihre Gültigkeit verlieren. Das folgende Pgm ist so angelegt, dass in einer for-Schlaufe sehr viele Objekte erzeugt werden. Dadurch erreicht das kleine Pgm einen hohen Speicherbedarf. Immer dann, wenn l auf ein neues Line-Objekt gesetzt wird, verliert sich die Referenz auf das alte Line-Objekt. Läuft die Schleife nur wenige Male (z.B. 100 mal), so kann es sein, dass die Garbage Collection nie aufgerufen wird. Läuft die Schleife hingegen viele Male, so muss die Garbage Collection den durch die nicht mehr benötigten Objekte belegten Speicherplatz wiedergewinnen. Auf meinem Rechner wird die Garbage Collection im Fall von 10000 Schleifendurchläufen 7928 mal aktiv. class Line { static int callFinalize = 0; Point m_a, m_b; public Line() { m_a = new Point(0,0); m_b = new Point(0,0); } public void finalize() { callFinalize++; } public static void main (String[] args ) { Line l; for(int i = 0; i < 10000; i++) l = new Line(); // loosing object references System.out.println("Calls: " + callFinalize); } } • 1 Quelle: Ken Arnolds & James Gosling, „Java Die Programmiersprache“ Frank Koch 40 Object Wrappers Mit Ausnahme der primitiven Datentypen (byte, short, int, long, float, double, char und boolean) sind alle Java-Strukturen immer Objekte. Manchmal möchte man, dass sich auch die primitiven Datentypen wie Objekte verhalten, denn dann kann man von deren Methoden profitieren (z.B. konvertieren des Wertes). Aus diesem Grunde kennt Java sogenannte ObjectWrappers für alle primitiven Datentypen. Man erkennt ein ObjectWrapper-Object daran, dass der Datentyp gross geschrieben wird. Natürlich muss nun wieder Speicher alloziert werden. Definition von Object Wrapper Objekten Float f = new Float(); Integer i = new Integer(); intObj wird mit der Integer-Repräsentation von 4711 initialisiert Integer intObj = new Integer("4711"); der in intObj gespeicherte Wert wird i zugewiesen int i = intObj.intValue(); der in intObj gespeicherte Wert wird str zugewiesen String str = intObj.toString(); Merke: Mit den in ObjectWrappers gespeicherten Werten kann keine Arithmetik betrieben werden. intObj++ ist also nicht möglich. Frank Koch 41 Übung Wiederverwendung Erstellen Sie ein Java-Programm mit mehreren Klassen gemäss der folgenden Spezifikation: Klassenname Mensch Lebewesen • Daten • iq • herz • Methoden • • • • • setIq getIq verlieben pgmieren print • setHerz • getHerz • print Ehe • frau • mann • ehejahre • • • • setFrau getFrau ... print Probieren Sie dabei die "Besteht aus"- sowie die "Ist ein"-Beziehung. Integrieren Sie möglichst alle im Unterricht angesprochenen Konzepte (Method Overloading, Method Overriding, Standardkonstruktor, super, finalize, static, ...). Frank Koch 42 Passing Params to an Application When you declare a main method for a Java application, you must specify an array of strings as a parameter. This array stores parameters from the user when the program is executed from the command line. You access a specific array element by specifying the index to the array: public class Hello { public static void main(String args[]) { System.out.println("Hello " + args[0]+"!"); } } You can pass parameters to a Java application by typing in arguments at the command line: java Hello Peter The output is: Hello Peter! To determine the number of arguments passed from the command line, use the length property of the args[ ] array. Frank Koch 43 Passing Params to an Applet Applets get parameters by using a special parameter tag in the HTML file called the PARAM tag. Each PARAM tag has two attributes: NAME and VALUE. <APPLET CODE="Hello.class" WIDTH=300 HEIGHT=300> <PARAM NAME="Vorname" VALUE="James"> <PARAM NAME="Nachname" VALUE="Gosling"> </APPLET> Your Java applet then uses a getParameter method to process parameters. This method takes an argument representing the name of the parameter passed to it. The following code shows how to obtain the parameters passed in through an HTML file: String vorname = getParameter("Vorname"); String nachname = getParameter("Nachname"); If the NAME parameter is omitted in the HTML file, the getParameter method returns null. It is recommended that you verify that a value is returned from getParameter. If you attempt to access a method or property of the String object that is equal to null, your code will generate a NullPointerException exception. You can verify that getParameter returns a value by checking for null, as shown here: if (vorname == null) { showStatus("No name specified"); System.exit(0); } Frank Koch 44 Übung Passing Params to an Applet Ein Applet soll den aus einem HTML-File übergebenen Text (z.B. "Wir lernen Java") ausgeben. Erstellen Sie das Applet ParamApplet.java mit der Klasse ParamApplet sowie die Datei ParamApplet.html. Ihr Applet soll eine Fehlermeldung generieren, wenn der Text nicht oder nicht richtig spezifiziert wurde. Die Lösung finden Sie im Anhang. Frank Koch 45 Anhang: Lösung Passing Params to an Applet ParamApplet.java import java.applet.Applet; import java.awt.Graphics; public class ParamApplet extends Applet { public void paint(Graphics g) { String text = getParameter("Text"); if (text == null) { showStatus("No text specified"); System.exit(0); } g.drawString("Der Text \"" + text + "\" wurde übergeben", 20, 40); } } ParamApplet.html <HTML> <HEAD> <TITLE> A Simple Program </TITLE> </HEAD> <BODY> <APPLET CODE="ParamApplet.class" WIDTH=300 HEIGHT=100> <PARAM NAME="Text" VALUE="Wir lernen Java"> </APPLET> </BODY> </HTML> Frank Koch 46 Exception Handling - Ausgangslage class Point { private static int s_no; public int m_x, m_y; public Point(int x, int y) { s_no++; setX(x); setY(y); } public void finalize() {s_no--;} public void setX(int x) { if (x<0) m_x = 0; System.out.println("X: Falscher Wert System.exit(0); else { m_x = x; } } public void setY(int y) { if (y<0) m_y = 0; System.out.println("Y: Falscher Wert System.exit(0); else { m_y = y; } } public int getX() {return m_x;} public int getY() {return m_y;} public void print() { System.out.println(m_x + " " + m_y); } public static void printNo() { System.out.println("Anzahl: " + s_no); } public static void main (String[] args ) { Point a=new Point(1,-1); // Point b=new Point(2,2); Point c=new Point(3,3); c.setX(-2); // c.setY(-3); // a.print(); b.print(); c.print(); Point.printNo(); } } Frank Koch " + x); " + y); Fehler Fehler Fehler 47 Exception Handling Syntax Exception Class class XException extends Exception { XException (Point p, int i) { super("X: Falscher Wert " + i); p.m_x=0; } } throws - Klausel public void setX(int x) throws XException {...} Auslösen von Exceptions if (x < 0) throw new XException(this, x); Auffangen von Exceptions public Point(int x, int y) { ... try { setX(x); setY(y); } ... catch(XException e) { System.out.println(e.getMessage()); } catch(YException e) { System.out.println(e.getMessage()); } finally { // Endbehandlung } } Frank Koch 48 Exception Handling finally{...} finally{} wird generell für Aufräumarbeiten (Schliessen von Dateien, Freigeben von Ressourcen , etc.) nach try{} benutzt. Nützlich daran ist, dass der Code im finally{} garantiert ausgeführt wird unabhängig davon, was im zugehörigen try{} passiert ist. Im Normalfall wird das Ende des try{} erreicht und anschliessend finally{} ausgeführt. Falls try{} mit return, continue oder break verlassen wird, wird zunächst finally{} ausgeführt, bevor der Programmablauf an der neuen Destination weiterschreitet. Falls in try{} eine Exception geworfen wird, so wird (falls vorhanden) das lokale catch{} ausgeführt und anschliessend finally{} ausgeführt. Gibt es kein lokales catch{}, so wird zunächst finally{} ausgeführt und anschliessend das nächste catch{} gesucht, dass die Exception bedienen kann. Wird innerhalb eines finally{} ein return, continue oder break ausgeführt oder eine Exception geworfen, so wird ein evtl. vorher ausgelöster Progammunterbruch ignoriert und der neue Programmunterbruch sofort behandelt. Frank Koch 49 Exception Handling Bsp 1 (1/2) class XException extends Exception { XException (Point p, int wert) { super("X: Falscher Wert " + wert); p.m_x = 0; // m_x ist PUBLIC } } class YException extends Exception { YException (Point p, int wert) { super("Y: Falscher Wert " + wert); p.m_y=0; // m_y ist PUBLIC } } class Point { static int s_no; public int m_x, m_y; public Point(int x, int y) { s_no++; try { setX(x); setY(y); } catch(XException e) { System.out.println(e.getMessage()); e.printStackTrace(); } catch(YException e) { System.out.println(e.getMessage()); e.printStackTrace(); } } public void finalize() {s_no--;} public void setX(int x) throws XException { if (x<0) throw new XException(this, x); else m_x = x; } Frank Koch 50 Exception Handling Bsp 1 (2/2) public void setY(int y) throws YException { if (y<0) throw new YException(this, y); else m_y = y; } public int getX() {return m_x;} public int getY() {return m_y;} public void print() { System.out.println(m_x + " " + m_y); } public static void printNo() { System.out.println("Anzahl: " + s_no); } public static void main (String[] args ) { Point a=new Point(1,-1); // Fehler Point b=new Point(2,2); Point c=new Point(3,3); try { c.setX(-2); // Fehler c.setY(-3); // Fehler } catch(XException e) { System.out.println(e.getMessage()); e.printStackTrace(); } catch(YException e) { System.out.println(e.getMessage()); e.printStackTrace(); } finally { a.print(); b.print(); c.print(); Point.printNo(); } Point.printNo(); } } Frank Koch 51 Exception Handling Beispiel 2 Unchecked Exceptions class UncheckedException { public static void main (String[] args ) { int[] pentagon = new int[5]; try { int i = 4711; i = i / 0; // Fehler Division by zero for(i=0; i<pentagon.length; i++) { pentagon[i] = i; } pentagon[i] = 5; // Fehler i = 5 } } } catch (Exception e) { System.out.println("Threw a " + e.getClass() + " with message: " + $ e.getMessage()); } Resultate (das Pgm wird nach der 1. Exception abgebrochen, weshalb es nicht zur 2. Ausgabe kommt): Threw a class java.lang.ArithmeticException with messsage: / by zero Threw a class java.lang.ArrayIndexOutOfBoundsException with messsage: null Frank Koch 52 Interfaces - Definition Interfaces ähneln Klassen. Während aber eine Klasse die (nicht abstrakten) Methoden implementiert, werden Methoden (sowie Konstanten) in Interfaces nur deklariert. Implementiert eine Klasse das Interface, so können die deklarierten Methoden von ihr unterstützt werden. interface Lookup { Object find(String name); } Das Interface Lookup definiert eine Methode find(), ohne deren Implementierung anzugeben. Programme, die Referenzen zu LookupObjekten nutzen, können find() aufrufen, wobei der tatsächliche Typ des Objekts keine Rolle spielt. void test(String name, Lookup array) { Object o = array.find(name); } Nachfolgend sehen wir die Implementierung eines Interfaces. class MyLookup implements Lookup { private String[] names; private Object[] values; public Object find(String name) { for(int i = 0; i < names.length; i++) if (names[i].equals(name)) return values[i]; return null; } } Auch Interfaces können mit extends erweitert werden. Ein Interface kann ein oder mehrere andere Interfaces erweitern. Die Menge der Basistypen einer Klasse besteht aus der von ihr erweiterten Klasse (extends) und den von ihr implementierten Interfaces (implements) einschliesslich aller Basistypen dieser Klasse und dieser Interfaces. Ein Interface kann von vielen Klassen implementiert werden, wobei sich die Implementierungen in den vom Interface-Programmierer bestimmten Grenzen (Methoden-Signatur) unterscheiden können. Interfaces bieten damit die Möglichkeit ein Mindestverhalten ihrer Implementierungen zu garantieren. Frank Koch 53 Interfaces - Mehrfachvererbung In Java kann eine Klasse nur aus einer Klasse abgeleitet werden (single inheritance). Oft aber gibt es Situationen, in denen eine Klasse EigenFahrzeug schaften von mehreren Klassen erben sollte (ein Luftkissenboot ist ein LandLandfahrzeug Wasserfahrzeug sowie ein Wasserfahrzeug). Nun könnte man versucht sein, die in Luftkissenboot Land- und Wasserfahrzeugen implementierten Eigenschaften stattdessen in deren Parentklasse Fahrzeuge anzusiedeln und das Luftkissenboot daraus abzuleiten. Schnell ginge man höher und höher und würde letztendlich die Klasse Object auf unbewältigbare Proportionen anwachsen lassen. Object Java unterstützt multiple inheritance bei Interfaces, So können wir, anstatt Eigenschaften zu Object hinzuzufügen, diese in einem Interface ansideln. Interfaces in der Klassenhierarchie geben Java damit die Möglichkeit der Mehrfachvererbung. interface FZ { // FZ = Fahrzeug public void movePos(int x, int y); } interface LandFZ extends FZ { public void park(); } interface WasserFZ extends FZ { public void sink(); } class Luftkissenboot implements LandFZ, WasserFZ { int m_x, m_y; boolean m_park=false, m_sink=false; public void movePos(int x, int y) { m_x = x; m_y = y; } public void park(){ m_park = true; } public void sink(){ m_sink = true; } } Frank Koch 54 Interfaces - Weiteres Alle Methoden in einem Interface sind implizit abstrakt. Weil ein Interface Implementierungen ihrer deklarierten Methoden nicht bereitstellen muss, braucht es diese Methoden auch nicht als abstrakt zu deklarieren. Jede ein Interface implementierende Klasse muss entweder alle ihre Methoden oder alternativ nur einige ihrer Methoden implementieren. In letzterem Fall ist die Klasse dann abstrakt und muss auch so deklariert werden. Methoden in einem Interface sind stets public. Die Methoden in einem Interface können nicht static (klassenbezogen) sein, da als static deklarierte Methoden immer klassenbezogen und damit konkret statt abstrakt sind und ein Interface nur abstrakte Methoden enthalten kann. Die Variablen eines Interfaces hingegen sind immer static (klassenbezogen) und final (endgültig). Sie dienen der Definition von beim Aufruf von Methoden verwendeten Konstanten. interface FZ { // FZ = Fahrzeug static final int INITIAL_X_POS = 0; static final int INITIAL_Y_POS = 0; public void movePos(int x, int y); } ... public void park(){ m_x = INITIAL_X_POS; m_y = INITIAL_Y_POS; m_park = true; } Frank Koch 55 Übung Erstellen Sie den Code zu folgendem Diagramm (Interfaces sind schraffiert, Klassen nicht-schraffiert gekennzeichnet). Fahrzeug Landfahrzeug Wasserfahrzeug Transporter PersonenTransporter Luftkissenboot Verteilen Sie die folgende Funktionalität in sinnvoller Weise an den adäquaten Stellen im obigen Diagramm. Beschränken Sie sich auf das Wesentlichste. • Ein Luftkissenboot kann parken, sinken, sowie sich fortbewegen. • Die Transportfähigkeit eines Luftkissenbootes lässt sich mit dem Transportgewicht sowie der Anzahl beförderbarer Personen beschreiben. • Ein Luftkissenboot verfügt über die Methode status(), mit der es alle in ihm vorhandenen Variablen auf dem Bildschirm ausgibt. • Zum Schluss benötigen wir noch eine main()-Methode, mit der wir ein konkretes Luftkissenboot mit bestimmtem Transportgewicht sowie bestimmter Anzahl Personen erzeugen, es an eine neue Position versetzen und es dort parken. Danach ruft main() die Methode status() auf. Frank Koch 56 Anhang: Lösung Interface interface FZ { // FZ = Fahrzeug int INITIAL_X_POS = 0; int INITIAL_Y_POS = 0; public void movePos(int x, int y); } interface LandFZ extends FZ { public void park(); } interface WasserFZ extends FZ { public void sink(); } class Transporter { int m_transportGewicht; public void setTransportGewicht(int tg) { m_transportGewicht = tg; } public int getTransportGewicht() { return m_transportGewicht; } } class PersonenTransporter extends Transporter { int m_anzahlPersonen; public void setAnzahlPersonen(int ap) { m_anzahlPersonen = ap; } public int getAnzahlPersonen() { return m_anzahlPersonen; } } class Luftkissenboot extends PersonenTransporter implements LandFZ, WasserFZ { int m_x, m_y; boolean m_park=false, m_sink=false; public void movePos(int x, int y) { m_x = x; m_y = y; } public void park(){ m_x = INITIAL_X_POS; m_y = INITIAL_Y_POS; m_park = true; } public void sink(){ m_sink = true; } public void status () { System.out.println("Transportgewicht = " + m_transportGewicht); System.out.println("AnzahlPersonen = " + m_anzahlPersonen); System.out.println("Park = " + m_park); System.out.println("Sink = " + m_sink); } public static void main (String[] args ) { Luftkissenboot lkb =new Luftkissenboot(); lkb.setTransportGewicht(6000); lkb.setAnzahlPersonen(100); lkb.movePos(10, 10); lkb.park(); lkb.status(); } } Frank Koch 57 Thread Zustände Ezeugt Thread wurde mit new erzeugt und kann nun mit den für den späteren Ablauf notwendigen Daten initialisiert werden. Ablauffähig Diesen Zustand erreicht der Thread durch den Aufruf der Thread-Methode start(). Der Thread wird damit rechenbereit und kann von dem JavaLaufzeitsystem (Java-Scheduler) in den Zustand rechnend überführt werden. Der Java-Scheduler bestimmt nach einem Prioritäten- und RoundRobin-Verfahren den nächsten Thread, der den Prozessor belegen darf. Rechnend Diesen Zustand erreicht der Thread durch den Aufruf der Thread-Methode run() durch den Java-Scheduler. Hier wird die eigentliche Arbeit verrichtet, weshalb die run()-Methode in der abgeleitetenKlasse redefiniert werden muss. Beendet Ist die run()-Methode abgearbeitet oder wurde die stop()-Methode des Threads aufgerufen, so befindet sich der Thread in dem Zustand beendet. Der Thread könnte nun mit der Methode start() neu angestossen werden. Wartend Hat der Java-Scheduler einen Thread anhalten, so ist dieser "wartend". Dies kann durch mehrere Methoden erreicht werden: • Methode sleep(long millisec) Der Thread wird für die angegebene Zeitspanne auf "wartend" gesetzt und danach automatisch auf "ablauffähig" gesetzt. • Methode suspend() Der Thread wird auf "wartend" gesetzt und wird erst wieder durch die Methode resume() auf "ablauffähig" gesetzt. • Methode yield() Thread gibt den Prozessor freiwillig frei und wird auf "ablauffähig" gesetzt. Dies kann die Frank Koch 58 Performance anderer Threads steigern. Frank Koch 59 Thread Beispiel class PingPong extends Thread { String m_word; long m_delay; public PingPong(String word) { m_word = word; } public void start() { System.out.println("Thread started"); super.start(); } public void run() { try { while(true) { System.out.print(m_word+" "); // Pseudozufallszahl 0..100 gleichverteilt m_delay = (long)(Math.random()*100); // Nachfolgend 3 Alternativen // eine geerbte Methode aufzurufen Thread.sleep(m_delay); sleep(m_delay); super.sleep(m_delay); } } catch(InterruptedException e) {return;} } public static void main(String[] args) { // 1. Art Objekt zu instanziieren PingPong ping = new PingPong("ping"); ping.start(); } } // 2. Art Objekt (ohne Namen) zu instanziieren new PingPong("PONG").start(); Resultat: Thread started ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping ping Thread started PONG PONG ping PONG ping PONG PONG ping ping PONG PONG PONG ping ping PONG PONG ping PONG PONG ping PONG PONG PONG ping PONG ping ping ping PONG ping Frank Koch 60 Thread mit und ohne synchronize class Lager { private long m_bestand; public Lager(long menge) {m_bestand = menge;} public /*synchronized*/ void trx(long menge, int no) { System.out.print("[" + no); long tmp = m_bestand + menge; for(long i=0; i<500000; i++); // Zeitverschwendung... m_bestand = tmp; System.out.print(no + "] "); } public long getMenge() {return m_bestand;} } class Handel extends Thread { private static Lager m_birnen = new Lager(100); // nur ein Lager! private static int m_anzahlThreads = 0; private int m_threadNummer; } public Handel() {} public void start() { System.out.println("Thread started"); m_threadNummer = m_anzahlThreads ++; super.start(); } public void run() { while(true) { m_birnen.trx((long)(Math.random()*100), m_threadNummer); try { sleep((long)(Math.random()*10)); } catch(InterruptedException e) { return; } } } public static void main(String[] args) { new Handel().start(); new Handel().start(); new Handel().start(); } Ohne synchronize Thread started Thread started [0Thread started 0] [1[2[02] 0] [22] 1] [2[1[01] 2] 0] [1[01] [2[11] 2] 0] [2[1[02] 0] 1] [22] [0 [1[22] 1] 0] [1[2[00] 1] [0[12] 1] [1[20] 1] [02] [1[20] 1] 2] [0[1[20] 2] [01] Mit synchronize Thread started Thread started Thread started [00] [22] [11] [00] [22] [11] [00] [22] [11] [00] [22] [00] [11] [00] [22] [00] [11] [22] [00] [11] [22] [00] [11] [00] [22] [11] [00] [22] [11] [22] [00] [11] Frank Koch 61 wait() und notify() Die Methoden wait() und notify() sind in der Klasse Object definiert und werden von allen Klassen geerbt. Sie werden wie Sperren auf bestimmte Objekte angewendet. Mait wait() wartet man auf ein bestimmtes Ereignis, dass an anderer Stelle mit notify() erzeugt wird. Alles wird innerhalb einer synchronize-Methode durchgeführt. Andernfalls wäre der Inhalt des Objekts nicht stabil. wait() synchronize checkCondition() { while(!condition) wait() // Code für den Erfüllungsfall der Bedingung } wait() setzt die Methode in einen Wartezustand. Gleichzeitig wird die synchronize-Sperre aufgehoben, so dass die Methode wieder von anderen Threads benutzt werden kann. notify() synchronize changeCondition() { // Ändern der für die Bedingung relevanten Werte notify() } Mehrerer Threads können auf dasselbe Objekt warten. Ein Aufruf von notify() weckt den am längsten Wartenden auf. Sollen alle Threads aufgeweckt wreden, kann notifyAll() benutzt werden. Frank Koch 62 Kommunikation zwischen Threads class Lager { private long m_bestand; public Lager(long menge) {m_bestand = menge;} public synchronized void trx(long menge, int no) { long tmp = m_bestand + menge; for(long i=0; i<500000; i++); // Zeitverschwendung... m_bestand = tmp; //notify(); } public synchronized long getMenge() { //try {wait();} //catch(InterruptedException e) {return (long)0;} return m_bestand; } } class Handel extends Thread { private static Lager m_birnen = new Lager(100); // nur ein Lager! private static int m_anzahlThreads = 0; private int m_threadNummer; } public Handel() {} public void start() { System.out.println("Thread started"); m_threadNummer = m_anzahlThreads++; super.start(); } public void run() { while(true) { if (m_threadNummer == 0) System.out.print(m_birnen.getMenge() + " "); else { m_birnen.trx((long)(Math.random()*100), m_threadNummer); try { sleep((long)(Math.random()*10000)); } catch(InterruptedException e) { return; } } } } public static void main(String[] args) { new Handel().start(); new Handel().start(); new Handel().start(); } Ohne wait() und notify() Thread started Thread started Thread started 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 132 132 132 132 132 132 132 132 132 132 132 132 132 132 Mit wait() und notify() Thread started Thread started Thread started Frank Koch 63 230 240 267 290 387 412 432 440 489 500 597 601 646 675 720 805 843 888 912 954 Frank Koch 64 Interface Runnable Leiten wir eine Klasse aus Thread ab, dann können wir diese nicht gleichzeitig aus anderen Klassen ableiten. Deshalb implementiert die Klasse Thread das Interface Runnable. Das Interface Runnable deklariert eine einzige Methode: public void run(); Wird ein Thread-Objekt mit Hilfe eines Objekts vom Typ Runnable erzeugt, ruft die Implementierung von Thread.run() die Methode run() des Runnable-Objekts auf. class RunPingPong implements Runnable { String m_word; int m_delay; RunPingPong(String word, int delay) {m_word = word; m_delay = delay;} public void run() { try { while(true) { System.out.print(m_word+" "); Thread.sleep(m_delay); } } catch(InterruptedException e) {return;} } } public static void main(String[] args) { RunPingPong ping = new RunPingPong("ping", 33); RunPingPong pong = new RunPingPong("PONG", 55); new Thread(ping).start(); new Thread(pong).start(); } Resultat: ping PONG ping ping PONG ping ping PONG ping ping PONG ping PONG ping ping PONG ping ping PONG ping PONG ping ping PONG ping PONG ping ping PONG ping PONG ping Ein Runnable-Objekt kann in seiner eigenen Thread-Umgebung ausgeführt werden. Dazu wird ein Thread-Objekt angelegt z.B. mit new Thread(<object>).start(); Der Thread wird dabei mit der run()-Methode des Objekts verbunden. Ein so konstruiertes Thread-Objekt ruft dann beim Starten genau diese im eigentlichen Anwendungsobjekt realisierte run()-Methode auf. Frank Koch 65 Übung Queue Erstellen Sie einen Puffer mit begrenzter Anzahl Elementen (z.B. int-Array mit 10 Elementen). Eine Erzeuger-Thread legt darin Datenelemente (Zahlen) an. Eine Verbraucher-Thread nimmt Daten aus diesem PufferBereich heraus und verarbeitet diese (Ausgabe auf dem Bildschirm). Ist der Puffer voll, so muss die Erzeuger-Thread pausieren. Ist der Puffer leer, so muss die VerbraucherThread pausieren. Interessant wird es, wenn Sie mehrere Erzeuger- und Verbraucher-Threads instanziieren... Probieren Sie auch Varianten mit unterschiedlich langen Pufferbereichen... Sie zweifeln an der betriebswirtschaftlichen Relevanz dieser Übung? Dann ersetzen Sie doch die Zahlen durch Hamburger, die Verbraucher durch HamburgerEsser und die Erzeuger durch McDonald-Personal ☺ Die Lösung finden Sie im Anhang. Frank Koch 66 Anhang: Lösung Queue (1/2) class Erzeuger extends Thread { String m_name; int m_delay; } Erzeuger(String name) {m_name=name;} public void run() { try { while(true) { m_delay = (int)(Math.random()*800); System.out.print(m_name + " : "); if (!Queue.eingabe((int)(Math.random()*300))) { System.out.println("Puffer voll"); sleep(2000); } else sleep(m_delay); } } catch (InterruptedException e) {return;} } class Verbraucher extends Thread { String m_name; int m_delay; Verbraucher(String name) {m_name=name;} public void run() { try { while(true) { m_delay = (int)(Math.random()*800); System.out.print(m_name + " : "); if (!Queue.ausgabe()) { System.out.println("Puffer leer"); sleep(2000); } else sleep(m_delay); } } catch (InterruptedException e) {return;} } } Frank Koch 67 Anhang: Lösung Queue (2/2) class Queue { static int[] m_menge = new int[10]; static int m_zaehler = 0; synchronized public static boolean eingabe(int neu) { if (m_zaehler < m_menge.length) { m_menge[m_zaehler++]=neu; System.out.println("Eingabe: " + m_menge[m_zaehler-1]); return true; } else return false; } synchronized public static boolean ausgabe() { if (m_zaehler > 0) { System.out.println("Ausgabe: " + m_menge[--m_zaehler]); return true; } else return false; } public static void main(String[] args) { new Erzeuger("Erzeuger1 ").start(); new Erzeuger("Erzeuger2 ").start(); new Verbraucher("Verbraucher1").start(); new Verbraucher("Verbraucher2").start(); } } Frank Koch 68 Packages 1 Packages sind Sammlungen logisch zueinander gehörender Klassen und Interfaces. Bei der Benutzung einer Klasse muss deren Package-Name angeben werden, womit auch bei einer hohen Zahl von Klassen jede einen eindeutigen Namen hat. Jede Klasse gehört zu einem Package und wird mit dem Kompilieren ihrem Package zugefügt. Wird keine package-Anweisung benutzt, so wird die Klasse dem DefaultPackage zugefügt, das Unnamed Package genannt wird. File ComplexNumber.java Package srd.math; public class ComplexNumber { private double m_real; private double m_imag; public ComplexNumber(double real, double imag) { m_real = real; m_imag = imag; } public ComplexNumber Add(ComplexNumber c) { return new ComplexNumber(m_real+c.m_real, m_imag+c.m_imag); } } File Test.java class Test { public static void main(String[] args) { srd.math.ComplexNumber c1, c2; c1 = new srd.math.ComplexNumber(1.0, 1.0); c2 = new srd.math.ComplexNumber(2.0, 2.0); srd.math.ComplexNumber c3 = c1.Add(c2); } } ... oder besser so ... import srd.math.ComplexNumber; class Test { public static void main(String[] args) { ComplexNumber c1, c2; c1 = new ComplexNumber(1.0, 1.0); c2 = new ComplexNumber(2.0, 2.0); ComplexNumber c3 = c1.Add(c2); } } Packages und das File System • Besteht ein Sourcefile aus mehr als einer Klassen, so darf nur eine Klasse public deklariert sein und das Sourcefile muss den gleichen Namen wie diese Klasse tragen. • .class-files werden in einem Verzeichnis gespeichert, dessen Namenskomponenten zu den Namenskomponenten des Pakets korrespondieren. So werden die .class-files zu dem Paket ch.zhwin.kfr.games unter %CLASSPATH%\ch\zhwin\kfr\games\* gespeichert. Im obigen Bsp wird die Klasse ComplexNumber unter .\srd\math\ComplexNumber gespeichert. • Java-Code ohne package-Anweisung wird automatisch dem unnamed package zugeordnet. • Klassen, die public deklariert sind, sind von ausserhalb und innerhalb eines Pakets zugreifbar. • Klassen, die nicht public deklariert sind, sind nur von innerhalb eines Pakets zugreifbar. • Compilieren Sie die zu einem Paket gehörenden Sourcefiles und trasferieren Sie die generierten .class-files anschliessend in das korrespondierende Verzeichnis. Anschliessend können Sie die so organisierten Klassen über die import-Anweisung benutzen. • Die import Anweisung kann für jede Klasse komplett ausgeschrieben werden (z.B. import zhwin.kfr.OnePublic). Oder aber Sie wird abgekürzt (z.B. import zhwin.*). Im Abkürzungsfall darf Frank Koch 69 sich der zum Paket gehörende Source nicht in dem Entwicklungsverzeichnis befinden. Im komplett ausgeschriebenen Fall gilt diese Restriktion nicht. Frank Koch 70 Packages 2 //.OnePublic.java //.\zhwin\kfr\OnePublic.class package zhwin.fkoch; //.TwoPublic.java //.\zhwin\kfr\TwoPublic.class package zhwin.fkoch; public class OnePublic { public void m_public() {} private void m_private() {} void m_friendly() {} public static void main(String[] args) { One o = new One(); o.m_public(); //o.m_private(); nicht ok o.m_friendly(); } } public class TwoPublic { public void m_public() {} private void m_private() {} void m_friendly() {} public static void main(String[] args) { OnePublic op = new OnePublic(); One o = new One(); } } class One { public void m_public() {} private void m_private() {} void m_friendly() {} public static void main(String[] args) { OnePublic op = new OnePublic(); op.m_public(); //op.m_private(); nicht ok op.m_friendly(); } class Two { public void m_public() {} private void m_private() {} void m_friendly() {} public static void main(String[] args) { OnePublic op = new OnePublic(); One o = new One(); } } Package: zhwin.fkoch //.\ZhwinTest.java //.\ZhwinTest.class //Paket-Source darf nicht im Verzeichnis '.' sein import zhwin.kfr.*; //Alternativ: //Paket-Source darf nun im Verzeichnis '.' sein //import zhwin.kfr.OnePublic; //import zhwin.kfr.TwoPublic; class ZhwinTest { public static void main(String[] args) { OnePublic op = new OnePublic(); op.m_public(); //op.m_private(); nicht ok //op.m_friendly(); nicht ok //One o = new One(); nicht ok TwoPublic tp = new TwoPublic(); } Frank Koch 71 Java Core Packages Java beinhaltet 6 Core-Packages. In jedem Paket sind die Klassen in einer Hierarchie geordnet, d.h. Klassen auf niedriger Stufe erben von ihren Superklassen. java.lang java.io java.util java.net java.awt java.applet Definiert Datentypen, Objekte, WrapperClasses, Klassen für Prozesse und die Runtime-Umgebung, Unterstützung für Multithreading Klassen und Interfaces für I/O: Files, Streams, Filter, Exceptions DataCollection-Klasses (z.B. Stack), Utility-Classes (z.B.Random) Network-Communication using TCP/IP, UDP, HTTP, URL, Sockets, Datagram-Class Steht für Abstract Windowing Toolkit und stellt viele Klassen für das GUI zur Verfügung. Graphic, GUIElemente, Container, Menus) Dieses Package enthält 2 Subpackages: • java.awt.image: Klassen und Interfaces für ImageData • java.awt.peer: Für das Mapping von Java-GUI auf das GUI eines bestimmten Betriebssystems Um Applets in den Browser zu laden • Microsoft hat die Core-Packages zudem um com.ms.com erweitert, um das Zusammenspiel mit COM (Component Object Model) zu ermöglichen. Die Benutzung dieses Packages bedeutet aber, dass Sie Ihre Pgme nur noch auf Plattformen portieren können, die COM unterstützen! • Microsoft und Sun sind die grossen Gegenspieler und immer bemüht Allianzen gegen ihren Gegner zu bilden. MS hat Java von Sun lizensiert und ist damit verpflichtet Visual J++ periodisch den neuen Features der Sprache Java sowie der Core-Packages anzupassen. Andererseits bemüht sich MS stetig, Java zu seinen Gunsten zu erweitern und zeigt sich sehr zäh, wenn es darum geht von SUN entwickelte Standards in Java++ zu implementieren. Es gab bereits einige gerichtliche Auseinandersetzungen. Am besten informieren Sie sich auf dem Internet: • Splash.javasoft.com • Java.sun.com/devcorner.html • www.microsoft.com/visualj/indexpgs/press.htm (Was MS in der Presse veröffentlicht) • www.microsoft.com/java/resource/press.htm (Was die Presse über MS veröffentlicht) Frank Koch 72 Utility Package (util) Date Class • Liefert Methoden zur Behandlung des Datums Stack Class • Stacks sind bekannte Strukturen in der Pgmierung und funktionieren wie ein Tellerstapel (LIFO). • Hier arbeitet man mit push und pop Random Class • Braucht man für Zufallszahlen Observable Class • Die Observable Class erlaubt es einem Objekt ein anderes zu observieren. Ändert sich der Zustand des observierten Objekts, so informiert es seinen Observer. StringTokenizer Class • Mit dieser Klasse können Sie Strings parsen. Ein String wird dabei in Token (Bestandteile des Strings) zerlegt, wobei Sie bestimmen, was als Delimiter der einzelnen Token gesehen wird. import java.util.*; public class ParseString { public static void main(String args[]) { String str = "To be or not to be"; String ary[] = new String[10]; StringTokenizer t = new StringTokenizer(str); for (int i=0;t.hasMoreTokens();i++) { ary[i]=t.nextToken(); System.out.println(ary[i]); } } } Frank Koch 73 Abstract Windowing Toolkit (awt) Die Entwicklung eines grafischen User-Interfaces, das auf vielen Plattformen läuft, wird durch das Java-AWT-Package ermöglicht. Dieses Package enthält Klassen, mit denen man relativ einfach portable und grafische Benutzeroberflächen realisieren kann. Das AWT beinhaltet im wesentlichen drei Arten von Klassen: Kontrollelemente Erlauben die Interaktion des Benutzers mit der Anwendung (Button, Menue, Dialogbox, ...). Container Verwalten Kontrollelemente. Es gibt den Container Frame, welcher einem Window entspricht und den Container Panel, welcher die Gruppierung von Kontrollelementen entspricht. Layout-Manager Werden innerhalb von Containern benutzt, um Kontrollelemente automatisch anzuordnen. Die Klassen im AWT-Package: Component Container Window Dialog FileDialog Frame Panel Applet Button Canvas CheckBox Label List Scrollbar TextComponent TextArea TextField Frank Koch 74 Container und Layout import java.awt.*; class DemoFrame { public static void main(String[] args) { Frame fr = new Frame("FrameDemo"); fr.setSize(400, 400); fr.setVisible(true); } } class DemoMultipleFrame { public static void main(String[] args) { Frame fr1 = new Frame("MultipleFrameDemo1"); fr1.setSize(200, 600); fr1.setVisible(true); Frame fr2 = new Frame("MultipleFrameDemo2"); fr2.setSize(600, 200); fr2.setVisible(true); } } class DemoBL { public static void main(String[] args) { Frame fr = new Frame("BorderLayoutDemo"); fr.setLayout(new BorderLayout()); fr.add("North", new Button("Eins")); fr.add("South", new Button("Zwei")); fr.add("East", new Button("Drei")); fr.add("West", new Button("Vier")); fr.add("Center", new Button("Fünf")); fr.pack(); fr.setVisible(true); } } class DemoFL { public static void main(String[] args) { Frame fr = new Frame("FlowLayoutDemo"); fr.setLayout(new FlowLayout()); fr.add(new Button("Eins")); fr.add(new Button("Zwei")); fr.add(new Button("Drei")); fr.add(new Button("Vier")); fr.add(new Button("Fünf")); fr.pack(); fr.setVisible(true); } } class DemoGL { public static void main(String[] args) { Frame fr = new Frame("GridLayoutDemo"); fr.setLayout(new GridLayout(3, 2)); fr.add(new Button("Eins")); fr.add(new Button("Zwei")); fr.add(new Button("Drei")); fr.add(new Button("Vier")); fr.add(new Button("Fünf")); fr.pack(); fr.setVisible(true); } } Frank Koch 75 Panel Manchmal benötigt man Komponenten innerhalb von Komponenten. Dazu kann die Container-Subklasse Panel eingesetzt werden. import java.awt.*; class DemoComplex { public static void main(String[] args) { // Create FlowLayout Panel Panel pfl = new Panel(); pfl.setLayout(new FlowLayout()); pfl.add(new Button("Eins")); pfl.add(new Button("Zwei")); pfl.add(new Button("Drei")); // Create BorderLayout Panel Panel pbl = new Panel(); pbl.setLayout(new BorderLayout()); pbl.add("North", pfl); // Panel within Panel pbl.add("South", new Button("South")); pbl.add("Center", new Button("Center")); } } // Create GridLayout Frame Frame fr = new Frame("ComplexLayoutDemo"); fr.setLayout(new GridLayout(1, 3)); fr.add(pbl); // Panel within Container fr.add(new Button("Zwei")); fr.add(new Button("Drei")); fr.pack(); fr.setVisible(true); Ausgabe: Frank Koch 76 Menu (MenuDemo.java) import java.awt.*; class DemoMenu { public static void main(String[] args) { Frame fr = new Frame("MenuDemo"); MenuBar mb = new MenuBar(); Menu me = new Menu("English"); me.add(new MenuItem("One")); me.add(new MenuItem("Two")); mb.add(me); Menu md = new Menu("Deutsch"); md.add(new MenuItem("Eins")); md.add(new MenuItem("-")); // Separator md.add(new MenuItem("Zwei")); md.add(new MenuItem("Drei")); md.add(new MenuItem("Vier")); mb.add(md); } } fr.setMenuBar(mb); fr.setSize(200, 100); fr.setVisible(true); Übung Menu • Verändern Sie das obige Programm DemoMenu.java, so dass ein beliebiges Untermenu angezeigt wird. • Wie gehen Sie vor, wenn Sie das gleiche Untermenu an mehreren Stellen in Ihrem Menu einbinden müssten. Gehen Sie möglichst objektorientiert vor und programmieren Sie Ihre Lösung. Frank Koch 77 Textfield TextField t = new TextField("Defaulttext"); Pop-up Menu Choice c = new Choice(); c.addItem("Choice 1"); c.addItem("Choice 2"); c.addItem("Choice 3"); fr.add(c)); Checkbox Checkbox cb = new Checkbox("Text"); Frank Koch 78 Einfache Grafik und AWT Ein einfaches Grafik-Programm unter AWT: // GraficDemo1.java // Einfaches Grafik-Programm import java.awt.*; class GraphicDemo extends Frame { public GraphicDemo() { setSize(400, 400); setTitle("GraphicDemo"); } public void paint(Graphics g) { g.setColor(Color.red); g.fillOval(200, 200, 50, 20); } public static void main(String [ ] args) { GraphicDemo gd = new GraphicDemo(); gd.show(); } } Frank Koch 79 Dynamische Grafik und AWT Ein dynamisches Grafik-Programm unter AWT: // GraficDemo2.java // Dynamisches Grafik-Programm import java.awt.*; class Oval { private int m_x, m_y, m_h, m_w; private Color m_c; public Oval(int x,int y,int h,int w, Color c) { m_x = x; m_y = y; m_h = h; m_w = w; m_c = c; } public void wachse() { m_h++; m_w++; } public void paint(Graphics g) { g.setColor(m_c); g.fillOval(m_x, m_y, m_h, m_w); } } class GraphicDemo extends Frame { Oval m_o = new Oval(0, 0, 30, 10, Color.red); public GraphicDemo() { setSize(400, 400); setTitle("GraphicDemo"); } public void paint(Graphics g) { m_o.paint(g); m_o.wachse(); repaint(); } public static void main(String [ ] args) { GraphicDemo gd = new GraphicDemo(); gd.show(); } } Frank Koch 80 Events Events (Mausklicks, Mausbewegungen, ...) bieten den Benutzern eines GUIs die Möglichkeit, mit der Anwendung zu interagieren. Das Java-Laufzeitsystem erkennt solche Events und leitet sie an die den Event auslösenden Objekte weiter. In dieser Komponente wird dann die vordefinierte Methode public boolean handleEvent(Event ev) aufgerufen, welche den Event analysiert (switch()) und die jeweilige ebenfalls im Objekt vordefiniert Ereignisbearbeitungsmethode aufruft. Solche Ereignisbearbeitungsmethoden sind: boolean action(Event ev, Object obj) boolean mouseDown(Event ev, int x, int y) boolean mouseDrag(Event ev, int x, int y) boolean mouseEnter(Event ev, int x, int y) boolean mouseExit(Event ev, int x, int y) boolean mouseUp(Event ev, int x, int y) boolean keyDown(Event ev, int key) Ein Kontrollelement wurde manipuliert z.B. Button gedrückt. In obj befindet sich das korespondierende Kontrollelement. Der Mausknopf wurde an der Position x, y gedrückt. Die Maus wurde über ein Kontrollelement bewegt, während ein Knopf gedrückt ist. Der Mauszeiger tritt in den Bereich des Kontrollelements ein. Der Mauszeiger verlässt den Bereich des Kontrollelements. Der Mausknopf wird losgelassen. Die Taste <key> wurde gedrückt. Der action Event: Der action Event für einen Button wird beim Klick auf den Button generiert; der action Event für ein TextField wird durch die <Enter>-Taste generiert, wenn sich der Cursor im TextField befindet. Der action Event veranlasst die objekteigene handleEvent()Methode die objekteigene action()-Methode aufzurufen. Diese Methode liefert den Default-Wert false zurück, was bedeuted, dass der Event nicht behandelt wurde. Dies hat zur Folge, dass der Event an das das Auslöse-Objekt einbettende Objekt (Parent) weitergeleitet wird (Frame- oder Panel-Objekt, wenn das Button-Objekt darin eingebettet ist). Dieses Weiterreichen geschieht solange, bis die action()-Methode den Wert true liefert. Damit entstehen zwei Möglichkeiten auf Events zu reagieren: 1) Eine action()-Methode kann für jedes Kontrollelement überschrieben werden um die gewünschte Funktionalität zu implementieren. Bei drei Button-Objekten könnten wir also die Klassen ButtonOne, ButtonTwo und ButtonThree aus Button ableiten. Die TwoButton.action()-Methode würde dann den action Event erhalten, wenn Button2 geklickt wurde. Leider entstehen auf diese Weise sehr viele Klassen, was zu einer Aufblähung und Dezentralisierung des Codes führt. 2) Behandeln die Kontrollelemente den action Event nicht selbst, so wird dieser an das Parent-Objekt weitergeleitet (Das Parent-Objekt einer Komponenten ist der Container, dem die Komponenten hinzugefügt wurde). Überschreiben wir die action()-Methode des Parentobjekts, so erhalten wir alle action Events an einem Ort. Nun aber müssen wir herausfinden, welches Objekt den Event ausgelöst hat. Dazu wird der action()-Methode das Event-Objekt (hier ev) übergeben. Mit ev.target haben wir eine Referenz zu dem auslösenden Objekt und ev.arg beinhaltet den neuen Zustand des auslösenden Objekts (z.B. der Text innerhalb eines TextField). Übrigens ist ev.arg identisch zu obj. Frank Koch 81 Events Beispiel (1/3) Der nachfolgende Code demonstriert ein mehrschichtiges Even-Handling. Dazu gehört folgendes User Interface: Nachfolgend die Ausgabe, wenn auf obigen User Interface die Buttons von links oben nach recht unten geclickt werden: Click auf MyButtonTrueInPanel MyButtonFalseInPanel ButtonInPanel ButtonInFrame(local) ButtonInFrame(global) Eingabe in das Textfeld Frank Koch Reaktion Event Handling MyButtonTrue->MyButtonTrueInPanel MyButtonFalse->MyButtonFalseInPanel MyPanel->MyButtonFalseInPanel MyPanel->ButtonInPanel MyFrame (instance)>ButtonInFrame(local) MyFrame (m_b)->ButtonInFrame(global) MyFrame (m_t)->hallo 82 Events Beispiel (2/3) // Events1.java // Demonstriert Events auf verschiedenen Stufen import java.awt.*; class MyButtonTrue extends Button { public MyButtonTrue(String s) { super(s); setBackground(Color.green); } public boolean action(Event ev, Object obj) { System.out.println("MyButtonTrue->" + getLabel()); return true; } } class MyButtonFalse extends Button { public MyButtonFalse(String s) { super(s); setBackground(Color.red); } public boolean action(Event ev, Object obj) { System.out.println("MyButtonFalse->" + getLabel()); return false; } } class MyPanel extends Panel { public MyPanel() { setLayout(new FlowLayout()); setBackground(Color.blue); add(new MyButtonTrue("MyButtonTrueInPanel")); add(new MyButtonFalse("MyButtonFalseInPanel")); add(new Button("ButtonInPanel")); } public boolean action(Event ev, Object obj) { System.out.println("MyPanel->" + ((Button)ev.target).getLabel()); return true; } } Frank Koch 83 Events Beispiel (3/3) class MyFrame extends Frame { private TextField m_t = new TextField("TextField(global)"); private Button m_b = new Button("ButtonInFrame(global)"); } public MyFrame(String s) { super(s); setLayout(new GridLayout(4,1)); add(new MyPanel()); add(new Button("ButtonInFrame(local)")); add(m_b); add(m_t); pack(); setVisible(true); } public boolean action(Event ev, Object obj) { if (ev.target == m_b) { // Button global String str = ((Button)ev.target).getLabel(); System.out.println("MyFrame (m_b)->" + str); return true; } else if (ev.target instanceof Button) { String str = ((Button)ev.target).getLabel(); System.out.println("MyFrame(instance)->" + str); return true; } // Das folgende else ist eine schlechte Alternative else if (ev.target == m_t) { // TextField global String str = ((TextField)ev.target).getText(); System.out.println("MyFrame (m_t)->" + str); return true; } return false; } public static void main(String[] args) { new MyFrame("EventDemo"); } Frank Koch 84 Interne Klassen / Nested Classes Windows-Events werden mit dem WindowsListener behandelt. import java.awt.*; import java.awt.event.*; // Für addWindowListener class MyFrame extends Frame { public MyFrame(String title) { super(title); // Aufruf geerbter Konstruktor // Instanziierung & Definition einer Internen Klasse WindowAdapter wa = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; // Reaktion auf Windows-Events addWindowListener(wa); } } ... wie gehabt ... public boolean action(Event ev, Object obj) { ... wie gehabt ... } class EventDemo { ... wie gehabt ... } Frank Koch 85 Übung Calendar Im Unterricht wird Ihnen der Bytecode zu dem Programm Calendar zur Verfügung gestellt, der folgenden Output erzeugt: "Spielen" Sie mit der Benutzerschnittstelle dieser Applikation, um daraus Rückschlüsse auf das Event-Modell zu gewinnen. Programmieren Sie anschliessend Ihren eigenen Calendar. Mein Calendar ist noch recht einfach. Natürlich könnte man die Anzahl Tage-Buttons abhängig vom ausgewählten Monat/Jahr anzeigen. Auch könnte man die Tage-Buttons nicht horizontal sondern vertikal durchlaufen lassen und nach Wochen gruppieren. Machen Sie mehr aus Ihrem Calendar... Die Lösung finden Sie im Anhang. Frank Koch 86 Anhang: Lösung Calendar (1/2) // Calendar einfach Version import java.awt.*; class Days extends Panel { public Days() { setLayout(new GridLayout(7, 5)); for(int i=1; i<=31; i++) add(new Button("" + i)); } } class Calendar extends Frame { private TextField m_textField = new TextField(""); private Choice m_months = new Choice(); private Choice m_years = new Choice(); private int m_d, m_m, m_y; public Calendar(String s) { super(s); m_d = 1; m_m = 1; m_y = 2002; m_textField.setText(m_d + "." + m_m + "." + m_y); } setLayout(new BorderLayout()); // Choice Box Monate m_months.addItem("Januar"); m_months.addItem("Februar"); m_months.addItem("März"); m_months.addItem("April"); m_months.addItem("Mai"); m_months.addItem("Juni"); m_months.addItem("Juli"); m_months.addItem("August"); m_months.addItem("September"); m_months.addItem("Oktober"); m_months.addItem("November"); m_months.addItem("Dezember"); m_months.select(m_m-1); // Choice Box Jahre for(int i=1990; i<2020; i++) m_years.addItem(""+i); m_years.select("" + m_y); // Zusammensetzen Kontrollelemente Panel p = new Panel(); p.add(m_months); p.add(m_years); add("North", p); add("Center", new DayPanel(31)); add("South", m_textField); pack(); setVisible(true); public void updateTextField(String dmy, int value) { if (dmy.equals("Day")) m_d = value; if (dmy.equals("Month")) m_m = value; if (dmy.equals("Year")) m_y = value; m_textField.setText(m_d + "." + m_m + "." + m_y); } Frank Koch 87 public boolean action(Event ev, Object obj) { // War es ein Button? if (ev.target instanceof Button) { String str = ((Button)ev.target).getLabel(); // Welcher Button war es? for(int i=1; i<=31; i++) if (str.equals("" + i)) updateTextField("Day", i); return true; } // War es die Monats Choice? if (ev.target == m_months) { String str = m_months.getSelectedItem(); if (str.equals("Januar")) updateTextField("Month", 1); if (str.equals("Februar")) updateTextField("Month", 2); if (str.equals("März")) updateTextField("Month", 3); if (str.equals("April")) updateTextField("Month", 4); if (str.equals("Mai")) updateTextField("Month", 5); if (str.equals("Juni")) updateTextField("Month", 6); if (str.equals("Juli")) updateTextField("Month", 7); if (str.equals("August")) updateTextField("Month", 8); if (str.equals("September")) updateTextField("Month", 9); if (str.equals("Oktober")) updateTextField("Month", 10); if (str.equals("November")) updateTextField("Month", 11); if (str.equals("Dezember")) updateTextField("Month", 12); return true; } // War es die Jahres Choice? if (ev.target == m_years) { updateTextField("Year", Integer.parseInt(m_years.getSelectedItem())); return true; } return false; } } public static void main(String[] args) { new Calendar("MyCalendar"); } Frank Koch 88 Übung Ball Im Verzeichnis ..\Java\Src\Awt\Ball (Bestandteil von Java_src.exe) finden Sie einige Java Programme aus dem Buch „Object Oriented Programming with Java“ von Timothy Budd. Studieren Sie den Code dieser Programme und erarbeiten Sie ein Verständnis der Programmstruktur sowie der Klassendefinitionen. Programm Beschreibung Source Ball World Ein Frame mit einem rollenden Ball BallWorld.java Ein Frame mit mehreren rollenden Bällen MultiBallWorld.java Interaktives Kanonenfeuern CannonWorld.java Multi Ball World Cannon World Ball.java Ball.java Ball.java (Sorry an die Pazifisten) Frank Koch 89 Applet Kontrollmethoden Methode Nutzung public void init(); Wird beim Laden des Applets aufgerufen. In init() sollten alle für die Arbeit des Applets wichtigen Ressourcen (Speicherplätze, Initialisierungen, ...) bereitgestellt werden. public void start(); Diese Methode wird unmittelbar nach init() aufgerufen und enthält den eigentlichen Applet-Code. start() wird auch aufgerufen, wenn das Applet neu dargestellt werden muss (Klick auf Aktualisieren, oder Wechsel auf eine andere WebPage mit anschliessender Rückkehr) public void stop(); Diese Methode ist das Gegenstück von start() und wird aufgerufen, wenn die WebPage verlassen oder der Browser beendet wird. public void destroy(); Diese Methode ist das Gegenstück von init() und wird aufgerufen, wenn der Browser beendet wird. public void paint(Graphics g); Diese Methode wird immer dann aufgerufen, wenn das Applet wiederhergestellt werden muss (z.B. weil es verdeckt wurde). Szenario: 1) Wir laden das Applet in den Browser: init(), start(), paint() 2) Wir browsen zu einer anderen WebPage: stop() 3) Wir gehen zurück auf die vorige WebPage: start(), paint() 4) Wir browsen zu einer anderen WebPage: stop() 5) Wir gehen zurück auf die vorige WebPage: start(), paint() 6) Wir verdecken das Browserfenster und holen es wieder hervor: paint() 7) Wir beenden den Browser: destroy() Frank Koch 90 Beispiel Methods import java.applet.Applet; import java.awt.Graphics; public class Methods extends Applet { private int m_paint; private int m_init; private int m_start; private int m_stop; private int m_destroy; public Methods() { m_paint = 0; m_init = 0; m_start = 0; m_stop = 0; m_destroy = 0; } public void init() { resize(320, 240); m_init++; } public void start() { m_start++; } public void stop() { m_stop++; } public void destroy() { m_destroy++; } public void paint(Graphics g) { m_paint++; g.drawString("paint = " + g.drawString("init = " + g.drawString("start = " + g.drawString("stop = " + g.drawString("destroy = " + } } m_paint, 0, 10); m_init, 0, 20); m_start, 0, 30); m_stop, 0, 40); m_destroy, 0, 50); Output obiges Szenario: Dieser Output zeigt paint mit 5 anstatt wie erwartet mit 4 an. Grund ist der weitere Aufruf der paint()-Methode beim Einfangen des Windows. Frank Koch 91 Applet Events Applets reagieren nicht nur auf die Aufrufe des Browsers. Auch Benutzer-Interaktionen (Mausklick, Mausbewegung, Tastatureingabe) können mit Events behandelt werden. Wie schon im Kapitel "The Java Event Model" gezeigt, verfügen auch Applets über einen Event-Handler (handleEvent()-Methode aus der Klasse Component), die mit jedem Event aufgerufen wird und die dem Event zugeordnete Ereignisbehandlungsmethode aufruft. Diese Ereignisbehandlungsmethoden sind: Der Mauscursor tritt in den AppletBereich ein. Der Mauscursor tritt aus dem AppletBereich aus. Wird mit jeder Mausbewegung aufgerufen, wenn kein Mausknopf gedrückt wurde. boolean mouseDrag(Event evt, Wird mit jeder Mausbewegung aufgerufen, wenn der Mausknopf gedrückt int x, int y) wurde. Der Mausknopf wurde gedrückt. boolean mouseDown(Event evt, int x, int y) Der Mausknopf wird losgelassen. boolean mouseUp(Event evt, int x, int y) boolean keyDown(Event evt, int Eine Taste wurde gedrückt während das Applet-Window aktiv war. key) Eine Taste wurde losgelasssen wähboolean keyUp(Event evt, int rend das Applet-Window aktiv war. key) Das Applet-Window wird auf aktiv geboolean gotFocus(Event evt, setzt. Object what) Boolean lostFocus(Event evt, Das Applet-Window wird auf inaktiv gesetzt. Object what) boolean mouseEnter(Event evt, int x, int y) boolean mouseExit(Event evt, int x, int y) boolean mouseMove(Event evt, int x, int y) Frank Koch 92 Events Beispiel import java.applet.*; import java.awt.*; public class Events extends Applet { private Dimension m_cursorLoc; // location of cursor private boolean m_drag; // True if we're dragging public void init() { resize(640, 480); } public void paint(Graphics g) { String cursorLoc = "(" + m_cursorLoc.width + "," + m_cursorLoc.height + ")"; g.drawString(cursorLoc, 10, 20); if (m_drag) g.setColor(Color.red); else g.setColor(Color.black); int x = m_cursorLoc.width; int y = m_cursorLoc.height; g.drawLine(x-4, y, x+4, y); g.drawLine(x, y-4, x, y+4); } public boolean mouseDrag(Event evt, int x, int y) { m_drag = true; m_cursorLoc = new Dimension(x, y); repaint(); // forces a repaint of the window return true; } public boolean mouseMove(Event evt, int x, int y) { m_drag = false; m_cursorLoc = new Dimension(x, y); repaint(); // forces a repaint of the window return true; } } Frank Koch 93 Übung Connector Erweitern Sie das soeben besprochenen Applet (Nennen Sie es nun "Connector"). Mit jedem mouseDown-Event speichern Sie die jeweilige Cursorposition (Array) und zeichnen eine Linie zwischen dieser Position und allen anderen bislang angeklickten Positionen. Weiterhin sind die Cursorbewegungen mit dem bekannten Kreuz darzustellen. Die Lösung finden Sie im Anhang. Erweiterung der Übung: Das oben vorgeschlagene Array hat die Einschränkung, dass zur Programmierzeit entschieden wird, wieviele Positionen gespeichert werden können. Das folgende Beispiel zur Klasse Vector (dynamisch veränderbares Array) soll Ihnen eine Idee geben, wie Sie Ihre Lösung dynamisch anlegen können. Schauen Sie auch mal in die Hilfe. import java.util.*; public class VectorTest { public static void main (String args[]) { Vector v = new Vector(10); myClass mc = new myClass(); mc.setName("Heidi"); v.addElement(mc); // Cast, da Vector generisch ist System.out.println(((myClass)v.elementAt(0)).getName()); } } Frank Koch 94 Anhang: Lösung Connector import java.applet.*; import java.awt.*; class Connector extends Applet { static final int m_MAXLOCS = 100; private Dimension m_locs[]; // records clicked locations private int m_noClicks; // number of mouse clicks private Dimension m_cursorLoc; // location of cursor public Connector() { m_locs = new Dimension[m_MAXLOCS]; m_noClicks = 0; } public void init() { resize(640, 480); } public void paint(Graphics g) { // connect all memorized locations with each other for(int i=0; i<m_noClicks-1; i++) { for(int j=i+1; j<m_noClicks; j++) { g.drawLine(m_locs[i].width, m_locs[i].height, m_locs[j].width, m_locs[j].height); } } } public boolean mouseDown(Event evt, int x, int y) { if (m_noClicks < m_MAXLOCS) { m_locs[m_noClicks] = new Dimension(x, y); m_noClicks++; repaint(); } return true; } } Frank Koch 95 Applets und Threads public class AppThread extends Applet implements Runnable { Thread thread = null; public void start() { thread = new Thread(this); thread.start(); } public void run() { while(thread != null) { ... } } public void stop() { thread.stop(); thread = null; } Frank Koch 96 Übung Nochmal Ball Haben Sie im AWT-Teil die Java Programme aus dem Verzeichnis ..\Java\Src\Awt\Ball (Bestandteil von Java_src.exe) studiert? Dann können wir die Übung nun für Applets erweitern: Ändern Sie das Multi Ball World-Programm so, dass es als Applet läuft. Testen Sie es mit dem Appletviewer aus dem JDK. Für Fortgeschrittene und Begeisterte: Ändern Sie das Cannon World-Programm so, dass es als Applet läuft. Frank Koch 97 I/O-Klassen Object interface DataInput interface DataOutput InputStream FileInputStream PipedInputStream ByteArrayInputStream StringBufferInputStream SequenceInputStream FilterInputStream BufferedInputStream DataInputStream LineNumberInputStream PushBackInputStream StreamTokenizer OutputStream FileOutputStream PipedOutputStream ByteArrayOutputStream FilterOutputStream BufferedOutputStream DataOutputStream PrintStream RandomAccessFile File interface FileNameFilter FileDescriptor Throwable Exception IOException EOFException FileNotFoundException InterruptedIOException UTFDataFormatException Frank Koch 98 System.in und System.out import java.io.*; class ConsolIO { public static void main(String[] args) { byte bArray[] = new byte[20]; System.out.println("Eingabe:"); try { System.in.read(bArray); } catch(IOException ioe) { // für read System.out.println(ioe.toString()); ioe.printStackTrace(); } System.out.print("Sie gaben ein: "); // Die Zeile 'System.out.println(bArray);' // läge nahe, aber System.out (PrintStream) // kann kein Bytearray ausgeben String s = new String(bArray, 0); System.out.println(s); } } Frank Koch 99 Simple File I/O import java.io.*; public class FileCopy { public static void main(String[] args) { File inputFile = new File("in.txt"); File outputFile = new File("out.txt"); try { FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } catch (Exception e) {e.getMessage();} } } Frank Koch 100 Buffered File I/O import java.io.*; class BufferedFileCopy { public static void main(String[] args) { try { byte bArray[] = new byte[128]; int no; FileInputStream in = new FileInputStream("in.txt"); // add buffering to that Input Stream BufferedInputStream bin = new BufferedInputStream(in); FileOutputStream out = new FileOutputStream("out.txt"); // add buffering to that Input Stream BufferedOutputStream bout = new BufferedOutputStream(out); while(bin.available() > 0) { // read in 128 bytes no = bin.read(bArray); // write out read bytes bout.write(bArray, 0, no); } bout.flush(); } catch(IOException ioe) { System.out.println(ioe.toString()); } } } Frank Koch 101 URL Application import java.net.*; import java.io.*; public class UrlApplication { public static void main(String[] args) { try { URL theURL = new URL("http://home.zhwin.ch/~kfr/Java/URLTest/UrlText.txt"); InputStream in = theURL.openStream(); DataInputStream data = new DataInputStream(in); String line; while((line = data.readLine()) != null) { System.out.println(line); } } catch(IOException e) {System.out.println(e);} } } Frank Koch 102 URL Applet (1/3) 1. Das angestrebte Resultat (Web-Server-File wird in Applet angezeigt) 2. Einloggen über den FTP-Client auf den Web-Server 3. Aufladen der Files über den FTP-Client auf den Web-Server Frank Koch 103 URL Applet (2/3) import import import import import import import java.awt.*; java.io.DataInputStream; java.io.BufferedInputStream; java.io.IOException; java.net.URL; java.net.URLConnection; java.net.MalformedURLException; public class UrlApplet extends java.applet.Applet implements Runnable { Thread runner; URL theURL; TextArea ta = new TextArea("Getting my text ..."); public void init() { setLayout(new GridLayout(1, 1)); String url = "http://home.zhwin.ch/~kfr/Java/URLTest/UrlText.txt"; try {this.theURL = new URL(url);} catch(MalformedURLException e) {System.out.println("Bad URL: " + theURL);} add(ta); } public Insets insets() { return new Insets(10, 10, 10, 10); } public void start() { if (runner == null) { runner = new Thread(this); runner.start(); } } public void stop() { if (runner != null) { runner.stop(); runner = null; } } Frank Koch 104 public void run() { URLConnection conn = null; DataInputStream data = null; String line; StringBuffer buf = new StringBuffer(); try { conn = this.theURL.openConnection(); conn.connect(); ta.setText("Connection opened ..."); data = new DataInputStream(conn.getInputStream()); ta.setText("Reading data ..."); while ((line = data.readLine()) != null) { buf.append(line + "\n"); } ta.setText(buf.toString()); } catch (IOException e) { System.out.println("IO Error:" + e.getMessage()); } } } Frank Koch 105 Client/Server mit Sockets Server Client Socket Socket Bind Listen Accept(s) Connection establishment In/Out Close Frank Koch Netzwerk Connect In/Out Close 106 Client/Server mit Sockets Initialisierung Server: Für die Implementation eines Server stellt Java die Klasse ServerSocket zur Verfügung. Durch eine Instanzierung eines solchen Sockets werden bereits die Methoden Socket.open(), bind() und listen() ausgeführt. ServerSocket listenSocket = new ServerSocket(PortID); Accept, In/Out sowie das Schliessen eines Socket müssen vom Programmierer ausgelöst werden. Socket clientSocket = listenSocket.accept(); .... listenSocket.close(); Initialisierung Client: Der Client benutzt die Klasse Socket. Sie vereinigt die Aktionen Socket.open() und connect() bei der Instanzierung. Socket s = new Socket(Hostname, RemotePort); Der eigene Port des Clients wir per default immer dynamisch von der Runtime vergeben. Geschlossen wird dieses Socket wie beim Server mit: s.close(); Kommunikation: Die Kommunikation der beiden Prozesse erfolgt in der Aktion In/Out. Diese müssen bei der Initialisierung der Verbindung zuerst erstellt werden. Client : DataInputStream in = new DataInputStream(s.getInputStream()); PrintStream out = new PrintStream(s.getOutputStream()); Server : DataInputStream in = new DataInputStream(clientSocket.getInputStream()); PrintStream out = new PrintStream(clientSocket.getOutputStream()); Beispiel: Nachstehend die Ausgabe des Client/Server Pgms auf den nächsten Seiten. Der Client liest von der Standardeingabe ganze Zeilen ein und übermittelt sie dem Server. Der Server dreht jeden erhaltenen String um und schickt ihn an den Client zurück. Die gedrehten Zeilen werden danach vom Client wieder ausgegeben. > java Server Server: listening on port 8001 Press enter to stop the server > java Client 127.0.0.1 8001 Connected to localhost/127.0.0.1 : 8001 > Hallo ollaH > Frank Koch 107 Client/Server Beispiel (Server (1/2)) import java.io.*; import java.net.*; public class Server extends Thread { public final static int DEFAULT_PORT = 8001; protected int port; protected ServerSocket listen_socket; // Exit with an error message, when an exception occurs. public static void fail(Exception e, String msg) { System.err.println(msg + ": " + e); System.exit(1); } // Create a ServerSocket to listen for connections on; public Server(int port) { start the thread. if (port == 0) port = DEFAULT_PORT; this.port = port; try { listen_socket = new ServerSocket(port); } catch (IOException e) { fail(e, "Exception creating server socket"); } } System.out.println("Server: listening on port " + port); this.start(); public void run() { try { } while(true) { // save the copy of the new created socket Socket client_socket = listen_socket.accept(); // Start workerthread Connection c = new Connection(client_socket); } } catch (IOException e) { fail(e, "Exception while listening"); } // Start the server up, listening on an optionally specified port public static void main(String[] args) { int port = 0; if (args.length == 1) { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { port = 0; } } // Start a server by creating its instance Server s = new Server(port); } } Frank Koch System.out.println("Press enter to stop the server"); try { int i = System.in.read(); } catch ( IOException e) { System.err.println(e); } System.out.println("Client Shutdown"); s.stop(); System.exit(0); 108 Client/Server Beispiel (Server (2/2)) // This class is class Connection protected protected protected the thread that handles all communication with a client extends Thread { Socket client; DataInputStream in; PrintStream out; // Initialize the streams and start the thread public Connection(Socket client_socket) { } client = client_socket; try { in = new DataInputStream(client.getInputStream()); out = new PrintStream(client.getOutputStream()); } catch (IOException e) { try { client.close(); } catch (IOException e2) {}; System.err.println("Exception while getting socket streams: " + e); return; } this.start(); // Provide the service. // Read a line, reverse it, send it back. public void run() { String line; StringBuffer revline; int len; try { while(true) { // read in a line line = in.readLine(); if (line.compareTo("") == 0) { System.out.println("Client Shutdown"); break; } len = line.length(); revline = new StringBuffer(len); for(int i = len-1; i >= 0; i--) revline.insert(len-1-i, line.charAt(i)); // and write out the reversed line out.println(revline); } } catch (IOException e) { System.err.println(e); } finally { try { } } Frank Koch } client.close(); } catch (IOException e2) {}; 109 Client/Server Beispiel (Client) import java.io.*; import java.net.*; public class Client { // see ports under c:\windows\service public static final int DEFAULT_PORT = 8001; public static void usage() { System.out.println("Usage: java Client <hostname> [<port>]"); System.exit(0); } public static void main(String[] args) { int port = DEFAULT_PORT; Socket s = null; String line; if ((args.length != 1) && (args.length != 2)) Client.usage(); if (args.length == 1) port = DEFAULT_PORT; else { try { port = Integer.parseInt(args[1]); } catch (NumberFormatException e) { usage(); } } try { s = new Socket(args[0], port); // hostname:port DataInputStream sin = new DataInputStream(s.getInputStream()); PrintStream sout = new PrintStream(s.getOutputStream()); // Create a stream for reading lines of text from the console DataInputStream in = new DataInputStream(System.in); System.out.println("Connected to " + s.getInetAddress() + " : "+ s.getPort()); while(true) { System.out.print("> "); System.out.flush(); } } } } Frank Koch // print a prompt // read a line from the console, empty line means exit line = in.readLine(); if ( line.compareTo("")==0 ) { System.out.println("Client Shutdown"); sout.println(line); break; } sout.println(line); line = sin.readLine(); if (line == null) { System.out.println("Connection closed by server."); break; } System.out.println(line); catch (IOException e) { System.err.println(e); } // Always be sure to close the socket finally { try { if (s != null) s.close(); } catch (IOException e2) {}; } 110 Übung POP3-MailClient Nutzen wir das erarbeitete Wissen um einen POP3-MailClient zu erstellen. Der POP3-Server befindet sich gewöhnlich auf dem Port 110. Nachstehend finden Sie die POP3-Befehle, die Sie vom Client an den POP3MailServer senden können. user <pop user> pass <password> quit list top <msg no> <n> dele <msg no> retr <msg no> Für das Connect zum Server: z.B. user kfr. Für das Connect zum Server: z.B. pass geheimnis. Beenden der Verbindung zum Server. Listet wartende Mails mit Nummer und Grösse. Ausgabe des Headers sowie der ersten n Zeilen eines Mails. Das Ende der Ausgabe wird mit einem Punkt auf einer separaten Zeile indiziert. Löschen eines Mails (Das Mail wird nur markiert und erst nach "quit" wirklich gelöscht). Runterladen des kompletten Mails. Schreiben Sie einen MailClient, mit dem Sie Ihre Mails auf dem MailServer ansehen können. Frank Koch 111 SMTP und FTP Services Zur Komplettierung finden Sie nachstehend die Befehlstabellen zu weiteren Services. SMTP (Wellknown Port 25) HELO <client name> Anforderung einer Verbindung; Authentifizierung ist nicht notwendig. MAIL FROM:<mail address> Absenderdaten RCPT TO:<mail address> Empfängerdaten DATA Nachrichtentext (Darin muss der eigentliche Header mit allen Angaben über Subject usw. angegeben werden). Abschluss durch: Leerzeile Punkt Leerzeile. QUIT Beenden der Verbindung. FTP (Wellknown Port 21) USER <user name> PASS <password> CWD <directory> RETR <filename> QUIT Frank Koch Für das Connect zum Server. Für das Connect zum Server. Verzeichnis auf dem Server wechseln Datei holen Beenden der Verbindung zum Server. 112 JDBC – Lokaler DB-Zugriff Mit JDBC hat Sun einen Standard definiert, um aus Java-Programmen heraus auf relationale Datenbanken zugreifen zu können. Das Akronym steht für Java Database Connectivity und stellt ein API mit einer Reihe von Klassen, Interfaces und Methoden zur Verfügung, deren sich der Programmierer bedienen kann. Zwei Besonderheiten zeichnen JDBC aus: • Der Datenbankzugriff erfolgt unabhängig von verwendeten Datenbanksystem. • Alle DBMS-spezifischen Details übernimmt ein JDBC-Treiber. Er ist in Java geschrieben und wird von den DB-Herstellern angeboten. Mittels einer JDBC-ODBC-Bridge kann via JDBC auch auf jede ODBCDB zugegriffen werden. Mehr Informationen hierzu finden Sie in dem ausgeteilten Kapitel 2 „JDBC in der Praxis“. Installationsanleitung: 1) Speichern Sie kfr.mdb auf Ihrem lokalen Rechner 2) Registrieren Sie kfr.mdb in ODBC unter dem Namen javatesterlocal. Unter NT und XP öffnen Sie hierzu die Systemsteuerung/Verwaltung und klicken doppelt auf as Icon "ODBC", unter Umständen mit dem Zusatz "32". Im erscheinenden Fenster wählen Sie die Registrierkarte "System", klicken auf "Hinzufügen", "MS Access Treiber". Unter "Datenquellennamen" geben Sie den Namen an, unter dem die Datenbank später von Java aus zugreifbar ist. Wir wollen Sie hier "javatesterlocal" nennen. Klicken Sie nun auf "Auswählen" und suchen Sie die frisch abgespeicherte Datenbank "kfr.mdb". Klicken Sie auf OK und die Datenbank ist registriert. 3) Modifizieren Sie ..\Src\Jdbc\Adressen.java für den lokalen Zugriff (siehe im Code) Frank Koch 113 JDBC - Elementare JDBC Befehle import java.sql.*; // Laden des Treibers JDBC-ODBC-Bridge Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Connect to DB // ODBC Registrierung "javatesterlocal" String url = "jdbc:odbc:javatesterlocal "; Connection connection = DriverManager.getConnection(url,"admin",""); // Aufbereitung und Ausführung einer SQL-Anweisung Statement s = connection.createStatement(); Resultset r = s.executeQuery("SELECT * FROM Adressen"); // Abfragen von DB-Metadaten DatabaseMetaData meta = connection.getMetaData(); System.out.println(meta.getDriverName()); System.out.println(meta.getDriverVersion ()); System.out.println(meta.getURL ()); // Lesen der Zeilen bis EOF while(r.next()) { // Erstes Feld System.out.println(r.getString(1)); // Zweites Feld System.out.println(r.getString(2)); ... } // Schliessen des Zugriffs r.close(); s.close(); connection.close(); Frank Koch 114 JDBC – Remote DB-Zugriff Mit der JDBC-ODBC-Bridge kann auch auf Datenbanken zugegriffen werden, die sich im Netzwerk oder Internet befinden. Für diese Übung steht uns auf dem Linux Server 160.85.169.102 die MySQL Datenbank „javatester“ zur Verfügung. Wir können auf diese Datenbank unter der UserID „student“ sowie dem Passwort „student“ zugreifen. Die Datenbank beinhaltet u.a. den Table „Adressen“. Weitere Angaben finden Sie in der Datei ..\Src\JDBC\installation.txt. Zwei Szenarien sind möglich: ODBC-Treiber befindet sich auf dem Abfrage-Client: • Der ODBC-Treiber http://www.mysql.com/Downloads/MyODBC/myodbc-2.50.39-nt.zip ist auf der lokalen Maschine zu installieren. Sie finden diesen Treiber auch unter Src\Downloads\Tools. • Registrieren Sie die MySQL-DB in dem neuen ODBC-Treiber unter dem Namen „wf_javadsn“. Die Zugangsdaten für den ODBC-Eintrag in unserem Beispiel sind: o Windows DSN Name: wf_java o MySQL host: 160.85.169.102 o MySQL database name: javatester o User: student o PW: student o Port: 3306 • Modifizieren Sie Adressen.java für den Remote Zugriff (siehe Kommentare im Code). • Alternativ können Sie die MySQL-DB auch mit dem MySQL-FrontEnd http://www.mysql.com/Downloads/ MySQL-Front_2.2_Setup.exe ansehen. Sie finden dieses Programm auch unter Src\Downloads\Tools. • Alternativ können Sie die MySQL-DB auch über Access einsehen, indem sie dort die ODBC-Quelle „javatesterremote“ zugreifen. ODBC-Treiber befindet sich auf dem DB-Server: • Auf dem Linux-Server ist bereits ein ODBC-Treiber installiert. • JDataConnect_2201.zip ist auf der lokalen Maschine zu installieren. Sie finden diesen Treiber auch unter Src\Downloads\Tools. • Zugriffe erfolgen direkt aus Java. Frank Koch 115 Übung JDBC und AWT Erstellen Sie ein Java-Pgm, dass mittels eines GUI die folgenden Operationen für unsere kfr-DB erlaubt: • Abfragen vorhandener Sätze • Einfügen neuer Sätze • Ändern bzw. Mutieren bestehender Sätze • Löschen bestehender Sätze Frank Koch 116 CGI (1/7) Greift man mit einem Browser auf einen Web-Server zu, so haben wir es mit einer Web-spezifischen Form der Client/Server-Programmierung zutun. Wir wollen nun den Fall betrachten, wenn dem Benutzer am HTMLClient Daten bereitgestellt werden sollen, die sich in einer DB auf der Server-Seite befinden. Wir benutzen nochmals unsere DB kfr.mdb aus den Schritten 2 und 3 zuvor. Den restlichen Code finden Sie auch unter ..\Src\CGI. Schritt 1: Wir erstellen die HTML-Abfragemaske CGITest.html für den Client. In diesem Bsp soll nach einem PLZ-Bereich gesucht werden können. <HTML> <HEAD> <TITLE>Adress-Suche</TITLE> </HEAD> <BODY> <H1>Adresssuche</H1> <P> Bitte den Postleitzahlenbereich der gew&uuml;nschten Adressen eingeben! </P> <FORM METHOD="POST" ACTION="/kfr/CGITest/CGITest.bat"> <P> Von <INPUT TYPE="text" NAME="VON" VALUE="00000" SIZE=5> bis <INPUT TYPE="text" NAME="BIS" VALUE="99999" SIZE=5> </P> <P> <INPUT TYPE="submit" VALUE="Abschicken!"> </P> </FORM> </BODY> </HTML> Mit der Zeile <FORM METHOD="POST" ACTION="/kfr/CGITest/CGITest.bat"> werden die URL des Clients sowie alle Daten, die der Benutzer in das Formular eingegeben hat ("Query-String") an den Web-Server übermittelt. Zur Verarbeitung dieser Daten startet der Web-Server dann in einem eigenen Prozess das CGI-Skript „CGITest.bat“, dem er die URL und den Query-String über die Standardeingabe (stdin) zur Verfügung stellt. Dieses CGI-Skript läuft auf der Server-Maschine und befindet sich bei uns im Verzeichnis CGITest. Frank Koch 117 CGI (2/7) Schritt 2: Nun erstellen wir das CGI-Script. Damit das CGI-Skript weiss, wieviele Daten es über die Standardeingabe (stdin) einlesen soll, wird ihm die Anzahl Bytes durch den Web-Server über die Umgebebungsvariable CONTENT_LENGTH mitgeteilt. Ein solches CGI-Skript kann in einer Vielzahl Sprachen formuliert werden, z.B. UNIX-Skript, DOS-Batch, PERL, C, Visual Basic und natürlich Java. Java hat den Vorteil, dass es portabel ist; kann aber gerade deshalb nicht auf die Umgebebungsvariable CONTENT_LENGTH zugreifen. Wir brauchen daher neben dem Java-Pgm (hier CGITest.java) ein kleines Wrapper-Skript (hier CGITest.bat), @echo off java Adressen "%CONTENT_LENGTH%" dass die Umgebungsvariable ausliest und dem Java-Pgm als Parameter liefert. Weiterhin startet das Wrapper-Skript den Java-Interpreter, der die Klasse CGITest.class startet. Das Java-Pgm liest nun den Query-String über stdin ein und erhält daraus die vom Benutzer eingegebenen Parameter. In diesem Beispiel werden die Parameter als Suchkriterien für einen JDBC-Zugriff benutzt. Das Java-Pgm generiert nun eine Ausgabe im HTML-Format auf die Standardausgabe (stdout). Der wartende WebServer nimmt diese Ausgabe als HTML-Seite an und sendet diese an den wartenden Client retoure. Anmerkung: Das Beispiel wurde so vorbereitet, dass es sowohl mit als auch ohne Web-Server lauffähig ist. Das abgedruckte Skript enthält beide Varianten, wobei die „mit-Server“-Variante auskommentiert ist. Frank Koch 118 CGI (3/7) import java.sql.*; import java.io.*; // // // // Standard CGI-Skript, liest einen Parameter (die Länge des Parameterstrings) sowie den Parameterstring über Stdin und gibt dieses aus. Weiterhin werden die Systemvariablen von Java ausgegeben. public class Adressen { static String query_string; // HTML-Kopf ausgeben static void htmlhead() { System.out.println("Content-type: text/html"); System.out.println(""); System.out.println("<HTML>"); System.out.println("<HEAD>"); System.out.println("<TITLE>CGI-Test</TITLE>"); System.out.println("</HEAD>"); System.out.println("<BODY>"); } // HTML-Seite abschließen static void htmlfoot() { System.out.println("</BODY>"); System.out.println("</HTML>"); } // Parameter aus CGI-String auslesen static String getParameter(String name) { String backstring; // Extrahiert aus der globalen Variable query_string // den Eintrag "name" und gibt den Inhalt zurück. // "=" an name hängen name = name + "="; int i; for (i = 0; (i < query_string.length() - name.length()) && !(name.equalsIgnoreCase( query_string.substring(i, name.length() + i))); i++); Frank Koch 119 CGI (4/7) // Ist Name gefunden worden? if (i < query_string.length() - name.length()) { // Ja -> in "backstring" ablegen backstring = query_string.substring (i + name.length ()); if (backstring.indexOf("&") >= 0) backstring = backstring.substring (0, backstring.indexOf("&")); } else { // Nein, leeren String ablegen backstring = ""; } // Nun noch falsche Zeichen ersetzen // erst alle "+" in Leerzeichen backstring = backstring.replace('+', ' '); // Nun Unicode-Zeichen i = 0; while (i < backstring.length ()) { if (backstring.charAt (i) == '%') backstring = backstring.substring(0, i) + (char)Integer.parseInt (backstring.substring(i+1, i+3), 16) + i++; } backstring.substring(i+3); } return backstring; static void cgi_prog() { // Kopf ausgeben htmlhead (); String von = getParameter("VON"); String bis = getParameter("BIS"); // Überschrift ausgeben System.out.println("<H1>Die Resultate der Anfrage " + von + " .. " + bis + " :</H1>"); // zunächst muß der JdbcOdbc-Treiber geladen werden try { Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver"); } catch(Exception e) { System.out.println("<P>Datenbanktreiber nicht gefunden!</P>"); return; } Frank Koch 120 CGI (5/7) // OK, Treiber geladen, nun eine Verbindung herstellen try { Connection verbindung = DriverManager.getConnection("jdbc:odbc:kfrdsn", "admin", ""); // Metadaten beziehen und ausgeben, falls vorhanden DatabaseMetaData metadaten = verbindung.getMetaData(); if (metadaten == null) { System.out.println("<P>Keine Metadaten verfügbar</P>"); } else { System.out.println("<P>Die befragte Datenbank ist " + metadaten.getDatabaseProductName() + "</P>"); System.out.println("<P>Versionsnummer: " + metadaten.getDatabaseProductVersion() + "</P>"); } // Eine Abfrage (query) erstellen Statement query = verbindung.createStatement(); // ... und formulieren... ResultSet ergebnisse = query.executeQuery("SELECT * FROM Adressen WHERE ((PLZ >= " + von.trim() + ") and (PLZ <= "+bis.trim()+ ")) order by name"); // herausfinden, welche Felder welche Tabellenpositionen besitzen int pos_name = ergebnisse.findColumn("Name"); int pos_vorname = ergebnisse.findColumn("Vorname"); int pos_strasse = ergebnisse.findColumn("Strasse"); int pos_plz = ergebnisse.findColumn("PLZ"); int pos_ort = ergebnisse.findColumn("Ort"); int pos_telefon = ergebnisse.findColumn("Telefon"); int pos_fax = ergebnisse.findColumn("Fax"); Frank Koch 121 CGI (6/7) // Und alle Ergebnisse auslesen, in einer Tabelle anzeigen... System.out.println("<TABLE BORDER>"); System.out.println("<TR>"); System.out.println("<TH>Name</TH>"); System.out.println("<TH>Vorname</TH>"); System.out.println("<TH>Stra&szlig;e</TH>"); System.out.println("<TH>PLZ</TH>"); System.out.println("<TH>Ort</TH>"); System.out.println("<TH>Telefon</TH>"); System.out.println("<TH>Fax</TH>"); System.out.println("</TR>"); while(ergebnisse.next()) { System.out.println ("<TR>"); System.out.println("<TD>"+ ergebnisse.getString(pos_name)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_vorname)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_strasse)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_plz)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_ort)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_telefon)+"</TD>"); System.out.println("<TD>"+ ergebnisse.getString(pos_fax)+"</TD>"); System.out.println ("</TR>"); } // und Tabelle schließen System.out.println("</TABLE>"); // Verbindung auflösen verbindung.close (); } catch(Exception e) { // Es ist irgendein Datenbankfehler aufgetreten: genaue Meldung ausgeben System.out.println("<P>Datenbankfehler:</P>"); System.out.println("<PRE>"); System.out.println(e.getMessage ()); e.printStackTrace(System.out); System.out.println("</PRE>"); } // Fuß ausgeben htmlfoot (); } Frank Koch 122 CGI (7/7) public static void main (String args[]) { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!! CODE FÜR VORHANDENEN WEB-SERVER // !!! // Die Länge der übermittelten Daten aus dem // !!! // ersten Parameter auslesen und in die // !!! // Variable content_length schreiben. // !!! int content_length = Integer.parseInt(args[0]); // !!! // einen entsprechend großen Pufferspeicher // !!! // instanziieren // !!! byte buffer[] = new byte[content_length + 1]; // // // // // !!! !!! !!! !!! !!! // // // // // // !!! } !!! catch(IOException e) { !!! System.out.println("Lesefehler"); !!! }; !!! query_string = new String(buffer); !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!! versuchen, die Daten einzulesen (kann nur // bei einem Fehler des Servers oder bei // falscher Übertragungsmethode (GET) // schiefgehen. try { System.in.read(buffer, 0, content_length); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!! CODE FÜR SIMULIERTEN WEB-SERVER query_string = args[1]; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } } cgi_prog(); Anmerkung: Das Beispiel wurde so vorbereitet, dass es sowohl mit als auch ohne Web-Server lauffähig ist. Das abgedruckte Pgm enthält beide Varianten, wobei die „mit-Server“-Variante auskommentiert ist. Frank Koch 123 Servlets Hier: Servlet generiert komplette HTML-Page als Output. Web-Browser 1 7 Web-Server 2 6 Servlet-Engine 3 5 Servlet-Klasse 4a Netzwerk 4b FileSystem Legende: 1) Browser: http-Request aus Browser (z.B. http://ServerName/servlets/FirstServlet). 2) Web-Server: Anhand „fehlender“ Extension wird Servlet erkannt und der Request an die Servlet-Engine weitergegeben. 3) Servlet-Eingine: Ruft die Servlet-Klasse auf 4) Servlet-Klasse kann nun auf die Hostressourcen (z.B.: Netzwerk, File-System) zugreifen. 5) Die Servlet-Klasse generiert HTML-Output und gibt diesen an Servlet-Eingine zurück. 6) HTML wird an Web-Server weitergereicht. 7) HTML wird an Web-Browser weitergereicht. Frank Koch 124 Servlets Hier: Servlet generiert einen Teil der HTML-Page als Output. Web-Browser 1 9 Web-Server 2 Servlet-Engine 4 3 7 8 JSSI 6 Servlet-Klasse 5a Netzwerk 5b FileSystem Legende: 1) Browser: http-Request aus Browser (z.B. http://ServerName/servlets/FirstJSSI.jhtml). 2) Web-Server: Anhand .jhtml Extension wird Servlet erkannt und der Request an den JSSI-Parser weitergegeben. 3) JSSI parst die Servlet-Befehle heraus und gibt diese an die Servlet-Engine weiter. 4) Servlet-Eingine: Ruft die Servlet-Klasse auf 5) Servlet-Klasse kann nun auf die Hostressourcen (z.B.: Netzwerk, File-System) zugreifen. 6) Die Servlet-Klasse generiert HTML-Output und gibt diesen an Servlet-Eingine zurück. 7) HTML wird an JSSI weitergereicht. 8) JSSI ersetzt die Servlet-Befehle gegen das generierte HTML und gibt ein HTML-File an den Web-Server zurück. 9) HTML wird an den Web-Browser weitergereicht. Frank Koch 125 Servlets (Installation) ACHTUNG: Nehmen Sie diese Installation NICHT in der Schule vor !!! Nachstehend die Reihenfolge sowie Kommentare zur Installation: • HTTP-Server: z.B.: Apache 1.1.9 oder höher (hier 1.3.11) (apache_1_3_11_win32.exe) • Installieren • C:\Programe\Apache Group\Apache\conf\httpd.conf editieren. Evtl ‚#‘ vor „servername“ entfernen (Eintrag unter servername spielt hier keine Rolle). • Test: Apache starten und im Browser den Rechnernamen bzw die IPNummer eingeben. Bei Erfolg erscheint Apache-Startseite im Browser. • JDK1.2 (falls noch nicht installiert): (jdk1_2_2-001-win.exe und jdk1_2_2-001doc.zip) • Java Servlet Development Kit 2.0 (jsdk20-win32.exe). Klassenpakete für das Kompilieren der Servlets. • • Installieren • Web-Server runterfahren und neu starten. Apache Servlet Engine: Vor installieren von ApacheJServ unbedingt JSDK2.0 installieren. ApacheJServ am Besten mit jdk1.1.8 verwenden. Es gibt Probleme mit der CLASSPATH Variablen im jdk1.2 (ApacheJServ-1_1.exe) • • • Installieren (Pfadnamen müssen eingegeben werden) • Java Virtual Machine: c:\jdk1.2.2\bin • JSDK: c:\jsdk2.0 Bestätigen, dass Installationsskript das Apache-Konfigurationsfile aktualisieren soll. Apache JSSI Parser: (ApacheJSSI-1_1_2.zip) Frank Koch 126 Servlets (FirstServlet) KofFirstServlet.java import import import import import java.io.PrintWriter; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; public class KofFirstServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>FirstServlet</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("<H1>FirstServlet</H1>"); out.println("</BODY>"); out.println("</HTML>"); out.close(); } } // // // // // // // Nachfolgend für JSSI-Beispiel response.setContentType("text/html"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); PrintWriter out = response.getWriter(); out.println("<H1>Hello World</H1>"); out.close(); • Speicherort: c:\Programme\Apache Jserv 1.1\servlets\FirstServlet.class • Aufruf über: http://ServerName/servlets/KofFirstServlet (Der WebServer erkennt anhand der fehlenden Extension, dass der Aufruf an die Servlet-Engine weitergeleitet werden muss. • Der vom Servlet generierte HTML-Output wird an den wartenden WebServer zurückgegeben. Frank Koch 127 Servlets (FileReadServlet) KofFileReadServlet.java import import import import import import import import import java.io.IOException; java.io.BufferedReader; java.io.FileReader; java.io.IOException; java.io.PrintWriter; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; public class KofFileReadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>FileReadServlet</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); readFile(out); out.println("</BODY>"); out.println("</HTML>"); } private void readFile(PrintWriter out) throws IOException { String file= ("c:/programme/apache jserv 1.1/servlets/text.txt") } } BufferedReader reader = new BufferedReader( new FileReader(file)); String line = reader.readLine(); while(line != null) { out.println(line); out.println("<BR>"); line = reader.readLine(); } • Speicherort: c:\Programme\Apache Jserv 1.1\servlets\FileReadServlet.class • Aufruf über: http://ServerName/servlets/KofFileReadServlet Frank Koch 128 Servlets (DBReadServlet) KofDBReadServlet.java import import import import import import import import import import java.io.IOException; java.io.PrintWriter; java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement; javax.servlet.ServletException; // Kawa Classpath siehe unten javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; public class KofDBReadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>KofDataBaseReadServlet</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); readFromDataBase(out); out.println("</BODY>"); out.println("</HTML>"); } private void readFromDataBase(PrintWriter out) throws IOException { try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:kfrdsn"; Connection c = DriverManager.getConnection(url, "", ""); Statement s = c.createStatement(); out.println("<TABLE BORDER=\"1\">"); out.println("<TR>"); out.println("<TD>Vorname</TD>"); out.println("<TD>Nachname</TD>"); out.println("<TD>email</TD>"); out.println("</TR>"); ResultSet rs = s.executeQuery("select * from Emails"); while(rs.next()) { out.println("<TR>"); out.println("<TD>" + rs.getString("vorname") + "</TD>"); out.println("<TD>" + rs.getString("nachname") + "</TD>"); out.println("<TD>" + rs.getString("email") + "</TD>"); } } out.println("</TR>"); } out.println("</TABLE>"); rs.close(); s.close(); c.close(); } catch(Exception ex) {} • Kawa: Menü • Speicherort: c:\Programme\Apache Jserv 1.1\servlets\DBReadServlet.class • Aufruf über: http://ServerName/servlets/KofDBReadServlet Frank Koch Packages Classpath Eintrag: C:\JSDK2.0\lib\jsdk.jar 129 Servlets (Email-Suche) EmailSuche.html <HTML> <HEAD> <TITLE>Email-Suche</TITLE> </HEAD> <BODY> <H1>Email Suche</H1> Bitte geben Sie Vor- und/oder Nachname bzw. Teile davon ein.<BR> <FORM ACTION="servlets/KofEmailFromDataBaseServlet" METHOD="GET"> Vorname:<BR> <INPUT TYPE="TEXT" SIZE="20" NAME="Vorname"><BR> Nachname:<BR> <INPUT TYPE="TEXT" SIZE="20" NAME="Nachname"><BR> <INPUT TYPE="SUBMIT" VALUE="Suche starten" NAME="b"> </FORM> </BODY> </HTML> KofEmailFromDataBaseServlet.java import import import import import import import import import import java.io.IOException; java.io.PrintWriter; java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; public class KofEmailFromDataBaseServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Suchergebnis</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); readFromDataBase(request, out); out.println("</BODY>"); out.println("</HTML>"); } private void readFromDataBase(HttpServletRequest request, PrintWriter out) { Connection connection = null; Statement statement = null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:kfrdsn"; connection = DriverManager.getConnection(url, "", ""); statement = connection.createStatement(); out.println("<TABLE BORDER=\"1\">"); out.println("<TR>"); out.println("<TD>Vorname</TD>"); out.println("<TD>Nachname</TD>"); out.println("<TD>email</TD>"); out.println("</TR>"); ResultSet rs = statement.executeQuery(getSQLRequest(request)); while(rs.next()) { out.println("<TR>"); out.println("<TD>" + rs.getString("vorname") + "</TD>"); out.println("<TD>" + rs.getString("nachname") + "</TD>"); out.println("<TD>" + rs.getString("email") + "</TD>"); out.println("</TR>"); } Frank Koch 130 out.println("</TABLE>"); rs.close(); statement.close(); connection.close(); } catch(Exception ex) { } finally { try { statement.close(); } catch(Exception cEx1){} try { connection.close(); } catch(Exception cEx2){} } } private String getSQLRequest(HttpServletRequest request) { String firstName = request.getParameter("Vorname"); String lastName = request.getParameter("Nachname"); if(((firstName == null) && (lastName == null)) || ((firstName.length() == 0) && (lastName.length() == 0))) { return ""; } if((firstName != null) && (firstName.length() > 0)) { if((lastName != null) && (lastName.length() > 0)) { return searchForFirstAndLastName(firstName, lastName); } else { return searchForFirstName(firstName); } } else { return searchForLastName(lastName); } } private String searchForFirstAndLastName(String firstName, String lastName) { return "select vorname, nachname, email from EmailTs " + "where vorname like '%" + firstName + "%' AND nachname like '%" + lastName + "%'"; } private String searchForFirstName(String firstName) { return "select vorname, nachname, email from Emails " + "where vorname like '%" + firstName + "%'"; } } private String searchForLastName(String lastName) { return "select vorname, nachname, email from Emails " + "where nachname like '%" + lastName + "%'"; } • Kawa: Menü • Speicherort: c:\Programme\Apache Jserv 1.1\servlets\KofEmailFromDataBaseServlet.class • Speicherort: c:\WebServerRoot\KofEmailSuche.html • Aufruf über: http://ServerName/servlets/KofEmailSuche.html Frank Koch Packages Classpath Eintrag: C:\JSDK2.0\lib\jsdk.jar 131 Servlets (Debugging von Servlets) KofDebugEmailFromDataBaseServlet.java import import import import import import import import import import import java.io.IOException; java.io.PrintWriter; java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; tools.servlet.ServletTools; // Für Ausgabe auf JavaConsole public class KofDebugEmailFromDataBaseServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); ServletTools.init(); // Für Ausgabe auf JavaConsole try { PrintWriter out = response.getWriter(); out.println("<HEAD>"); out.println("<TITLE>Suchergebnis</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); readFromDataBase(request, out); out.println("</BODY>"); out.println("</HTML>"); String test = null; test.toUpperCase(); // Hier provozieren wir eine Excpetion } catch(Throwable t) {t.printStackTrace();} // Für Ausgabe auf Console } .... } • Kawa: Menü Packages Classpath Eintrag: C:\Programme\Apache JServ 1.1\servlets\Htmltool.jar • Speicherort: c:\Programme\Apache Jserv 1.1\servlets\DebugEmailFromDataBaseServlet.class • Speicherort: c:\WebServerRoot\servlets/KofDebugEmailSuche.html • Aufruf über: http://ServerName/servlets/KofDebugEmailSuche.html Frank Koch 132 JavaScript (1.1) - Positionierung HTML-Dokumente sind passiv; Interaktion mit dem Benutzer ist nur eingeschränkt möglich. Oft aber sollte der Inhalt des angezeigten Dokuments auf Benutzerreaktinen angepasst werden. Aus diesem Grunde entwickelte Netscape "ActiveScript", das im Dezember 1995 in Zusammenarbeit mit Sun an deren Sprache Java angepasst und in "JavaScript" umgetauft wurde. Java ist ein offener Standard, der von namhaften Softwarehäusern unterstützt wird und zum "de facto-Standard" für interaktive WebPages wurde. JavaScript und HTML JavaScript ermöglicht es Aktionen und Eingaben von Benutzern zu verarbeiten. Es erlaubt die Steuerung des Kontrollflusses, wodurch es möglich wird Algorithmen zu implementieren und die Bearbeitung von HTML-Anweisungen gezielt zu steuern. JavaScript und Java Gemeinsamkeiten: • JavaScript hat Syntax und Sprachelemente weitgehend von Java übernommen. • Java ist eine Allzweck-Pgmiersprache, die sich besonders gut für das Internet eignet. JavaScript wurde speziell für den Einsatz in WWW-Dokumenten entworfen. JavsScript bildet somit eine Teilmenge des Einsatzbereiches von Java. Unterschiede: • Objektorientiert (Java) versus objektbasiert (JavaScript). JavaScript ist eine prozedurale Sprache, die zusätzlich über ein stark eingeschränktes Objektkonzept verfügt und sich auf bestimmte, vordefinierte Objekte beschränkt (keine Vererbung, kein Polymorphismus). • Starke (Java) versus schwache (JavaScript) Typisierung • Komplex (Java) versus einfach (JavaScript) • Kompiliert (Java) versus interpretiert (JavaScript) • Bytecode (Java) versus Einbindung in HTML (JavaScript) Vorzüge von JavaScript • Leicht erlernbar • Kurze Entwicklungszeit • Kompakte Sprache • Plattformunabhängig Nachteile von JavaScript • Beschränktes EInsatzgebiet • Nicht für komplexe Anwendungen geeignet • Nicht für zeitkritische Anwendungen geeignet • Skripte sind Bestandteil der HTML-Pages und für jedermann einsehbar Anmerkung Um JavaScript zu verstehen, hilft es ein wenig über HTML zu wissen. Schauen Sie sich dazu doch einmal die Kursunterlage von Hubert Partl an. Frank Koch 133 JavaScript – Beispiel „BenutzerIO“ <HTML> <HEAD> <META NAME="Author" CONTENT="Frank Koch"> <TITLE>JavaScript BenutzerIO</TITLE> </HEAD> <BODY> <CENTER> <B><FONT SIZE=+4> Guten Tag!<BR> <SCRIPT LANGUAGE="JavaScript"> name = prompt("Wie heissen Sie?", ""); document.write("Hallo " + name + ",<BR>"); document.write("hat mich gefreut, "); document.write("Sie kennenzulernen.<BR>"); </SCRIPT> Auf Wiedersehen! </FONT></B> </CENTER> </BODY> </HTML> Frank Koch 134 JavaScript – Bsp „Diskontierung“ (1/3) Frank Koch 135 JavaScript – Bsp „Diskontierung“ (2/3) <HTML> <HEAD> <META NAME="Author" CONTENT="Frank Koch"> <TITLE>JavaScript Diskontierung</TITLE> </HEAD> <BODY> <CENTER> <B><FONT SIZE=+4> <SCRIPT LANGUAGE="JavaScript"> // Funktionsdefinitionen function berechneZinsen(betrag, zinssatz) { return(betrag * (zinssatz / 100.0)); } function berechneRealenWert(betrag, inflationsrate) { return(betrag / (1.0 + (inflationsrate / 100.0))); } function runden(wert) { return(Math.round(wert * 100.0) / 100.0); } // Eingabevariablen var anfangskapital, zinssatz, inflationsrate, anlagezeitraum; // Variablen zur Kennzeichnung korrekter Eingaben var anfangskapitalOK, zinssatzOK, inflationsrateOK, anlagezeitraumOK; // Variablen für die zu berechnenden Werte var kapital, zinsen, realesKapital, realeZinsen; // Eingabe des Anfangskapitals while(!anfangskapitalOK) { anfangskapital = prompt("Geben Sie das Anfangskapital ein", "0"); anfangskapital = parseFloat(anfangskapital); if ((!isNaN(anfangskapital)) && (anfangskapital >= 0.0)) { anfangskapitalOK = true; } else { alert("Geben Sie ein Zahl grösser oder gleich Null ein"); } } // Eingabe des Zinssatzes while(!zinssatzOK) { zinssatz = prompt("Geben Sie den Zinssatz in % ein", "0"); zinssatz = parseFloat(zinssatz); if ((!isNaN(zinssatz)) && (zinssatz >= 0.0)) { zinssatzOK = true; } else { alert("Geben Sie ein Zahl grösser oder gleich Null ein"); } } Frank Koch 136 JavaScript – Bsp „Diskontierung“ (3/3) // Eingabe der Inflationsrate while(!inflationsrateOK) { inflationsrate = prompt("Geben Sie die Inflationsrate in % ein", "0"); inflationsrate = parseFloat(inflationsrate); if (!isNaN(inflationsrate)) { inflationsrateOK = true; } else { alert("Geben Sie ein Zahl ein"); } } // Eingabe des Anlagezeitraumes while(!anlagezeitraumOK) { anlagezeitraum = prompt("Geben Sie den Anlagezeitraum in Jahren (1..100) ein", "0"); anlagezeitraum = parseFloat(anlagezeitraum); if ((!isNaN(anlagezeitraum)) && (anlagezeitraum >= 1) && (anlagezeitraum <= 100)) { anlagezeitraumOK = true; } else { alert("Geben Sie ein Zahl zwischen 1 und 100 ein"); } } // Werte ausgeben document.write("Anfangskapital: ", runden(anfangskapital), " CHF<BR>"); document.write("Zinssatz: ", runden(zinssatz), " %<BR>"); document.write("Inflationsrate: ", runden(inflationsrate), " %<BR>"); document.writeln("Anlagezeitraum: ", runden(anlagezeitraum), " Jahre<BR>"); // Tabellenkopf document.writeln("<TABLE BORDER>"); document.write("<CAPTION>Wertentwicklung unter Berücksichtigung von"); document.writeln("Verzinsung und Inflation</CAPTION>"); document.write("<TR><TH>Jahre</TH>"); document.write("<TH>Zinsen</TH>"); document.write("<TH>Guthaben</TH>"); document.write("<TH>Tatsächliche Zinsen</TH>"); document.write("<TH>Tatsächliches Guthaben</TH></TR>"); // Werte in der Tabelle realesKapital = kapital = anfangskapital; for(var jahre = 1; jahre <= anlagezeitraum; jahre++) { document.write("<TR><TD>"); document.write(jahre, "</TD><TD>"); zinsen = berechneZinsen(kapital, zinssatz); document.write(runden(zinsen), "</TD><TD>"); kapital += zinsen; document.write(runden(kapital), "</TD><TD>"); realeZinsen = berechneRealenWert(zinsen, inflationsrate); document.write(runden(realeZinsen), "</TD><TD>"); realesKapital += zinsen; realesKapital = berechneRealenWert(realesKapital, inflationsrate); document.writeln(runden(realesKapital), "</TD></TR>"); } document.writeln("</TABLE>"); </SCRIPT> </FONT></B> </CENTER> </BODY> Frank Koch 137 </HTML> Frank Koch 138 JavaScript – Bedeutung für Java Java ist eine Allzweck-Programmiersprache. Alles, was in HTML oder JavaScript möglich ist, könnte man auch in Java realisieren. In der Praxis greift man trotzdem gerne auf HTML und JavaScript zurück, weil sie die Aufgaben, für die sie entwickelt wurden, einfach und schnell lösen können. Beispielsweise kann man mit Java Dialogboxen und Formulare erstellen; der dafür benötigte Aufwand ist jedoch weit grösser als in HTML und JavaScript. Ideal ist es, wenn man diese verschiedenen Entwicklungswerkzeuge je nach deren Stärken einsetzen könnte. Voraussetzung dafür ist, dass sich HTML, JavaScript und Java nahtlos miteinander verbinden lassen. Der "Kitt" zwischen HTML und Java ist JavaScript. In HTMLScript gibt es das applet-Objekt, über das es möglich ist, öffentliche Variablen und Methoden eines durch den applet-Tag eingebundenen Java-Applets anzusprechen. Variablen können sowohl gelesen als auch verändert werden. Die Eigenschaften und Methoden des jeweiligen applet-Objekts hängen dabei von zugehörigen Java-Applet ab. Frank Koch 139 JavaScript – Bsp „AppletLink“ Applet-Teil import java.applet.Applet; import java.awt.Graphics; import java.awt.Font; public class AppletLink extends Applet { Font m_f; int m_size = 12; String m_text = "leer"; public void newText(String text) { m_text = text; repaint(); } public void addSize() { m_size++; m_f = new Font("Arial", 2, m_size); repaint(); } public void init() { m_f = new Font("Arial", 2, m_size); } public void paint(Graphics g) { g.setFont(m_f); g.drawString("Text="+m_text+" Grösse="+m_size,10,50); } } HTML-Teil <HTML> <HEAD> <META NAME="Author" CONTENT="Frank Koch"> <TITLE>JavaScript AppletLink</TITLE> </HEAD> <BODY> <CENTER> <B><FONT SIZE=+4> <APPLET CODE="AppletLink.class" NAME="applet" WIDTH=300 HEIGHT=100> </APPLET> <SCRIPT LANGUAGE="JavaScript"> </SCRIPT> <FORM> <INPUT TYPE="TEXT" NAME="text" VALUE="mein Text" ONCHANGE="applet.newText(value)"> <INPUT TYPE="BUTTON" NAME="button" VALUE="Grösser" ONCLICK="applet.addSize()"> </FORM> </FONT></B> </CENTER> </BODY> </HTML> Frank Koch 140 javadoc • • • javadoc parses the declarations and documentation comments in a set of Java source files and produces a set of HTML pages describing, by default, the public and protected classes, interfaces, constructors, methods, and fields. As an argument to javadoc you pass in either a series of Java package names or source files. javadoc generates one .html file for each .java file and each packages it encounters. In addition, it produces a class hierarchy (tree.html) and an index of those members (AllNames.html). When javadoc parses the class and member delarations, it picks up their signatures for inclusion. In addition, you can add further documentation by including doc comments (masked by /** and */) in the source code. Beispiel: „javadoc.java“ mit javadoc-Comments: /** * My comment for class 'Super': * <pre> * Super s = new Super(); * s.methodeSuper(); * </pre> */ public class Super { public void methodeSuper() {} } /** * My comment for class 'Sub': * <pre> * Sub s = new Sub(); * s.publicMethode(); * </pre> */ public class Sub extends Super { /** * My comment for variable 'publicVariable': */ public int publicVariable; /** * My comment for variable 'privateVariable': */ private int privateVariable; /** * My comment for methode 'publicMethode': * @param void * @return void * @exception no exception */ public void publicMethode() {} private void privateMethode() {} } Erzeugung der Dokumentation: javadoc javadoc.java Frank Koch 141 Reflexion bzw Introspection // Gibt die Methoden einer zuvor unbekannten Klasse //(hier: Random) aus import java.lang.reflect.*; import java.util.Random; class Reflexion { public static void main(String[] arguments) { Random rd = new Random(); // Random wird gewählt Class className = rd.getClass(); Method[] methods = className.getMethods(); for (int i = 0; i < methods.length; i++) { System.out.println("Method: " + methods[i]); } } } Ausgabe: Method: public final native java.lang.Class java.lang.Object.getClass() Method: public native int java.lang.Object.hashCode() Method: public boolean java.lang.Object.equals(java.lang.Object) Method: public java.lang.String java.lang.Object.toString() Method: public final native void java.lang.Object.notify() Method: public final native void java.lang.Object.notifyAll() Method: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException Method: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException Method: public final void java.lang.Object.wait() throws java.lang.InterruptedException Method: public synchronized void java.util.Random.setSeed(long) Method: public void java.util.Random.nextBytes(byte[]) Method: public int java.util.Random.nextInt() Method: public long java.util.Random.nextLong() Method: public float java.util.Random.nextFloat() Method: public double java.util.Random.nextDouble() Method: public synchronized double java.util.Random.nextGaussian() Frank Koch 142 Locale import java.util.Locale; class TestLocale { public static void main(String[] arguments) { Locale l = new Locale("DE", "CH"); System.out.println(l.getCountry()); System.out.println(l.getLanguage()); System.out.println(l.toString()); System.out.println(l.getDisplayLanguage()); System.out.println(l.getDisplayCountry()); System.out.println(l.getDisplayName()); } } Ausgabe: CH De De_CH Deutsch Schweiz Deutsch (Schweiz) Frank Koch 143