Java Dieser Teil führt in das Programmieren mit Java ein. Voraussetzung sind gute C++ Kenntnisse. Es wird gezeigt, wie Java-Programme entwickelt werden und der Unterschied zur C++ wird diskutiert. Am Schluss werden einige charakteristische Java Beispiel-Programme gezeigt. Inhalt 1. Java-Technologie...................................................................................................... 5 1.1. Java-Kode ........................................................................................................... 5 1.2. Java-Plattform ..................................................................................................... 7 2. Programmentwicklung mit Java .................................................................................10 2.1. Anwendungen .....................................................................................................11 2.1.1. Übersetzen von Programmen ..........................................................................12 2.1.2. Anwendungen starten ....................................................................................13 2.1.3. Kommentare ................................................................................................13 2.1.4. Klassendefinition ...........................................................................................13 Arbeiten mit Java Prof.Dr. Alois Schütte 1/65 2.1.5. Die Methode main .........................................................................................14 2.1.6. Verwendung von Klassen und Objekten............................................................17 2.2. Applets ..............................................................................................................17 3. 2.2.1. Import von Klassen und Packages ...................................................................18 2.2.2. Definition einer von Applet abgeleiteten Klasse..................................................21 2.2.3. Implementierung von Applet Methoden ............................................................21 2.2.4. Applet ausführen...........................................................................................22 Unterschied Java und C++ .......................................................................................24 3.1. Variablen ...........................................................................................................24 3.2. Unterschied Wert <--> Referenz ...........................................................................25 3.2.1. Objekte kopieren ..........................................................................................26 3.2.2. Zeiger .........................................................................................................27 3.3. Arrays ...............................................................................................................27 3.3.1. Anlegen von Arrays .......................................................................................28 3.4. Operatoren.........................................................................................................31 3.5. Typkonvertierung ................................................................................................33 Arbeiten mit Java Prof.Dr. Alois Schütte 2/65 3.5.1. Numerische Konvertierungen ..........................................................................33 3.6. Anweisungen (if/else, while und do/while) ..............................................................34 3.7. Garbage Collection ..............................................................................................34 3.8. import-Anweisung ...............................................................................................35 3.9. Subklassen und Vererbung ...................................................................................37 4. 3.9.1. Modifier für Klassen .......................................................................................38 3.9.2. Modifier für Methoden ....................................................................................38 3.9.3. Modifikatoren ...............................................................................................39 3.9.4. Superklassen, Objekte und Klassenhierarchie....................................................39 3.9.5. Subklassen-Konstruktoren..............................................................................39 3.9.6. Abstrakte Klasssen und Schnittstellen ..............................................................41 3.9.7. Schnittstellen ...............................................................................................41 3.9.8. Schnittstellen erweitern .................................................................................42 Java Beispiele .........................................................................................................43 4.1. I/O ....................................................................................................................43 4.1.1. Arbeiten mit Java Übersicht über Streams .................................................................................46 Prof.Dr. Alois Schütte 3/65 4.2. File Streams .......................................................................................................50 4.3. Filter Streams .....................................................................................................53 4.4. Interfaces ..........................................................................................................60 4.4.1. Definition eines Interface ...............................................................................63 4.4.2. Implementierung eines Interface.....................................................................64 Arbeiten mit Java Prof.Dr. Alois Schütte 4/65 1. Java-Technologie Java-Technologie1 ist der Sammelbegriff für die Programmiersprache Java, die Java APIs und die Java Plattform. 1.1. Java-Kode Java ist eine Hochsprache, die durch folgende Begriffe charakterisiert werden kann: objektorientiert robust sicher architekturneutral portabel performant 1 Die Ausarbeitung basiert auf Online Veröffentlichungen von Sun. Arbeiten mit Java Prof.Dr. Alois Schütte 5/65 Java Quellprogramme müssen zunächst übersetzt werden. Dadurch entsteht ein Zwischenkode (Java Bytecode). Dieser plattformunabhängige Kode wird dann in einer Ablaufumgebung vom Bytekode Interpreter der Zielumgebung ausgeführt. Der Bytekode ist „Maschinenkode der Java Virtual Machine“ (Java VM). Durch diesen plattformunabhängigen Bytekode und der Verfügbarkeit der Java VM auf nahezu allen Plattformen (Handy, PC bis zu Mainframe) sind portable Anwendungen realisierbar: Arbeiten mit Java Prof.Dr. Alois Schütte 6/65 1.2. Java-Plattform Eine Plattform ist eine Hardware/Software Umgebung, in der Programme ablaufen können. Die Java Plattform ist eine reine Software Umgebung, die auf einer Hardwareplattform aufsetzt. Die Java Plattform besteht aus: der Java Virtual Machine (Java VM) und dem Java Application Programming Interface (Java API). Das folgende Bild zeigt die Java Plattform: Arbeiten mit Java Prof.Dr. Alois Schütte 7/65 Java wird nicht nur verwendet, um Applets zu realisieren, sondern auch um ServerAnwendungen zu realisieren. Eine Anwendung (im Gegensatz zum Applet) ist ein eigenständiges Programm, das auf der Java-Plattform abläuft. Um sowohl Applets als auch Java Anwendungen realisieren zu können, sind APIs für unterschiedliche Bereiche verfügbar, wie etwa Netzwerkkommunikation, Benutzerschnittstellen, Sicherheit u.v.m. Die folgende Abbildung zeigt die wesentlichen Bestandteile des Java Software Development Kits (SDK). Arbeiten mit Java Prof.Dr. Alois Schütte 8/65 Arbeiten mit Java Prof.Dr. Alois Schütte 9/65 2. Programmentwicklung mit Java Zunächst betrachten wir die Entwicklung einer Anwendung, dann wird gezeigt, wie Applets programmiert werden können. Die Entwicklung wird gezeigt an der „klassischen“ Hello World Anwendung. Anwendung: Arbeiten mit Java Prof.Dr. Alois Schütte 10/65 Applet im Browser: 2.1. Anwendungen Am Beispiel eines HelloWorld Programms wird die Entwicklung einer Java Anwendun zeigt. Arbeiten mit Java Prof.Dr. Alois Schütte g ge- 11/65 $ cat helloWorld.java /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class helloWorld { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } $ 2.1.1. Übersetzen von Programmen Das Java-Programm wird mit dem Java-Compiler javac übersetzt: $ ls -l -rw------1 as $ javac helloWorld.java $ ls -l -rw------1 as -rw------1 as $ users 269 Mär 14 13:51 helloWorld.java users users 429 Mär 14 13:54 helloWorld.class 269 Mär 14 13:51 helloWorld.java Es entsteht eine Datei mit Namen helloWorld.class. helloWorld ist der Name der Klasse in der Quelldatei, .class zeigt, dass es sich um Bytekote handelt. Arbeiten mit Java Prof.Dr. Alois Schütte 12/65 2.1.2. Anwendungen starten Durch den Java-Interpreter java kann die Anwendung gestartet werden. Das Argument von java ist die Klasse, die „Startmethode“ main enthält. $ java helloWorld Hello World! $ 2.1.3. Kommentare In Java sind Kommentare in C++ Art möglich: $ cat helloWorld.java /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class helloWorld { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } $ 2.1.4. Klassendefinition In Java ist jede Methode (Funktion) und jede Variable Bestandteil einer Klasse oder eines Objektes (Exemplar einer Klasse). Globale Funktionen oder Variablen sind nicht erlaubt. Arbeiten mit Java Prof.Dr. Alois Schütte 13/65 Die Klassendefinition in der einfachsten form ist class name { …} $ cat helloWorld.java /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class helloWorld { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } $ Eine Klassedefinition beschreibt Daten und das Verhalten von Objekt-Exemplaren der Klasse. Wenn eine Klasse instanziiert wird, wird ein Objekt erzeugt, dass sich so verhält, wie es die Klassendefinition vorsieht. Daten der Klasse werden in Variablen abgelegt, das Verhalten wird durch Methoden beschrieben. Die Klasse helloWorld hat keine Daten. Sie besitzt eine Methode mit Namen main. 2.1.5. Die Methode main Der Ausgangspunkt für Java Anwendungen ist die Methode main. Der Java-Interpreter startet als erstes die Methode main, von wo aus dann alle anderen Aktivitäten gestartet werden. Arbeiten mit Java Prof.Dr. Alois Schütte 14/65 $ cat helloWorld.java /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class helloWorld { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } $ Die Methode main hat folgendes Aussehen: public static void main(String[] args) Die Methodensignatur enthält drei Modifikatoren: public definiert, dass main von allen Objekten aufrufbar ist. static definiert main als Klassenmethode void besagt, dass main keinen Rückgabewert hat. Arbeiten mit Java Prof.Dr. Alois Schütte 15/65 Die Argumente von main, also die Kommandozeilen-Parmeter werden in einem Array von Strings abgelegt. Das Beispielprogramm hat keine Parameter. Achtung (Unterschied zu C++) args ist ein Array von Strings, wobei der Programmname nicht enthalten ist. Die Verwendung von Kommandozeilenargumenten zeigt folgendes Beispiel (echo): $ cat echo.java public class echo { public static void main (String[] args) { for (int i = 0; i < args.length; i++) System.out.print(args[i] + " "); System.out.println(); } } $ Wenn numerische Kommandozeilenargumente verwendet werden sollen, so ist der String zu konvertieren, etwa durch: int firstArg; if (args.length > 0) firstArg = Integer.parseInt(args[0]); Arbeiten mit Java Prof.Dr. Alois Schütte 16/65 2.1.6. Verwendung von Klassen und Objekten Das HelloWorld-Programm ist ein einfaches Programm, es enthält keine weiteren Klassendefinitionen. Das Programm verwendet eine Klasse System, die zu einem API der Java-Plattform gehört. $ cat helloWorld.java /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class helloWorld { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } $ System.out ist der volle Name der Variablen out der Klasse System. Wenn die Klasse System geladen wird, so wird ein PrintStream-Objekt erzeugt und der Variablen out zugewiesen. Dadurch kann die Methode println dieses Objektes aufgerufen werden. 2.2. Applets Applets werden von einem Browser aus aufgerufen. Der Java-Kode für das Hello World Applet ist ebenfalls einfach: Arbeiten mit Java Prof.Dr. Alois Schütte 17/65 $ cat helloWorldApplet.java import java.applet.Applet; import java.awt.Graphics; /** * The helloWorldApplet class implements an applet that * simply displays "Hello World!". */ public class helloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } $ 2.2.1. Import von Klassen und Packages $ cat helloWorldApplet.java import java.applet.Applet; import java.awt.Graphics; /** * The helloWorldApplet class implements an applet that * simply displays "Hello World!". */ public class helloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } Arbeiten mit Java Prof.Dr. Alois Schütte 18/65 $ Die beiden ersten Zeilen importieren die Klassen Applet und Graphics. Ohne die beiden Zeilen würde das Applet auch funktionieren, wenn man den Kode wie folgt erweitert: public class helloWorldApplet extends java.applet.Applet { public void paint(java.awt.Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } Durch das Importieren kann man also Klassen ohne vollen Namen angeben zu müssen verwenden. Das Package java.applet beinhaltet die speziell für Applets erforderlichen Klassen; java.awt (abstract window toolkit) ist eine Sammlung von Klassen zu Realisierung von graphischen Benutzerschnittstellen. Wenn das gesamte Package importiert werden soll, also nicht nur eine Klasse, so kann man den Platzhalter „*“ verwenden: Arbeiten mit Java Prof.Dr. Alois Schütte 19/65 $ cat helloWorldApplet.java import java.applet.*; import java.awt.*; /** * The helloWorldApplet class implements an applet that * simply displays "Hello World!". */ public class helloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } $ Jede Klasse in Java ist Bestandteil eines Package. Ein Package ist eine Menge von Klassen und Interfaces, wodurch Zugriffsschutz und Namensräume geregelt werden. Wenn ein Programm nicht explizit eine package-Anweisung am Anfang enthält, so gehört die Klasse zum Default Package (so wie in unserem Hello World Beispiel). Arbeiten mit Java Prof.Dr. Alois Schütte 20/65 2.2.2. Definition einer von Applet abgeleiteten Klasse $ cat helloWorldApplet.java import java.applet.*; import java.awt.*; /** * The helloWorldApplet class implements an applet that * simply displays "Hello World!". */ public class helloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } $ Jedes Applet muss eine Klasse enthalten, die von der Klasse Applet abgeleitet ist. Dadurch erben sie die Eigenschaften, die zur Kommunikation mit Browsern erforderlich sind. Durch das Schlüsselwort extends wird ausgedrückt, dass die Klasse helloWorldApplet von der Klasse Applet abgeleitet ist. Wenn ein Browser ein Applet lädt, wird die Klasse initialisiert, die von Applet abgeleitet wurde. 2.2.3. Implementierung von Applet Methoden Jedes Applet muss mindestens eine der Methoden init, start oder paint beinhalten. Arbeiten mit Java Prof.Dr. Alois Schütte 21/65 $ cat helloWorldApplet.java import java.applet.*; import java.awt.*; /** * The helloWorldApplet class implements an applet that * simply displays "Hello World!". */ public class helloWorldApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); // Display "Hello world!" } } $ Die Methode paint wird redefiniert: der formale Parameter ist ein Graphics Objekt. Bei Ausführung des Applet wird der Applet Konntext als aktueller Parameter übergeben; damit kann dann die Metode drawString des Graphics Objekts „Hello world“ ausgeben an die Position 50, 25. 2.2.4. Applet ausführen Ein Applet wird in ein HTML Dokument einebettet durch das Tag „APPLET“. Arbeiten mit Java Prof.Dr. Alois Schütte 22/65 $ cat helloWorld.html <HTML> <HEAD> <TITLE>The Hello World Applet</TITLE> </HEAD> <BODY> Hello World Applet: <br> <APPLET CODE="helloWorldApplet.class" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML> $ Durch die Attribute WIDTH und HEIGHT wird der Applet Kontext für die Methode paint bestimmt. Arbeiten mit Java Prof.Dr. Alois Schütte 23/65 3. Unterschied Java und C++ Im Folgenden wird Java erklärt, in dem der Unterschied zu C++ beschrieben wird. 3.1. Variablen Instanzvariablen werden initialisiert, wenn ein Objekt erzeugt wird. Für eine komplexere Initialisierung als mit den einfachen Variablenstartwerten gibt es Konstruktor-Methoden, die ausgeführt werden, wenn eine neue Instanz der Klasse erzeugt wird. Klassenvariablen werden initialisiert, wenn die Klasse das erste Mal geladen wird. Man kann Initialisierungsmethoden für Klassenvariablen schreiben (sog. statische Initialisierer), die benötigt werden für Klassen, die native-Methoden implementieren. Beispiel: class A { static int Kvar; int Ivar; // Klassenvariable // Instanzvariable } Als Anfangswerte für die Initialisierung wird verwendet: Typ Boolean Char Arbeiten mit Java Prof.Dr. Alois Schütte Anfangswert false '\u000' 24/65 Ganzzahl (int, byte, short, long) 0 +0.0 Gleitkomma null andere Referenzen 3.2. Unterschied Wert <--> Referenz Als einfache Datentypen werden die vordefinierten Datentypen (int, float, …) bezeichnet. Objekte und Arrays werden als nicht-einfache Datentypen bezeichnet bzw. als Referenzdatentypen. In Java gilt: einfache Typen werden immer durch den Wert übergeben Arrays und Objekte werden immer durch Referenz übergeben Die Änderung einer Referenz innerhalb einer Funktion hat keine Wirkung nach "außen": Beispiel: Weil Objekte per Referenz übergeben werden, können 2 Variable dasselbe Objekt referenzieren: Arbeiten mit Java Prof.Dr. Alois Schütte 25/65 Button p, q; p = new Button(); q = p; p.setLabel("OK"); String s = q.getLabe(); // p referenziert ein Button Objekt // q referenziert denselben Button // eine Änderung im Objekt durch p ... // ...ist auch durch q sichtbar, s ="OK" Dies gilt nicht für einfache Typen: int i = 3; int j = i; i = 2; // // // // i enthält den Wert 3 j enthält eine Kopie des Wertes in i eine Änderung von i bewirkt keine Änderung von j; i == 2, j == 3 3.2.1. Objekte kopieren Button a = new Button("Okay"); Button b = new Button("Cancel"); a = b; Im o.a. Beispiel wird deutlich: die Variable a enthält eine Referenz auf das Objekt, welches von b refereziert wird; das Objekt das a vor der Zuweisung (a=b) referenziert hat, ist verloren. Um Daten von einem Objekt in ein anderes zu kopieren, benutzt man die Methode clone(). Die clone()-Methode erzeugt ein neues Objekt desselben Typs wie das Ursprungsobjekt und initialsiert die Datenfelder des neuen, „geklonten“ Objektes mit den aktuellen Werten der Datenfelder des Ursprungsobjektes: Arbeiten mit Java Prof.Dr. Alois Schütte 26/65 Vector b = new Vector; c = b.clone(); D.h. die Variable c enthält ein Duplikat des von b referenzierten Objektes 3.2.2. Zeiger In Java gibt es keine Zeiger. Referenzieren und Dereferenzieren von Objekten wird automatisch vorgenommen; es ist nicht erlaubt, Speicheradressen zu manipulieren Gründe für diese Designentscheidung sind: Zeiger sind in C++ häufig eine Fehlerquelle die Sprache wird ohne Zeiger vereinfacht Zeiger und Zeigerarithmetik können dazu benutzt werden, Laufzeitüberprüfungen und Sicherheitsmechanismen zu umgehen (= Sicherheitsgarantie) 3.3. Arrays Arrays in Java werden durch Referenzen manipuliert und dynamisch mit new erzeugt. Ein Garbage Collector gibt den nicht mehr benötigten Speicher von Arrays frei, wenn sie nicht mehr benötigt werden. Arbeiten mit Java Prof.Dr. Alois Schütte 27/65 3.3.1. Anlegen von Arrays Arrays können auf zwei Arten angelegt werden: 1. Möglichkeit: mit new. Button buttons[] = new Button [10]; Dabei werden die Elemente des Arrays auf den Standardwert ihres Typs initialisiert, z.B int_Array-Elemente auf 0 initialisiert; die Arrays von Objekten werden auf null initialisiert 2. Möglichkeit: dynamisches Anlegen eines Arrays und Initialisierung mit den angegebenen Werten. int look_up table[] = [1,2,4,8,16]; Ein mehrdimensionales Array wird mit new angelegt, indem die entsprechende Anzahl von Elementen in [] für jede Dimension angegeben wird: byte TwoDimArray[][] = new byte[256][16]; Bei allen Arrayreferenzen wird der Index überprüft. Liegt der Index außerhalb der Grenzen, so wird eine „ArrayIndexOutOfBounds“ Exception erzeugt. Die Größe eines Arrays ist nicht Teil seines Typs, d.h. es kann eine Variable deklariert werden, die z. B. vom Typ String[] ist, und ihr ein Array aus String- Objekten zuweisen, egal wie lang dieses Array ist: Arbeiten mit Java Prof.Dr. Alois Schütte 28/65 String[] strings; strings = new String[10]; strings = new String[20]; // diese Variable weist auf ein String-Array // das nur 10 Strings enthält // oder 20 Das folgende Beispiel zeigt die Verwendung von Variablen und Arrays im Zusammenhang: Arbeiten mit Java Prof.Dr. Alois Schütte 29/65 $ cat tArray.java class tArray { public static void main(String[] args) { int[][] iA = new int[4][3]; //2 dim. int Array iA[1][1] = 6; System.out.println("int array:"); for (int i=0; i<2; i++) { for (int j=0; j<3; j++) System.out.print(iA[i][j]+" "); System.out.println(); } float[][] fA = new float[4][]; //2 dim. Array mit variabler Anz. Spalten for (int i=0; i<fA.length; i++) { fA[i] = new float[i+1]; } fA[1][1] = 6; System.out.println("\nfloat array:"); for (int i=0; i<fA.length; i++) { for (int j=0; j<fA[i].length; j++) System.out.print(fA[i][j]+" "); System.out.println(); } } } Arbeiten mit Java Prof.Dr. Alois Schütte 30/65 Die Ausgabe des letzten Programms: $ java tArray int array: 0 0 0 0 6 0 float array: 0.0 0.0 6.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 $ 3.4. Operatoren Bis auf die nachfolgenden Ausnahmen, existieren die Operatoren von C++. Folgende Operatoren werden in Java nicht unterstützt: • Kommaoperator • * und &-Operatoren (Zeiger) • sizeof-Operator Zusätzlich gibt es folgende Operatoren: Arbeiten mit Java Prof.Dr. Alois Schütte 31/65 • +-Operator zum Konkatenieren von Strings: wird auf String-Werte angewendet; ist nur ein Operand ein String, so wird der andere in einen String konvertiert; diese Umwandlung geschieht bei einfachen Datentypen automatisch und bei nicht-einfachen Datentypen durch den Aufruf der Methode toString() • instanceof (Objekt instanceof gesuchteKlasse): prüft, ob Objekt eine Instanz der Klasse gesuchteKlasse ist. Das bedeutet, dass der linke Operand ein Referenztyp sein muss. Der rechte Operand ist ein Typ- (bzw. Klassen-) Bezeichner. instanceof liefert true, wenn das Objekt auf der linken Seite eine Instanz der Klasse ist, die auf der rechten Seite angegeben ist instanceof liefert false, wenn das Objekt auf der linken Seite den Wert null hat (nullReferenz ist keine Instanz irgendeines Objekttyps) • >>>: alle integralen Typen in Java sind vorzeichenbehaftet, dieser Operator behandelt den Wert, der geshiftet werden soll, als nicht vorzeichenbehafteten Wert und schiebt die Bits mit einer Nullerweiterung nach rechts • & und |: integrale Typen wie in C++ boolean: beide Operanden werden ausgewertet, auch wenn das Ergebnis schon feststeht (nachdem der linke Operand ausgewertet ist) • [] (Zugriff auf Felder) und . (Zugriff auf Einträge) werden in Java nicht als Operatoren gewertet Arbeiten mit Java Prof.Dr. Alois Schütte 32/65 In Java ist keine Operatorüberladung möglich. 3.5. Typkonvertierung Folgende Regeln gelten zur Typkonvertierung: • boolean kann in keinen anderen Typ konvertiert werden und kein Typ kann nach boolean konvertiert werden. • Alle numerischen Typen können in beliebig andere numerische Typen konvertiert werden. • Ein Referenztyp kann in einen anderen Referenztyp konvertiert werden, wenn der Ausgangstyp vom Zieltyp abgeleitet wurde. 3.5.1. Numerische Konvertierungen Wenn eine Variable in einen anderen Typen konvertiert werden soll, so muss ihr der gewünschte Typ in Klammern vorangestellt werden: double x = 674.14; int i = (int)x; Bei Konvertierungen muss beachtet werden, dass mit der Konvertierung ein Verlust an Genauigkeit sowie eine Einschränkung des Wertebereiches einhergehen kann. Es gibt folgende Regeln: • Bei der Konvertierung eines Gleitpunkttyps in einen Ganzzahltyp werden alle Nachkommastellen abgeschnitten. Falls der Wert der Vorkommastellen zu groß bzw. zu klein ist, um ihn durch den betreffenden Ganzzahltyp darzustellen, resultiert der größte bzw. der kleinste mit dem Ganzzahltyp darstellbare Wert. Arbeiten mit Java Prof.Dr. Alois Schütte 33/65 • Bei der Konvertierung eines Ganzzahltyps in einen kleineren Ganzzahltyp werden die überzähligen Bits abgeschnitten. Das kann einen Wechsel des Vorzeichens bewirken. • Ein Ganzzahltyp kann ohne eine explizite Konvertierung an einen größeren Ganzzahltyp zugewiesen werden. So können alle Ausdrücke vom Typ byte und short an eine Variable vom Typ int zugewiesen werden. • Der Typ char ist ohne explizite Konvertierung zuweisungskompatibel zu short, int und long. • Bei einer Konvertierung aus dem Typ double in den Typ float resultiert derjenige float-Wert, der gegenüber dem double-Wert die geringste Differenz aufweist. 3.6. Anweisungen (if/else, while und do/while) Bis auf die folgenden Ausnahmen existieren die Kontrollstrukturen von C++. In Bedingunden (von if, while) ist null und nicht gleich false und Werte ungleich 0 und nicht-null Werte sind nicht das gleiche wie true. Es gibt kein goto-Konstrukt. 3.7. Garbage Collection In Java gibt es kein Gegenstück zum new-Operator, das ein Objekt wieder entfernt. Auch Destruktoren im Sinne von C++ gibt es nicht. An Stelle expliziter Freigabe von Objekten gibt es einen Mechanismus, der sich automatisch darum kümmert: der Garbage Collector. Der Garbage Collector prüft, ob es noch Verweise auf ein Objekt gibt. Wird ein Objekt von niemand mehr referenziert, wird es automatisch freigegeben. Java gibt keine Garantien, wann die Garbage Collection stattfindet oder in welcher Reihenfolge die Objekte freigegeben werden. Arbeiten mit Java Prof.Dr. Alois Schütte 34/65 Garbage Collection gibt automatisch die Speicherressourcen von Objekten frei, aber Objekte können noch andere Ressourcen besitzen, wie Dateideskriptoren oder Sockets. Der Garbage Collector kann solche Ressourcen nicht freigeben, deshalb muss man finalizer-Methoden schreiben, die z.B. offene Dateien schließen, Netzwerkverbindungen beenden. Wenn ein Objekt einen Finalizer hat, so wird diese Methode aufgerufen, bevor der Garbage Collector das Objekt löscht. Nach dem Aufruf des Finalizers werden die Objekte nicht sofort freigegeben. Der Grund ist, dass der Finalizer ein Objekt "wiederbeleben" kann, indem es den thisZeiger irgendwo speichert, so dass das Objekt wieder eine Referenz hat. Beispiel: /* schließt einen Stream, wenn der Garbage Collector seine Arbeit verrichtet; überprüft jedoch zuerst, ob der Deskriptor nicht schon geschlossen ist */ protected void finalize() throws IOException { if (fd != null) close(); } 3.8. import-Anweisung Die package-Anweisung dient dazu, eine Sammlung von Klassen zu einer Einheit zusammenzufassen. Um die Zugehörigkeit einer Quelldatei zu einem Package anzugeben, wird vor der Deklaration von Klassen eine Package-Anweisung in der Quelldatei eingefügt. Dem Schlüsselwort Package folgt der Package-Name. Arbeiten mit Java Prof.Dr. Alois Schütte 35/65 package tools; Zum Importieren eines Packages oder einer Klasse aus einem Package definiert Java die importAnweisung. Diese Anweisung stellt Javaklassen für die aktuelle Klasse unter einem abgekürzten Namen zur Verfügung. import stellt weder die Klasse zur Verfügung , noch "liest" es sie tatsächlich ein, sondern es spart nur Schreibarbeit und macht den Kode lesbarer. Es ist eine beliebige Anzahl von import-Anweisungen möglich. Sie müssen aber nach der optionalen package Anweisung am Anfang der Datei stehen und vor der ersten Klassen oder Schnittstellendefinition in der Datei. Es sind 3 Formen möglich: 1. Form: import package; ermöglicht dem angegebenen Paket durch den Namen seiner letzten Komponente angegeben zu werden import java.awt.image java.awt.image.ImageFilter kann als image.ImageFilter aufgerufen werden. 2. Form: import package.class; ermöglicht es der angegebenen Klasse in dem angegebenen Paket nur durch den Klassennamen benutzt zu werden import java.util.Hashtable; Arbeiten mit Java Prof.Dr. Alois Schütte 36/65 nur Hashtable statt java.util.Hashtable 3. Form: import package.*; alle Klassen des Paketes werden durch ihre Klassennamen verfügbar gemacht import java.lang.* ist implizit in jedem Javaprogramm enthalten Werden 2 Pakete, die Klassen mit gleichen Namen haben, importiert, kommt es zu einer Fehlermeldung, wenn eine Klasse mit ihrem nicht mehr eindeutigen kurzen Namen benutzt wird. 3.9. Subklassen und Vererbung Durch Vererbung können Klassen definiert werden, die auf einer anderen Klasse basieren. Diese neuen Klassen stellen eine Erweiterung und Spezialisierung ihrer Basisklasse dar. Die Subklasse kann neue Methoden und Elemente hinzufügen oder bestehende Methoden überschreiben. Wenn von einer Klasse einen Subklasse abgeleitet wird, muss die Subklasse im Kopf ihrer Deklaration das Schlüsselwort extends benutzen. Hinter extends muss genau eine Klasse angegeben werden. public class A extends B { ... } A ist eine Subklasse von B, d.h. A erbt alle Variablen und Methoden der Klasse B, außer die als private gekennzeichneten. Arbeiten mit Java Prof.Dr. Alois Schütte 37/65 3.9.1. Modifier für Klassen abstract: Abstrakte Klassen dienen nur dazu, eine Klassenstruktur festzulegen, ohne Implementierungen vorzunehmen. Eine abstrakte Klasse darf nicht instantiiert werden. Von ihr muss erst eine Unterklasse abgeleitet werden, die die Methoden der abstrakten Klasse implementiert. final: Von Klassen, die mit final gekennzeichnet sind, können keine Unterklassen abgeleitet werden. Eine Klasse darf nicht gleichzeitg als abstract und final deklariert werden. 3.9.2. Modifier für Methoden final: Eine mit final gekennzeichnete Methode kann nicht überschrieben werden. static: Static-Methoden gelten implizit als final und können deshalb nicht überschrieben werden. abstract: Abstrakte Methoden sind dazu gedacht, die Aufrufstruktur, aber nicht aber die Implementierung festzulegen. Sie müssen in einer Subklasse implementiert werden, die nicht abstrakt ist. Abstrakte Methoden dürfen nur in abstrakten Klassen deklariert werden. Arbeiten mit Java Prof.Dr. Alois Schütte 38/65 3.9.3. Modifikatoren Situation public default protected erreichbar für nicht-Subklasse aus dem gleichen Paket? erreichbar für Subklasse aus dem gleichen Paket? erreichbar für nicht-Subklasse aus einem anderen Paket? erreichbar für Subklasse aus einem anderen Paket? geerbt von Subklasse in gleichem Paket? geerbt von Subklasse in einem anderen Paket? 3.9.4. private private protected ja ja ja nein nein ja ja ja nein nein ja nein nein nein nein ja nein nein nein nein ja ja ja nein ja ja ja ja nein nein Superklassen, Objekte und Klassenhierarchie Jede Klasse, die definiert wird, besitzt eine Superklasse. Wenn die Superklasse nicht in der extends-Klausel angegeben ist, so ist die Superklasse implizit Object. Object ist die einzige Klasse, die keine Superklasse besitzt. Methoden, die von Object definiert werden, können von jedem Java-Objekt aufgerufen werden. Weil jede Klasse eine Superklasse besitzt, formen Klassen in Java eine Klassenhierarchie, die als Baum mit Object als Wurzel dargestellt werden kann. 3.9.5. Subklassen-Konstruktoren Aufrufen eines Konstruktors aus der Superklasse: Arbeiten mit Java Prof.Dr. Alois Schütte 39/65 public GraphicCircle(double x, double y, double r, Color outline, Color fill) { super(x,y,r); this.outline = outline; this.fill = fill; } Das Schlüsselwort super dient dazu, die Konstruktor-Methode der Superklasse aufzurufen. Der Konstruktoraufruf der Superklasse muss als 1. Anweisung innerhalb der KonstruktorMethode erscheinen. Wenn die 1. Anweisung in einem Konstruktor nicht ein explizter Aufruf des Konstruktor der Superklasse mit super ist, dann fügt Java implizit den super()-Aufruf ein: • Java ruft den Konstruktor der Superklasse ohne Argumente auf. • Wenn die Superklasse keinen Konstruktor ohne Argumente hat kommt es zu einem Übersetzungsfehler . Weil der Superklassen-Konstruktor immer zuerst aufgerufen wird, wird immer als erstes der Object-Konstruktor aufgerufen, gefolgt von der Subklasse und der Klassenhierarchie hinunter zu der Klasse, die instanziert wurde. Ist kein Konstruktor in einer Klasse deklariert, wird der Standardkonstruktor aufgerufen, der wiederum nichts anderes macht, als den Superklassenkonstruktor aufzurufen. Arbeiten mit Java Prof.Dr. Alois Schütte 40/65 3.9.6. Abstrakte Klasssen und Schnittstellen Eine abstract-Methode in Java entspricht in etwa einer "rein virtuellen" Funktion in C++, d.h. eine virtuelle Funktion, die als = 0 deklariert ist. Javaklassen, die abstract-Methoden enthalten, können nicht instanziert werden. Ist eine Methode abstract definiert, muss sie nicht implementiert werden. Regeln für abstract-Methoden und abstract-Klassen: • • • • jede Klasse, die eine abstract-Methode enthält ist automatisch selbst abstract eine abstract-Klasse muss mindestens eine abstract-Methode enthalten eine abstract-Klasse kann nicht instanziert werden eine Subklasse der abstract-Klasse kann instanziert werden, wenn sie alle abstractMethoden ihrer Superklasse überschreibt und eine Implementierung für diese Methoden zur Verfügung stellt • wenn eine Subklasse einer abstract-Klasse nicht alle abstract-Methoden, die sie erbt, implementiert, dann ist sie selbst abstract 3.9.7. Schnittstellen In Java dürfen Klassen nur eine Superklasse besitzen, das bedeutet, dass die von C++ bekannte Mehrfachvererbung nicht möglich ist. Stattdessen kennt Java die so genannten Interfaces. Das sind reine Schnittstellen, die keinerlei Implementierungen enthalten. Eine Schnittstelle sieht aus wie eine abstrakte Klasse, außer, dass sie das Schlüsselwort interface statt den Wörtern abstract und class benutzt. Alle Methoden in einer Schnittstelle sind implizit abstract. Jede Variable, die in einer Schnittstelle deklariert ist, muss static und final sein . Arbeiten mit Java Prof.Dr. Alois Schütte 41/65 Eine Klasse kann mit dem Schlüsselwort implements eine oder mehrere Schnittstellen vererben. Diese Klasse erbt alle Konstanten und die abstrakten Methoden. Die Methoden müssen dann überschrieben werden. Beispiel: interface W{} interface X extends W {} class Y implements W {} class Z extends Y implements X {} 3.9.8. Schnittstellen erweitern Schnittstellen können Subschnittstellen besitzen. Eine Subschnittstelle erbt alle abstrakten Methoden und Konstanten seiner Superschnittstelle und kann neue abstrakte Methoden und Konstanten definieren. Eine Schnittstelle, die mehr als eine Schnittstelle erweitert, erbt alle abstrakten Methoden und Konstanten aller Schnittstellen und kann neue abstrakte Methoden und Konstanten definieren. Eine Klasse, die solch eine Schnittstelle implementiert, muss alle abstrakten Methoden, die in der Schnittstelle selbst definiert sind, und alle Methoden, die von allen Superschnittstellen geerbt wurden, implementieren. Arbeiten mit Java Prof.Dr. Alois Schütte 42/65 4. Java Beispiele Durch die folgenden Beispiele von Java Anwendungen werden einige Techniken der Java Programmierung gezeigt, die das Bearbeiten der Übungen im Praktikum erleichtern sollen. I/O Interfaces 4.1. I/O Hier soll kurz erklärt werden, wie auf externe Medien geschrieben, bzw. von ihnen gelesen werden kann. Um von externen Medien zu Lesen oder darauf zu schreiben existiert das Konzept der Streams: Arbeiten mit Java Prof.Dr. Alois Schütte 43/65 Source … I n f o a m t o i n Program read … Stream Program write … I n f o m a t i o n … Dest. Unabhängig davon woher die Daten kommen (Datei, Pipe, Netzwerk) und welchen Typ sie haben ist das Verfahren des sequentiellen Lesens und Schreibens immer das gleiche: Lesen Schreiben open Stream while (more information) read (information) close Stream open Stream while (more information) write (information) close Stream Arbeiten mit Java Prof.Dr. Alois Schütte 44/65 Das Paket java.io beinhaltet Stream-Klassen, um diese Lese- und Schreiboperationen durchzuführen. Die Stream-Klassen sind unterteilt nach den grundlegenden Datentypen, die behandelt werden: • Charakter Streams Reader und Writer sind abstrakte Superklassen um 16 Bit Zeichen zu Lesen und zu Schreiben. Damit lassen der komplette Unicode Zeichensatz behandeln. • Byte-Streams InputStream und OutputStream sind Klassen zum byte-weisen Lesen und Schreiben. Diese Klasen werden normalerweise verwendet um Binärdaten (Sound, Images) zu behandeln. Die I/O Superklassen definieren die grundlegenden Methoden zum Lesen und Schreiben. Reader und InputStream definieren ähnliche APIs für unterschiedliche Datentypen. Reader beinhaltet u.a. folgende Methoden zum Lesen von Zeichen und von Zeichenfeldern: int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) InputStream definiert die gleichen Methoden für Bytes: int read() int read(byte cbuf[]) Arbeiten mit Java Prof.Dr. Alois Schütte 45/65 int read(byte cbuf[], int offset, int length) Writer und OutputStream sind das Pendant zum Schreiben. Writer definiert die Methoden für Zeichen.: int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) OutputStream defineert die gleichen Methoden für Bytes: int write(int c) int write(byte cbuf[]) int write(byte cbuf[], int offset, int length) Alle Streams (Reader, Writer, inputStream, OutputStream) werden automatisch geöffnet wenn sie erzeugt werden. Sie können explizite durch die Methode close geschlossen werden. Der Garbage Collector schließt Streams implizite, wenn die Objekte nicht mehr benötigt werden. 4.1.1. Übersicht über Streams Die folgende Tabelle gibt einen Überblick über das Package java.io: Arbeiten mit Java Prof.Dr. Alois Schütte 46/65 Typ of I/O Streams Description CharArrayReader CharArrayWriter Use these streams to read from and write to memory. You create these streams on an existing array and then use the read and write methods to read from or write to the array. ByteArrayInputStream ByteArrayOutputStream Memory StringReader StringWriter StringBufferInputStream Pipe Arbeiten mit Java PipedReader PipedWriter PipedInputStream PipedOutputStream Prof.Dr. Alois Schütte Use StringReader to read characters from a String in memory. Use StringWriter to write to a String. StringWriter collects the characters written to it in a StringBuffer, which can then be converted to a String. StringBufferInputStream is similar to StringReader, except that it reads bytes from a StringBuffer. Implement the input and output components of a pipe. Pipes are used to channel the output from one thread into the input of another. See PipedReader and PipedWriter in action in the section How to Use Pipe Streams. 47/65 File Concatenation Object Serialization Data Conversion Counting Arbeiten mit Java FileReader FileWriter FileInputStream FileOutputStream N/A SequenceInputStream Collectively called file streams, these streams are used to read from or write to a file on the native file system. The section How to Use File Streams. has an example that uses FileReader and FileWriter to copy the contents of one file into another. Concatenates multiple input streams into one input stream. The section How to Concatenate Files. has a short example of this class. N/A ObjectInputStream ObjectOutputStream Used to serialize objects. See Object Serialization. N/A DataInputStream DataOutputStream Read or write primitive data types in a machineindependent format. See How to Use DataInputStream and DataOutputStream. shows an example of using these two streams. LineNumberReader Keeps track of line numbers while reading. Prof.Dr. Alois Schütte 48/65 LineNumberInputStream Peeking Ahead Printing Buffering Filtering Arbeiten mit Java PushbackReader PushbackInputStream PrintWriter PrintStream BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream FilterReader FilterWriter FilterInputStream FilterOutputStream Prof.Dr. Alois Schütte These input streams each have a pushback buffer. When reading data from a stream, it is sometimes useful to peek at the next few bytes or characters in the stream to decide what to do next. Contain convenient printing methods. These are the easiest streams to write to, so you will often see other writable streams wrapped in one of these. Buffer data while reading or writing, thereby reducing the number of accesses required on the original data source. Buffered streams are typically more efficient than similar nonbuffered streams and are often used with other streams. These abstract classes define the interface for filter streams, which filter data as it's being read or written. The section Working with Filter Streams shows you how to use filter streams and how to implement your own. 49/65 A reader and writer pair that forms the bridge between byte streams and character streams. Converting beInputStreamReader tween Bytes and OutputStreamWriter Characters An InputStreamReader reads bytes from an InputStream and converts them to characters, using the default character encoding or a character encoding specified by name. An OutputStreamWriter converts characters to bytes, using the default character encoding or a character encoding specified by name and then writes those bytes to an OutputStream. You can get the name of the default character encoding by calling System.getProperty ("file.encoding"). Die Beispiele werden Streams Verarbeitung für File I/O verdeutlichen. 4.2. File Streams Die Filestreams FileReader, FileWriter, FileInputStream und FileOutputStream sind zum Zugriff auf das Dateisystem entwicklet worden. Das folgende Programm ist eine Implementierung eines Kopierprogramms für Dateien: Arbeiten mit Java Prof.Dr. Alois Schütte 50/65 $ cat copy.java import java.io.*; public class copy { public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("usage: copy sourceFile destFile"); return; } File inputFile = new File(args[0]); File outputFile = new File(args[1]); FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); } $ } in.close(); out.close(); Arbeiten mit Java Prof.Dr. Alois Schütte 51/65 Zunächst werden zwei Files deklariert; dann zwei Reader (in und out) erzeugt. Dann wird solange von in gelesen und auf out geschrieben, bis das Lesen das Dateiende erreicht. Das Programm, das ebenfalls kopiert, aber mit Bytes anstelle von Zeichen arbeitet, ist analog, es verwendet einfach FileInputStreams und FileOutputStreams: Arbeiten mit Java Prof.Dr. Alois Schütte 52/65 $ cat copyBytes.java import java.io.*; public class copyBytes { public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("usage: copy sourceFile destFile"); return; } File inputFile = new File(args[0]); File outputFile = new File(args[1]); FileInputStream in = new FileInputStream(inputFile); FileOutputStream out = new FileOutputStream(outputFile); int c; while ((c = in.read()) != -1) out.write(c); } $ } in.close(); out.close(); 4.3. Filter Streams Arbeiten mit Java Prof.Dr. Alois Schütte 53/65 Das Package java.io stellt eine Menge von abstrakten Klassen zur Verfügung, um Filter zu realisieren. Ein Filterstream filtert Daten eines zugrunde liegenden Stream. Die Art des Filterns hängt vom jeweiligen Filterstream ab: es existieren Filtersreams die Zählen, Puffern und Konvertieren von Daten. Das folgende Beispiel verdeutlicht DataInputStream und DataOutputStream um Daten auf eine Datei durch Tabulator getrennt zu schreiben bzw. zu lesen. Die Daten werden wie folgt (allerdings nicht im ASCII Format) abgelegt: Preis \t 19.99 9.99 Menge \t 12 8 Beschreibung Java T-shirt Java Cup Das Beispielprogramm schreibt zuerst Daten in der o.a. Form in die Datei „invoice1.txt“. Dann werden die Daten von der Datei gelesen und ausgegeben. Hierzu wird DataOutputStream einem zugrundeliegenden OutputStream angehängt, in diesem Fall dem FileOutputStream . DataOutputStream out = new DataOutputStream( new FileOutputStream("invoice1.txt") ); Nun können Methoden von DataOutputStream verwendet werden, um die Datei zu schreiben: Arbeiten mit Java Prof.Dr. Alois Schütte 54/65 double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; int[] units = { 12, 8, 13, 29, 50 }; String[] descs = { "Java T-shirt", "Java Cup", "Java JDK", "Java Pin", "Java Key Chain" }; for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeChar('\t'); out.writeInt(units[i]); out.writeChar('\t'); out.writeChars(descs[i]); out.writeChar('\n'); } Um die Daten aus der Datei zu lesen, wird ein DataIntputStream verwendet; er benutzt als zugrunde liegendem Stream FileIntputStream. Dann werden die Variablen definiert, um die gelesenen Daten abzulegen. Arbeiten mit Java Prof.Dr. Alois Schütte 55/65 // read it in again DataInputStream in = new DataInputStream(new FileInputStream("invoice1.txt") ); double price; int unit; StringBuffer desc; double total = 0.0; Nun kann die Datei bis zum Ende gelesen werden: Arbeiten mit Java Prof.Dr. Alois Schütte 56/65 try { while (true) { price = in.readDouble(); in.readChar(); // throws out the tab unit = in.readInt(); in.readChar(); // throws out the tab char chr; desc = new StringBuffer(20); char lineSep = System.getProperty("line.separator").charAt(0); while ((chr = in.readChar()) != lineSep) desc.append(chr); System.out.println("You've ordered " + unit + " units of " + desc + " at $" + price ); total = total + unit * price; } } catch (EOFException e) { } System.out.println("For a TOTAL of: $" + total); in.close(); Die While-Schleife bricht ab, wenn ein „in.readXX“ eine Ausnahme erzeugt. Das gesamte Programm mit der erzeugten Ausgabe ist im Folgenden dargestellt: Arbeiten mit Java Prof.Dr. Alois Schütte 57/65 $ cat DataIODemo.java import java.io.*; public class DataIODemo { public static void main(String[] args) throws IOException { // write the data out DataOutputStream out = new DataOutputStream(new FileOutputStream("invoice1.txt")); double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; int[] units = { 12, 8, 13, 29, 50 }; String[] descs = { "Java T-shirt", "Java Cup", "Java JDK", "Java Pin", "Java Key Chain" }; for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeChar('\t'); out.writeInt(units[i]); out.writeChar('\t'); out.writeChars(descs[i]); out.writeChar('\n'); } out.close(); Arbeiten mit Java Prof.Dr. Alois Schütte 58/65 // read it in again DataInputStream in = new DataInputStream(new FileInputStream("invoice1.txt")); double price; int unit; StringBuffer desc; double total = 0.0; try { while (true) { price = in.readDouble(); in.readChar(); // throws out the tab unit = in.readInt(); in.readChar(); // throws out the tab char chr; desc = new StringBuffer(20); char lineSep = System.getProperty("line.separator").charAt(0); while ((chr = in.readChar()) != lineSep) desc.append(chr); System.out.println("You've ordered " + unit + " units of " + desc + " at $" + price); total = total + unit * price; } } catch (EOFException e) { } System.out.println("For a TOTAL of: $" + total); Arbeiten mit Java Prof.Dr. Alois Schütte 59/65 in.close(); } } $ $ java DataIODemo You've ordered 12 units of Java T-shirt at $19.99 You've ordered 8 units of Java Cup at $9.99 You've ordered 13 units of Java JDK at $15.99 You've ordered 29 units of Java Pin at $3.99 You've ordered 50 units of Java Key Chain at $4.99 For a TOTAL of: $892.8800000000001 $ 4.4. Interfaces Ein Interface ist eine benannte Menge von Methoden-Definitionen ohne Implementierung und ggf. Konstantendefinitionen. Somit hat ein Interface Ähnlichkeit zu abstrakten Klassen. Die Unterschiede sind: • Ein Interface kann eine Methode nicht implementieren – eine abstrakte Klasse kann dies. • Eine Klasse kann mehrere Interfaces implementieren aber nur eine Superklasse haben (keine Mehrfachvererbung). • Ein Interface ist nicht Bestandteil der Klassenhierarchie. Nicht in Beziehung stehende Klassen können dasselbe Interface implementieren. Arbeiten mit Java Prof.Dr. Alois Schütte 60/65 Im Folgenden wird ein Beispiel betrachtet, bei dem eine Klasse (StockMonitor) zu realisieren ist, die Aktienkurse überwacht, die über eine Datenleitung von einem Kurslieferanten gelesen werden. Diese Klasse erlaubt es anderen Klassen zu registrieren, dass die Klassen informiert werden wollen, wenn eine Aktie einen Schwellwert übersteigt. Die Klasse StockMonitor implementiert eine Methode watchStock mit der andere Klassen die Überwachung einer Aktie (tickerSysmbol) Registrieren können: Arbeiten mit Java Prof.Dr. Alois Schütte 61/65 public class StockMonitor { public void watchStock(StockWatcher watcher, // interface name String tickerSymbol, // ticker symbol double delta ) { ... } } Das erste Argument der Methode watchStock ist der Name eines Interface: public interface StockWatcher { final String sunTicker = "SUNW"; … void valueChanged(String tickerSymbol, double newValue); } Dieses Interface deklariert eine Methode valueChanged. Ein Objekt, das bei Änderung des Aktienkurses informiert werden will, muss ein Exemplar der Klasse sein, die das Interface implementiert. Durch das erste Argument die Methode watchStock der Klasse StockMonitor wird sicher gestellt, dass alle Objekte die Methode valueChanges implementieren müssen. Hätte man anstelle eines Interface StockWatcher eine Klasse verwendet, so wäre die Verwendung nur von Objekten, die aus StockWatcher abgeleitet werden, möglich. Arbeiten mit Java Prof.Dr. Alois Schütte 62/65 Durch die Verwendung des Interface, kann der Dienst von jeder Klasse in der Klassenhierarchie verwendet werden (z.B. Applet, Thread, ….). 4.4.1. Definition eines Interface Die Definition eines Interface besteht aus • Interface Deklaration • Interface Körper Intercace Declaration public interface StockWatcher { final String sunTicker = "SUNW"; final String oracleTicker = "ORCL"; final String ciscoTicker = "CSCO"; Body Constant Declarations Method void valueChanged(String tickerSymbol, double newValue); Declarations } Interface Deklaration Die Komponenten der Interface Deklaration sind: Arbeiten mit Java Prof.Dr. Alois Schütte 63/65 • public dadurch wird das Interface pubic-verfügbar • interface <Name> definiert den Namen des Interface • extends <SuperInterface1>, …<SuperInterfaceN> ein Interface kann mehrere Super-Interfsces haben (im Gegensatz zu Klassen). Interface Körper Die Komponenten des Interface Körper sind: • Konstanten Definitionen sind implizite public, static und final. • Methoden Deklarationen werden durch „;“ getrennt und sind implizit public und abstract. 4.4.2. Implementierung eines Interface Ein Interface beschreibt ein Verhalten von Objekten. Eine Klasse, die das Interface implementiert setzt das gewünschte Verhalten der Objekte um. Um eine Klasse, die ein Interface implementiert zu realisieren, wird bei der Klassendeklaration das Inteface durch „implements“ angegeben: Arbeiten mit Java Prof.Dr. Alois Schütte 64/65 public class StockApplet extends Applet implements StockWatcher { ... public void valueChanged(String tickerSymbol, double newValue) { if (tickerSymbol.equals(sunTicker)) { ... // get Data from Datafeed for SUN } else if (tickerSymbol.equals(oracleTicker)) { ... // get Data from Datafeed for ORACLE } else if (tickerSymbol.equals(ciscoTicker)) { ... // get Data from Datafeed for CISCO } } } Arbeiten mit Java Prof.Dr. Alois Schütte 65/65