Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu...

116
Yet Another Java Intro Harald Krottmaier 14. August 2003

Transcript of Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu...

Page 1: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Yet Another Java Intro

Harald Krottmaier

14. August 2003

Page 2: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Inhaltsverzeichnis

1 Anatomie eines Java-Programms 1

1.1 Ein sehr einfaches Beispiel . . . . . . . . . . . . . . . . . . . . . . 1

1.2 Vom Sourcecode zum Programm . . . . . . . . . . . . . . . . . . 2

1.2.1 Was alles schiefgehen wird . . . . . . . . . . . . . . . . . . 3

1.2.2 Wohin mit den Klassenfiles? . . . . . . . . . . . . . . . . . 4

1.3 Ein einfaches Beispiel . . . . . . . . . . . . . . . . . . . . . . . . 6

1.4 Ein einfaches Applet . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.5 Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1.6 Schlusselworter in Java . . . . . . . . . . . . . . . . . . . . . . . . 11

2 Datentypen, Variablen und Operatoren 12

2.1 Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.1.1 Primitive-Datentypen . . . . . . . . . . . . . . . . . . . . 12

boolean-Datentyp . . . . . . . . . . . . . . . . . . . . . . 13

Ganzzahlige-Datentypen (byte, short, int und long) . . 14

char-Datentyp . . . . . . . . . . . . . . . . . . . . . . . . 14

Gleitkomma-Datentypen (float, double) . . . . . . . . . 15

2.1.2 Referenz-Datentypen . . . . . . . . . . . . . . . . . . . . . 16

String und StringBuffer . . . . . . . . . . . . . . . . . 17

Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Mehrdimensionale Arrays . . . . . . . . . . . . . . . . . . 21

2.2 Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.2.1 Deklaration von Variablen . . . . . . . . . . . . . . . . . . 23

2.2.2 Default Werte . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.2.3 Arten und Scope von Variablen . . . . . . . . . . . . . . . 25

2.3 Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

2.3.1 Unare Arithmetische Operatoren . . . . . . . . . . . . . . 28

2.3.2 Binare Arithmetische Operatoren . . . . . . . . . . . . . . 29

2.3.3 Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . 30

I

Page 3: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

INHALTSVERZEICHNIS II

2.3.4 Logische Verknupfungsoperatoren . . . . . . . . . . . . . . 30

2.3.5 Bitoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.3.6 Shortcut-Zuweisungsoperatoren . . . . . . . . . . . . . . . 32

2.3.7 Weitere Operatoren . . . . . . . . . . . . . . . . . . . . . 32

3 Flusskontrolle 34

3.1 While... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.2 For... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.3 If... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

3.4 Switch... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.5 break, continue und return . . . . . . . . . . . . . . . . . . . . 39

4 Klassen in Java 41

4.1 Einige Begriffe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.2 Definition einer Klasse in Java . . . . . . . . . . . . . . . . . . . 43

4.3 Der Konstruktor einer Klasse . . . . . . . . . . . . . . . . . . . . 45

4.3.1 Konstruktoren in Einfachen Klassen . . . . . . . . . . . . 46

4.3.2 Konstruktoren und Abgeleitete Klassen . . . . . . . . . . 47

4.4 ’Destruktor’ einer Klasse . . . . . . . . . . . . . . . . . . . . . . . 50

4.5 Member-Modifier . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

4.5.1 Access-Modifier . . . . . . . . . . . . . . . . . . . . . . . . 53

4.5.2 Object- und Class-Members . . . . . . . . . . . . . . . . . 56

4.5.3 Variablen-Modifier . . . . . . . . . . . . . . . . . . . . . . 57

4.5.4 Methoden-Modifier . . . . . . . . . . . . . . . . . . . . . . 58

4.6 Initialisierung von Member-Variablen . . . . . . . . . . . . . . . . 58

4.7 Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

4.8 Inner Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

4.9 Ableitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

4.10 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

4.11 Ein kurzer Einblick in Packages . . . . . . . . . . . . . . . . . . . 66

5 Fehlerbehandlung 68

5.1 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

6 Swing 73

6.1 Und wieder ein einfaches Beispiel . . . . . . . . . . . . . . . . . . 74

6.2 Die Model-View-Controller Architektur . . . . . . . . . . . . . . 75

6.3 Container und Komponenten . . . . . . . . . . . . . . . . . . . . 76

6.4 Layoutmanager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

6.5 Ein weiteres Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . 80

Page 4: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

INHALTSVERZEICHNIS III

6.6 Event-Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

6.6.1 Event-Listener Interface und Adapter . . . . . . . . . . . 83

6.6.2 Event-Listener Methoden . . . . . . . . . . . . . . . . . . 84

6.6.3 Kurzer Uberblick uber konkrete Events in Swing . . . . . 85

6.7 Was passiert beim Zeichnen eines Fensters? . . . . . . . . . . . . 89

6.8 Swing-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . 90

6.8.1 Top-Level Container . . . . . . . . . . . . . . . . . . . . . 90

6.8.2 Allgemeine Container . . . . . . . . . . . . . . . . . . . . 91

6.8.3 Kontroll Komponenten . . . . . . . . . . . . . . . . . . . . 92

6.8.4 Info Komponenten . . . . . . . . . . . . . . . . . . . . . . 92

6.8.5 Spezielle Komponenten . . . . . . . . . . . . . . . . . . . 93

7 Threads 94

7.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

7.2 Threads in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

7.3 Lebenszyklus eines Threads . . . . . . . . . . . . . . . . . . . . . 99

7.4 Einige Methoden in Thread . . . . . . . . . . . . . . . . . . . . . 100

7.5 Stolpersteine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

Literaturverzeichnis 106

Changelog 110

Page 5: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Bevor es losgeht...

Wieso diese Seiten? Warum denn schon wieder eine Einfuhrung in Java? Wozudas Ganze? Fragen uber Fragen, die man sich stellen kann, wenn man die-se Unterlagen in die Hande kriegt. Obwohl es viele Grunde gegen ein solchesMinimal-Skriptum gibt (z.B. Arbeitsaufwand, Umfang der hier abgedeckt wer-den kann etc.), sprechen auch einige Grunde dafur:

Zeitmangel der Studenten: Es gibt viel zu tun. Da ich auch einmal stu-diert habe, weiß ich, dass es ziemlich schwer ist, auf eigene Faust ein neuesGebiet – in diesem Fall die Programmiersprache Java – zu erfassen. DieseUnterlagen sollen hier helfen und den Zeitaufwand fur das Erlernen derSprache reduzieren.

Vorwissen der Studenten: Einige von euch haben schon Java Programmegeschrieben, einige noch nicht. Diese Unterlagen sollen ein Basiswissenvermitteln, damit man die gestellte Programmieraufgabe in vernunftigerZeit losen kann.

Fun: Seien wir ehrlich: Es macht auch Spaß, Unterlagen zusammenzustellen:)

Wir beginnen mit einigen einfuhrenden, beispielhaften Programmen und erlauterndie wichtigsten Konzepte der Programmiersprache. Mit diesem Wissen kannman einfache Aufgaben losen. Hier wird bewusst immer wieder eine Verbindungzu bekannten Programmiersprachen hergestellt, um einen raschen Lernerfolg zugewahrleisten (im Speziellen zu C++).

Danach wird ein Uberblick uber Datentypen, die in Java zur Verfugung stehen,gegeben und die Unterschiede zur Programmiersprache C++ herausgearbeitet.

Fur Anregungen habe ich selbstverstandlich auch immer ein offenes Ohr. Bittekontaktiert mich einfach via Email oder verwendet das Diskussionsforum (tu-graz.lv.prgpraktikum.skriptum) am Newsserver der TU-Graz. Die aktuellsteVersion der Unterlagen und die dazu passenden Beispiele ist am Server abgelegt.

So. Das sollte zur Motivation reichen. Auf geht’s in die erste Runde!

IV

Page 6: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 1

Anatomie einesJava-Programms

Um den Einstieg moglichst einfach zu machen, beginnen wir mit der Analyseeines einfachen Programms und untersuchen im Anschluss etwas komplexereBeispiele. Wie man vom Sourcecode zu einem lauffahigen Programm kommt,wird nach dem ersten Beispiel gezeigt.

1.1 Ein sehr einfaches Beispiel

Wer will schon ein “Hello World”-Programm? Wir beginnen mit einem Very-SimpleExample.java! Bitte nicht verzweifeln, wenn hier schon einige Begriffeverwendet werden, die erst in den nachsten Kapitel genauer erlautert werden.Fur das Verstandnis ist ein allgemeines Vorwissen zur Programmierung bei wei-tem ausreichend. Nun aber zum ersten Beispiel:

1 public class VerySimpleExample2 {3 public static void main( Str ing [ ] args )4 {5 System . out . pr int ln (”This i s a very simple example . . . ” ) ;6 }7 }

Intuitiv ist vielleicht schon klar, was dieses Programm macht: Es schreibt dieZeichenkette:

This is a very simple example...

auf die Konsole (stdout). Betrachten wir nun die Zeilen etwas genauer:

Zeile 5: Hier wird eine Methode (println(...);) von einem Objekt (out)aufgerufen. Dieses Objekt wird in einem statischen Objekt (System) ge-halten. System wird beim Initialisieren der Java Virtual Machine (JVM)erzeugt.

1

Page 7: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 2

Zeile 3: Definition einer Methode main die als Argument ein Feld von Stringsnimmt (String[] args). Diese statische Methode (static) gibt keinenWert zuruck (void) und kann auch von anderen Objekten aus aufgerufenwerden (public).

Zeile 1: Definition einer Klasse (class) VerySimpleExample die von Objektenjeder anderen Klasse aus aufgerufen werden kann (public).

Die geschwungenen Klammern ({ bzw. }, curly brace) umschließen jeden Block(Zeile 2 und 7 bzw. 4 und 6) von Anweisungen und stehen laut Styleguide([PPrakt. Java Coding 2002]) in einer eigenen Zeile. Das macht den Codelesbarer im Vergleich zu den Richtlinien, die Sun ([Sun 1999]) vorschlagt.

1.2 Vom Sourcecode zum Programm

Der Sourcecode wird in eine Datei gespeichert, die die Erweiterung ’.java’ hat.Als Dateiname muss der in diesem File definierte Klassenname verwendet wer-den (VerySimpleExample). Die Groß-/Kleinschreibung muss ebenso beachtetwerden, d.h. eine Klasse VerySimpleExample muss in einem File VerySimple-Example.java definiert sein. In Java wird von einem Compiler (javac) Bytecodeerzeugt. Dieser ist nicht direkt ausfuhrbar. Der Bytecode wird in Dateien mitder Endung ’.class’ gespeichert. Interpretiert wird der Bytecode von einer sog.Java Virtual Machine (JVM, java). Nicht nur Sun (http://java.sun.com),sondern auch andere Hersteller (z.B. IBM) stellen Implementationen der JVMfur verschiedenste Betriebssysteme her. In diesem Zusammenhang soll dasBlackdown-Projekt genannt werden, in dem eine Implementation der JVM furLinux realisiert wird (die mitunter besser funktioniert als die Implementationvon Sun...).

Das Interpretieren eines Bytecodes ist selbstverstandlich langsamer als das di-rekte Ausfuhren von Maschinencode. Aktuelle Technologien wie z.B. HotS-pot versprechen hier wesentliche Performance-Verbesserungen1. Eine zweiteMoglichkeit zur Performancesteigerung ist die direkte Umsetzung des Bytecodesin Maschinencode. Just-in-Time Compiler (sog. JITs) setzen hier die .class-Files in Maschinencode um, der dann vom Prozessor ausgefuhrt wird. Dadurchergeben sich ublicherweise Performancesteigerungen. Naheres findet man aufden Seiten von Sun bzw. uber Google.

Das waren nun aber wirklich viel Fakten! Das Ganze zusammengefasst:

• Schreiben des Sourcecodes in einem beliebigen Editor (z.B. emacs). Be-achte den Filenamen!

• Ubersetzen des Sourcecodes in Bytecode (javac VerySimpleExample.javaerzeugt VerySimpleExample.class, sofern keine Fehler im Sourcecodesind :))

• Interpretieren des Bytecodes mit einer virtuelle Maschine (java Very-SimpleExample). Interpreter fur den Bytecode gibt es fur die unterschied-lichsten Betriebssysteme (Windows, Solaris, Linux, MacOS...).

1Wer sich fur diese Technologie interessiert, soll bitte den Link verfolgen... Eine Beschrei-bung wurde hier den Rahmen sprengen.

Page 8: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 3

1.2.1 Was alles schiefgehen wird

Betrachten wir nun die haufigsten Fehler, die auftreten konnen (und auch auf-treten werden):

Vorsicht Falle: Selbstverstandlich muss der Compiler (javac) und auch derInterpreter (java) am Rechner installiert sein. Wer auf der Konsole folgendeRuckmeldung

>javac VerySimpleExample.javajavac: Command not found.

bekommt, hat entweder das Programm javac nicht im Suchpfad oder hat denCompiler nicht installiert. Wer mit dem Begriff Suchpfad nichts anfangen kann,der sei auf diverse Einfuhrungshandbucher in das jeweils verwendete Betriebs-system verwiesen. Wenn jemand den Compiler noch nicht installiert hat, dersoll doch einmal die Java Seiten von Sun im Internet besuchen.

Vorsicht Falle: Der Dateiname des Sourcecodes ist hier – im Unterschied zuanderen Programmiersprachen – wirklich wesentlich. Ein Versuch, die KlasseVerySimpleExample in ein File verysimpleexample.java zu speichern ergibtfolgenden Fehler:

>javac verysimpleexample.javaverysimpleexample.java:1: class VerySimpleExample is public,should be declared in a file named VerySimpleExample.javapublic class VerySimpleExample

^1 error

Wenn man mit bestimmten Windows-Versionen arbeitet (z.B. Windows 98,nicht aber Windows 2000...), ist es notwendig, den Filenamen unter Anfuhrungs-zeichen zu schreiben, damit die Groß-/Kleinbuchstaben im Filenamen nicht ver-loren gehen!

Vorsicht Falle: Wenn das Programm richtig compiliert worden ist, wird derBytecode in ein File (NameOfTheClass.class) abgelegt. Dieser Bytecode mussmit dem Interpreter ausgefuhrt werden. Hier ist es wesentlich, dass nur derKlassenname, und nicht der Filename des Bytecodes angegeben wird. Gibtman hier den Namen des Bytecode-Files an, bekommt man folgende Meldung:

>java VerySimpleExample.classException in thread "main" java.lang.NoClassDefFoundError:

VerySimpleExample/class

Page 9: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 4

Man muss den Namen der Klasse, also VerySimpleExample als Parameter furden Interpreter angegeben. Der richtige Aufruf muss also so erfolgen:

>java VerySimpleExampleThis is a very simple example...

Vorsicht Falle: Ein ausfuhrbares Programm in einer Klasse muss eine Methodepublic static void main(String[] args) implementieren. Diese Methodewird von der JVM gesucht und aufgerufen. Sie entspricht der main() Funktionvon C++. Betrachten wir folgendes Beispiel:

1 public class BadVerySimpleExample2 {3 public void main( Str ing [ ] args )4 {5 System . out . pr int ln (” I ’m a bad simple example . . . ” ) ;6 }7 }

Das File lasst sich selbstverstandlich compilieren, aber nicht ausfuhren!

>javac BadVerySimpleExample.java>java BadVerySimpleExampleException in thread "main" java.lang.NoSuchMethodError: main

Hier ist die Fehlermeldung vielleicht etwas verwirrend (eine Methode main wurdeja in Zeile 3 definiert...), aber die Signatur, die verlangt wird, ist nicht vorhan-den. Der Code ist kompilierbar (da er ja syntaktisch korrekt ist), aber nichtausfuhrbar. Ihr konnt es mir glauben (oder auch selbst ausprobieren :)), dieJVM verlangt (ohne wenn und aber) die richtige Signatur fur main.

Diese oben beschriebenen Fehlerquellen sind die haufigsten, die Java spezifischsind. Syntaxfehler werden (wie in jeder Programmiersprache...) separat mitentsprechenden Fehlermeldungen vom Compiler ausgewiesen.

1.2.2 Wohin mit den Klassenfiles?

Diese Frage sollte man sich vor allem stellen, wenn man mit mehreren Klassenarbeitet. Gibt man beim Compilieren keine expliziten Parameter an, so werdendie Klassenfiles im selben Verzeichnis abgelegt wie die Sourcecodefiles. Fureinzelne Tests sollte das wie geschrieben keine Rolle spielen, bei “richtigen”Programmen sollte man diese Vorgehensweise nicht machen.

Hinweis: Was man noch wissen sollte: Sind Klassen voneinander abhangig,findet das der Compiler selbststandig heraus (in C++ ist das nicht so, hiermuss explizit im Makefile angegeben werden, welche Objekt-Files voneinanderabhangig sind...). Hierbei vergleicht der Compiler die Sourcecodefiles mit den

Page 10: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 5

Klassenfiles. Haben die Klassenfiles ein jungeres Datum als die Sourcecodefiles,wird ebenso automatisch neu compiliert.

Aus dieser Tatsache ergibt sich aber auch, dass der Compiler nicht nur wissenmuss, wo der Sourcecode liegt, sondern auch, wo die Klassenfiles liegen (an-sonsten konnte er ja nicht herausfinden, ob das Klassenfile “junger” als derSourcecode ist...).

Die Sourcecodefiles werden im angegeben Verzeichnis gesucht (bzw. bei Packa-ges, siehe Abschnitt 4.11, in Subverzeichnissen), im Pfad, der im Klassenpfad(siehe spater) spezifiziert wurde, oder in den Verzeichnissen, die via sourcepath-Parameter angegeben werden.

Das selbe gilt fur den Bytecode-Interpreter: Kann dieser die Klassenfiles nichtfinden, wird ein NoClassDefFoundError ausgelost.

>java SomeExampleException in thread "main" java.lang.NoClassDefFoundError: SomeExample

Sieht man eine solche Meldung auf der Konsole, passt der Klassenpfad nicht.Die Suche nach den Klassenfiles erfolgt entweder uber:

• einen Parameter -cp oder -classpath des Compilers bzw. Interpretersoder uber

• eine Umgebungsvariable CLASSPATH. Umgebungsvariablen werden abhangigvom Betriebssystem bzw. von der verwendeten Shell unterschiedlich ge-setzt. Unter Windows wird die Variable via:set CLASSPATH=.\classes;C:\users\users\hkrott\src\java\classesgesetzt, unter Unix (csh) verwendet man das Shell-Kommando:setenv CLASSPATH ./classes:/usr/users/hkrott/src/java/classes

Wenn man bash als Shell verwendet, muss man das Kommandoexport CLASSPATH=./classes:/usr/users/hkrott/src/java/classesausfuhren.

Vorsicht Falle: Der Suchpfad kann sinnvollerweise mehrere Verzeichnisse bzw.auch sog. jar-Files (was das ist, werden wir noch horen...) beinhalten. Sinnvol-lerweise (!@%@!?) gibt es je nach Betriebssystem unterschiedliche Trennzeichenzwischen den Eintragen: Unter Windows muss der Pfad mit einem Strichpunkt(“;”) getrennt werden, unter Unix ist es der Doppelpunkt (“:”)’. Uber dieseEigenheit stolpert man gelegentlich...

Wir wissen nun, wie man die Suche der Sourcecodefiles (mit -sourcecode bzw.-classpath) und der Klassenfiles steuern kann (via -cp bzw. -classpath undCLASSPATH), aber noch nicht, wie man den Speicherort beim Compilieren (mitjavac) festlegt: Diese Aufgabe ubernimmt der Parameter -d.

Vorsicht Falle: Wenn man den -d Parameter verwendet, sollte man sich si-cher sein, dass das angegebene Verzeichnis auch wirklich existiert! Existiert es

Page 11: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 6

nicht, erhalt man viiieeellle Fehlermeldungen, die richtig interpretiert werdenmussen...

Generell kann man fur großere Projekte empfehlen, ein eigenes Verzeichnis mitdem Namen classes anzulegen und die genannten Parameter zu verwenden.Eine mogliche Kommandofolge konnte etwas so aussehen:

>cd myproject>mkdir classes>javac -d ./classes -classpath ./classes -sourcepath./src src/*java>java -classpath ./classes MyProjectMainClass

Ich habe im obigen Beispiel bewusst nicht den sourcepath-Parameter verwen-det, um die Komplexitat gering zu halten. Der interessierte Leser kann das jagerne ausprobieren :) Als Trennzeichen wurde hier jenes fur Unix verwendet.

Hinweis: Es gabe noch wesentlich mehr zu den Parametern des Compilers undInterpreters zu schreiben. Fur die ersten Schritte sind jedoch die oben genannten(-cp bzw. -classpath und -d) ausreichend. Genauere Informationen sind uberden help-Parameter bzw. uber die Onlinehilfe abrufbar.

Das war also unser erstes Java Programm! Nun noch eine Liste mit Punkten,die wir nicht vergessen sollten:

• Es gibt in Java keine Funktionen, sondern nur Methoden!

• Bei Programmen muss die Methode main() mit der entsprechenden Si-gnatur (public static void main(String[] args) definiert werden.

• Der Sourcecode wird in einen Bytecode ubersetzt und von der JVM (JavaVirtuellen Maschine) interpretiert.

• Sourcedateinname entspricht Klassenname (Groß-/Kleinbuchstaben be-achten!)

• JVM gibt es fur verschiedene Betriebssysteme.

• Klassen werden uber einen Suchpfad gefunden (-cp und -classpath bzw.CLASSPATH-Umgebungsvariable.

Nun geht’s weiter mit einem etwas komplizierteren Beispiel.

1.3 Ein einfaches Beispiel

Wenn man die Programmiersprache Java etwas genauer untersucht, dann siehtman, dass bei der Toolsammlung (Software Development Kit) der Hersteller(Sun, IBM, etc.) eine Unmenge an Libraries mitgeliefert werden. In der aktuel-len Version vom SDK (Java 2 Platform, v 1.4) sind das ca. 3000 Klassen, welchedie unterschiedlichsten Aufgaben ubernehmen. Einige der Libraries stehen un-mittelbar zur Verfugung, andere wiederum mussen explizit angesprochen oder

Page 12: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 7

importiert werden. Im folgenden Beispiel verwenden wir Strings, die dem Pro-gramm in der Kommandozeile ubergeben werden. Strings stehen unmittelbarzur Verfugung und mussen nicht explizit geladen/importiert werden.

1 public class SimpleExample2 {3 public static void main( Str ing [ ] args )4 {5 // check number of arguments6 i f ( args . length == 0)7 {8 System . err . pr int ln (”Usage : java SimpleExample ” +9 ”argument1 [ argument2 . . . ] ” ) ;

10 System . err . pr int ln (” Get some information from the arguments ” +11 ”given to the program . ” ) ;12 return ;13 }14 System . out . pr int ln (”Hello and welcome to the argument processor ! ” ) ;15 System . out . pr int ln (”There are ” + args . length +16 ” argument ( s ) on the commandline . ” ) ;17 for ( int i =0; i<args . length ; i++)18 {19 System . out . pr int ln (”argument ” + ( i +1) + ” has ” + args [ i ] . length () +20 ” characters . Uppercase : ” + args [ i ] . toUpperCase ( ) ) ;21 }22 System . out . pr int ln (”That ’ s i t . Bye ! ” ) ;23 }24 }

Bei der Beschreibung gehen wir nun von oben nach unten. Wir arbeiten hiermit Strings und Arrays (Felder) von Strings und verwenden sogar schon einefor-Schleife :)

Zeile 1: Definition der Klasse SimpleExample.

Zeile 3: Diese hatten wir schon im ersten Beispiel: Definition der main-Methodeder Klasse SimpleExample. Beachte die Signatur!

Zeile 6: Ein If-Statement (siehe Abschnitt 3.3) uberpruft eine Bedingung.Wenn die Anzahl der Argumente (reprasentiert in einem Array von Strings)gleich 0 ist, dann soll das Programm mit einer Meldung abbrechen. Mankann bei einem Array (siehe Abschnitt 2.1.2) die Anzahl der gespeichertenElemente uber das Property (Eigenschaft des Objekts) length abfragen.

Zeile 9: Fur Fehlermeldungen sollte man Grundsatzlich stderr verwenden.stderr ist bei jedem Java-Programm via System.err verfugbar und wirdbeim Starten der JVM erstellt.

Zeile 12: Beendet das Programm an dieser Stelle und ubergibt die Kontrollewieder dem Betriebssystem. Im Abschnitt uber Fehlerkontrolle (siehe Ka-pitel 5) werden noch weiter Methoden vorgestellt, wie man mit falschenbzw. fehlerhaften Parametern umgeht.

Zeile 14-16: Schreibe auf die Konsole (=System.out).

Zeile 17: Fur jedes ubergebene Argument fuhre die folgenden Anweisungenaus. In Java wird – gleich wie in C++ – der Zahler fur die Array-Elementevon 0 weg gezahlt, d.h. das Elemente mit dem Index 0 ist das ersteElemente im Array. Siehe Abschnitt 3.2.

Page 13: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 8

Zeile 19/20: Hier werden die einzelnen Argumente behandelt. Die Argumentewerden als String zur Verfugung gestellt. Man beachte den Ausdruckargs[i].length(): Hier wird auf das i-te Element im Array zugegriffen(ist ein String) und auf dieses String-Objekt wird die Methode length()aufgerufen. Im Vergleich zum Array wird hier nicht ein Property, sonderntatsachlich eine Methode aufgerufen!

Zeile 20: Damit wir auch mit dem String arbeiten, wird hier der ubergebeneWert in Großbuchstaben ausgegeben. Schon hier soll auf eine Eigenschaftvon Strings hingewiesen werden: Strings sind immutable (unveranderlich),d.h. der String, der in args[i] abgelegt ist, verandert sich durch dentoUpperCase()-Methodenaufruf nicht.

Zeile 23: Ende der Methode main.

Zeile 24: Ende der Klassendefinition.

Hinweis: In C++ ist in argv[0] der Programmname gespeichert. Die Anzahlder Argumente wird via argc festgelegt. In Java gibt es bei main nur einenParameter (String[] args). Dieses Array ist ein Objekt und hat die Lange alsEigenschaft dieses Arrays (args.length). Das erste Argument wird in args[0]gespeichert. Den Namen der Klasse kann man via this.getClass().getName();herausfinden.

Compiliert wird das Programm (nun kann man schon schreiben “wie gewohnt”:)) mit javac SimpleExample.java. Ein Aufruf konnte so aussehen:

>java SimpleExample first second third-parameter "fourth parameter"Hello and welcome to the argument processor!There are 4 argument(s) on the commandline.argument 1 has 5 characters. Uppercase: FIRSTargument 2 has 6 characters. Uppercase: SECONDargument 3 has 15 characters. Uppercase: THIRD-PARAMETERargument 4 has 16 characters. Uppercase: FOURTH PARAMETERThat’s it. Bye!

Parameter werden also einfach durch Leerzeichen getrennt bzw. mit Anfuhrungs-zeichen ubergeben.

1.4 Ein einfaches Applet

So, bevor wir nun wirklich mit den in Java zur Verfugung gestellten Datenty-pen beginnen, noch ein einfaches Applet. Vielleicht ist es euch schon zu Ohrengekommen, dass es in Java Applikationen und Applets gibt. Einfache Appli-kationen haben wir bereits kennen gelernt. Applets hingegen sind Programme,die innerhalb eines Java-fahigen Webbrowsers verwendet werden konnen (mehrdazu aber wesentlich spater!). Vorab einmal ein ganz einfaches Beispiel:

Page 14: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 9

1 import java . applet . Applet ;2 import java . awt . Graphics ;3

4 public class SimpleAppletExample extends Applet5 {6 public void paint (Graphics gc )7 {8 gc . drawString (” I ’m a very simple applet ! ” , 10 , 10 ) ;9 }

10 }

Zeile 1/2: Wir verwenden hier das import Schlusselwort um anzudeuten, dasswir weitere Klassen verwenden (in diesem Fall java.applet.Applet undjava.awt.Graphics). Man konnte diese zwei Zeilen auch weglassen, muss-te dann allerdings den sog. full qualified name von der Applet- bzw.Graphics-Klasse angeben, wenn man sie verwenden will. Z.B., Zeile 4wurde dann nicht mehr “...extends Applet” lauten, sondern “...extendsjava.applet.Applet”. Das ist naturlich etwas umstandlich, deshalb wirdman das import Schlusselwort verwenden. Man kann auch mehrere Klas-sen aus einem Package mit einem Platzhalter importieren (z.B. importjava.applet.*), allerdings sollte man das nicht tun, da man relativschnell den Uberblick verliert, welche Klassen nun wirklich im Programmverwendet werden.

Zeile 4-10: Hier wird die Klasse SimpleAppletExample definiert. Die Erwei-terung extends Applet zeigt an, dass diese Klasse von der Klasse Applet(genauer java.applet.Applet) abgeleitet wird. Zu diesem Zeitpunkt bit-te noch nicht verzweifeln: Klassen und Objekte werden noch im Kapitel 4genauer erlautert.

Zeile 6: Definition der Methode paint, die als Parameter ein Objekt vom TypGraphics verwendet. Diese Methode wird automatisch nach dem Initiali-sieren eines Applets aufgerufen (mehr dazu auch hier spater...).

Zeile 8: Die Methode drawString vom Objekt gc wird mit den drei Parame-tern (text, x, y) aufgerufen.

Auch Applets mussen – selbstverstandlich – compiliert und damit in Bytecodeubersetzt werden (javac SimpleAppletExample). Der Aufruf des Programmserfolgt allerdings nicht mit java SimpleAppletExample (es wurde hier keinemain-Methode definiert!). Wie schon oben bemerkt, werden Applets innerhalbeines “Java enabled Webbrowsers” ausgefuhrt. Damit der Browser das Appletladen kann, werden in einer HTML-Seite spezielle Tags eingefugt.

1 <HTML>2 <HEAD>3 <TITLE>Using the SimpleAppletExample</TITLE>4 </HEAD>5 <BODY>6 Now the applet . . .7 <APPLET CODE=”SimpleAppletExample . c l a s s ” WIDTH=”200” HEIGHT=”25”>8 </APPLET>9 That ’ s i t !

10 </BODY>11 </HTML>

Page 15: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 10

In Zeile 7 sieht man die Anwendung des Applet-Tags (mit einigen Parametern).Wenn man nun diese HTML-Seite mit einem Webbrowser anschaut, sieht manfolgendes:

Abbildung 1.1: HTML-Seite mit dem Applet

Weiter will ich zu diesem Zeitpunkt gar nicht auf Applets eingehen. Diese Zei-len sollen nur den Unterschied zwischen Java-Applets und Java-Applikationenzeigen.

Viele Eigenschaften von C++ sind auch in Java vorhanden. Einige Konzeptesind sicherlich zu Beginn ungewohnt (jedes Problem wird mit Klassen beschrie-ben, die Methode main muss bei ausfuhrbaren Programmen mit einer bestimm-ten Signatur vorhanden sein...), andere Eigenschaften (z.B. Speichermanage-ment via GC, Garbage Collector) sowie die umfangreiche mitgelieferte API sindsehr angenehm und erleichtern – zumindest zu Beginn :) – den Umgang mit derSprache.

1.5 Kommentare

In Java gibt es zwei unterschiedliche Arten von Kommentaren: Jene, die “nur”Details im Sourcecode kommentieren, und jene, die zusatzliche fur die Doku-mentation von Klassen und Methoden verwendet werden.

Einfache Kommentare sind gleich wie in C++:1 // A simple one−l ine−comment . . .2

3 /∗ another comment over4 more than5 one l i n e ∗/6

7 /∗ the second kind8 may nest the f i r s t kind9 // so i t ’ s nice fo r debuging purpose

10 to comment out one block : ) ∗/

Jene Kommentare, die auch fur die Dokumentation verwendet werden, mussenselbstverstandlich speziell markiert werden. Die Auswertung dieser Kommenta-re ubernimmt ein spezielles Programm. Dieses Programm (javadoc) wird mitdem SDK mitgeliefert2.

1 /∗∗2 ∗ A simple example fo r a documentation−3 ∗ comment used by <b>javadoc</b>.4 ∗/5 public class SimpleExample . . .

2Ein weiteres sehr populares Programm zum Auswerten von Kommentaren ist Doxygen.Mit Doxygen konnen auch C++- und C-Programme dokumentiert werden. Naheres ist unterhttp://www.doxygen.org3u finden.

Page 16: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 1. ANATOMIE EINES JAVA-PROGRAMMS 11

Ein Dokumentationskommentar wird – wie im Beispiel dargestellt – uber “/**”eingeleitet. Da javadoc HTML-Seiten aus den Kommentaren erstellen kann,ist es auch moglich, Kommentare mit HTML-Tags zu formatieren.

Tags (@tagname) geben einzelnen Kommentaren eine bestimmte Bedeutung.Hier ein Auszug aus den vorhandenen Tags:

@author@version@param@return@throws. . .

Fur Referenzen innerhalb von Kommentaren wird das Tag @see verwendet.javadoc bietet noch viele weitere Moglichkeiten. Ein Blick in die Source-Filesder Java Platform sollte auf alle Falle gemacht werden, damit man sieht, wiedie Tags angewendet werden sollen ([Javadoc Homepage]).

1.6 Schlusselworter in Java

In Java 1.4 gibt es folgende 52 Schlusselworter, die (selbstverstandlich) nicht alsNamen fur Variablen oder Methoden verwendet werden durfen.

abstract assert boolean breakbyte case catch charclass const continue defaultdo double else extendsfalse final finally floatfor goto if implementsimport instanceof int interfacelong native new nullpackage private protected publicreturn short static strictfpsuper switch synchronized thisthrow throws transient truetry void volatile while

Tabelle 1.1: Schlusselworter in Java

Die Schlusselworter goto und const sind zwar definiert, finden aber in Java 2keine Verwendung. strictfp ist seit Java 2 ein Schlusselwort. true, false undnull sind reservierte Worte fur Werte von boolean-Datentypen bzw. Referenz-Datentypen.

Nachdem wir jetzt ein gewisses Gefuhl fur Java bekommen haben, konnen wireinzelne Sprachelemente genauer betrachten. Auf geht’s in die zweite Runde...

Page 17: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 2

Datentypen, Variablen undOperatoren

Java ist eine stark typisierte Sprache, d.h. jede Variable muss deklariert werdenund hat einen bestimmten Typ. Der Typ der Variable muss bereits zur Com-pilezeit bekannt sein. In diesem Kapitel beschaftigen wir uns mit den in Javazur Verfugung gestellten Datentypen. Wir werden Variablen deklarieren undOperationen mit ihnen ausfuhren.

2.1 Datentypen

Starten wir mit den Datentypen: Grundsatzlich gibt es zwei Arten von Daten-typen: Primitive- und Referenz-Datentypen.

Hinweis: Im Vergleich zu C gibt es in Java keine expliziten Zeiger, eigene Typ-Definitionen (typedef), Aufzahlungen (enum), Record-Typen (struct, union)und Bitfelder. Bei genauerem Hinsehen sieht man, dass man typedef, enum,struct und union und Bitfelder einfach mit Klassen abbilden kann (siehe Kapi-tel 4), die keine Methoden haben. In dieser Hinsicht ist Java sicher einfacher zuhandhaben, da man sich nur ein Schlusselwort merken muss. Uber die Tatsache,dass es keine Zeiger gibt, freuen sich sicher auch viele Entwickler :)

2.1.1 Primitive-Datentypen

Diese Kategorie der Datentypen kann man in zwei Typen klassifizieren: booleanund numerische Typen (und diesen wieder in Ganzzahlen- und Gleitkommaty-pen). Zu jedem Primitiven-Datentypen werden passenden Referenz-Datentypenin Form von Klassen zur Verfugung gestellt, die den jeweiligen Wert kapseln undunterschiedlichste Methoden bereitstellen. Zu int gibt es z.B. einen Referenz-Datentyp mit dem Namen Integer, zu byte einen mit dem Namen Byte usw.(siehe Abschnitt 2.1.2).

12

Page 18: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 13

Typ Große/Format Beschreibungboolean true/false Boolscher WertGanzzahlenbyte 8-bit 2-er Komplement

(-128 bis 127)Byte Ganzzahl

short 16-bit 2-er Komplement(-32768 bis 32767)

Short Ganzzahl

int 32-bit 2-er Komplement(-2147483648 bis2147483647)

Integer Ganzzahl

long 64-bit 2-er Komplement(-9223372036854775808bis 9223372036854775807)

Long Ganzzahl

char 16-bit Unicode Character(\u0000 bis \uffff, 0 bis65535)

Character

Gleitkommazahlenfloat 32-bit IEEE 754 Single-precision Gleitkom-

mazahldouble 64-bit IEEE 754 Double-precision Gleit-

kommazahl

Tabelle 2.1: Wertebereich von Primitiven-Datentypen

Wie man mit diesen Datentypen arbeitet, sehen wir etwas spater im Abschnitt 2.2.

Hinweis: In Java sind die numerischen Typen mit Ausnahme von char imVergleich zu C++ signed Datentypen. Das Schlusselwort unsigned gibt es inJava nicht!

Hinweis: Fur alle Primitiven-Datentypen wird vom Interpreter implizit aucheine String-Reprasentationen zur Verfugung gestellt. Wird ein Primitiver--Datentype im Kontext eines Strings verwendet, so wird die entsprechende String-Darstellung verwendet! Siehe auch Beispiel in Abschnitt 2.3.2.

boolean-Datentyp

Fur den boolean-Datentyp gibt es genau zwei Werte: true und false. Wie manin Tabelle 1.1 sehen kann, sind diese beiden Werte bereits definierte Schlussel-worter der Sprache.

Hinweis: Fur Kontrollstrukturen, die wir im nachsten Kapitel noch genauerkennenlernen werden, bedeutet das im Gegensatz zu C/C++, dass beim Ent-scheidungskriterium wirklich ein boolean-Wert ausgewertet wird. Der geubteC/C++-Guru muss hier also etwas umdenken und nicht if (int_value) {...},sondern explizit if (int_value != 0 ) {...} schreiben.

Page 19: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 14

Ganzzahlige-Datentypen (byte, short, int und long)

Im Vergleich zu C/C++ sind die Ganzzahligen-Datentypen nur als signed-Datentypen, d.h. mit Vorzeichen verfugbar. byte, short, int und long unter-scheiden sich lediglich im Wertebereich (siehe Tabelle 2.1).

Die Werte konnen, wie man es von anderen Programmiersprachen gewohnt ist,in unterschiedlichen Zahlensystemen interpretiert werden. Generell werden sieim Dezimalen-System interpretiert (z.B. int an_int = 10;). Uber bestimmteSchreibweisen (“0x” bzw. “0X” als Prefix) wird der Wert als hexadezimale Zahlinterpretiert bzw. “0” (die Zahl “Null”) als Prefix wird der Wert als oktale Zahlinterpretiert.

Dezimale Zahlen werden als 32-Bit Integer verarbeitet. Wenn ein “l” bzw. “L”unmittelbar einer Zahl folgt, wird die Zahl als long-Wert interpretiert (1234ist ein Wert vom Typ int, 1234L ein Wert vom Typ long). Damit long-Werte fehlerfrei gelesen werden konnen, wird ein großes-L empfohlen, um eineVerwechslung mit “1” zu vermeiden.

Fur Umwandlungen von Zahlen in Zeichenketten und umgekehrt, stellen diepassenden Referenz-Datentypen statische Methoden (siehe Abschnitt 4.5.2) zurVerfugung (z.B. Integer.toString(int), Integer.parseInt(String) bzw.Byte.parseByte(String)).

char-Datentyp

Wie man in Tabelle 2.1 sieht, kann man in diesem Datentyp alle Unicode-Zeichen (16-Bit) ablegen. Der Wert kann direkt zwischen Apostrophen (z.B.char a_char = ’a’;), uber den Latin-1 Zeichencode, oder uber den Unicode-Wert (z.B. char another_char = ’\u0061’;) definiert werden. Steuerzeichen(z.B. Tabulatoren) sind in Tabelle 2.2 dargestellt.

Der zum Primaren-Datentyp char passende Referenz-Datentyp Character bie-tet einige statische Methoden an, die mit einem Zeichen arbeiten konnen (z.B.Character.isLowerCase(char), Character.toLowerCase(char), etc.).

Zeichen Bedeutung\b Backspace\t Tabulator\n Newline\f Formfeed (Seitenvorschub)\r Carriage Return (CR)\" Double Quote\’ Single Quote\\ Backslash\xxx Latin-1 Zeichen, wobei xxx eine oktale Zahl (Basis

8) ist.\uxxxx Unicode Zeichen, wobei xxxx dem hexadezimalen

Zeichencode (Basis 16) entspricht.

Tabelle 2.2: Steuerzeichen

Page 20: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 15

Gleitkomma-Datentypen (float, double)

Zwei Datentypen stehen in Java fur Gleitkomma-Zahlen zur Verfugung: float(32-Bit) und double (64-Bit). Es besteht die Moglichkeit, die Werte auch miteinem Exponenten zu versehen (z.B. 13e3 bzw. 13E3). Beim Datentyp floatmuss bei der Zuweisung von Werten explizit ein f bzw. F folgen, ansonsten wirddas Programm nicht compiliert (“possible loss of precision...”). Wertevon Gleitkomma-Datentypen konnen nicht hexadezimal oder oktal ausgedrucktwerden.

Jedem Informatiker ist klar, dass Gleitkommazahlen in der Reprasentation imComputer nur eine Annaherung an den echten Wert der Zahl darstellen kann.Variablen vom Typ float (32-Bit) garantieren mindestens 6 signifikante De-zimalstellen, vom Typ double (64-Bit) garantieren mindestens 15 signifikanteDezimalstellen.

Interessant ist die Tatsache, dass auch Divisionen durch 0 mit den Gleitkomma-Datentypen berechnet werden konnen. Hierbei kommt es zu keiner Fehlermel-dung! Der Wert wird in diesem Fall richtigerweise auf “Infinity” gesetzt.Ebenso werden Divisionen durch Unendlich (Ergebnis: “0”) und auch die Divi-sion von 0 durch 0 richtig berechnet (Ergebnis: “Not-a-Number”). Wie sich derLeser inzwischen schon vorstellen kann, sind diese Werte in den entsprechendenReferenz-Datentypen Float und Double gespeichert.

In Java konnen Variablen von einem bestimmten Primaren-Datentyp, einer Va-riablen mit einem anderen Primaren-Datentyp zugewiesen werden. Ist der Wer-tebereich der neuen Variable großer, als der der ursprunglichen, erfolgt die Um-wandlung automatisch. Es ist also moglich, einer Variablen vom Typ double,den Wert einer Variablen vom Typ float zuzuweisen (widening conversion).Wenn die Umwandlung in die andere Richtung passiert (narrowing conversati-on), muss diese Konvertierung explizit uber sog. casts durchgefuhrt werden.

int an int = 13;byte a byte = (byte) an int ;short a short = ( short )13 .67 ;

Diese Umwandlung passiert gleich wie in C/C++. Bei der Umwandlung in derletzten Zeile (von einem float in einen short) wird einfach der Teil nach demKomma weggeschnitten. Fur Auf-/Abrundungen stehen statische Methoden inder Klasse Math zur Verfugung (z.B. Math.ceil(double), Math.floor(double)etc.).

Nun noch ein kurzes Beispiel, das die Maximalwerte der jeweiligen Primitiven-Datentypen ausgibt. Man sieht, dass hier auf die entsprechenden Referenz-Datentypen zuruckgegriffen wird, um die Maximalwerte zu setzen. Es wird hieraus Platzgrunden aber auch aus Grunden der Motivation nicht auf alle Metho-den und Eigenschaften dieser speziellen Referenz-Datentypen eingegangen. Derinteressierte Leser hat die Moglichkeit, den Sourcecode (z.B. src/java/lang/Byte.java) zu inspizieren.

1 public class PrimitiveMaxValuesExample2 {3 public static void main( Str ing args [ ] )4 {5 // boolean6 boolean a boolean = true ;

Page 21: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 16

7

8 // integer s / char9 byte l a rges t byte = Byte .MAXVALUE;

10 short l a r g e s t sho r t = Short .MAXVALUE;11 int l a r g e s t i n t = Integer .MAXVALUE;12 long l a rge s t l ong = Long .MAXVALUE;13 char a char = ’S ’ ;14

15 // rea l numbers16 f loat l a rges tF loat = Float .MAXVALUE;17 double largestDouble = Double .MAXVALUE;18

19 System . out . pr int ln (”The value of a boolean i s ” + a boolean ) ;20 System . out . pr int ln (”The l a rge s t byte value i s ” + larges t byte ) ;21 System . out . pr int ln (”The l a rge s t short value i s ” + la rg e s t sho r t ) ;22 System . out . pr int ln (”The l a rge s t integer value i s ” + l a r g e s t i n t ) ;23 System . out . pr int ln (”The l a rge s t long value i s ” + la rge s t l ong ) ;24

25 i f ( Character . isUpperCase ( a char ))26 {27 System . out . pr int ln (”The character ” + a char + ” i s upper case . ” ) ;28 }29 else30 {31 System . out . pr int ln (”The character ” + a char + ” i s lower case . ” ) ;32 }33

34 System . out . pr int ln (”The l a rge s t f l o a t value i s ” + larges tF loat ) ;35 System . out . pr int ln (”The l a rge s t double value i s ” + largestDouble ) ;36 }37 }

Aufruf auf der Konsole:exttt¿java PrimitiveMaxValuesExample

The value of a_boolean is trueThe largest byte value is 127The largest short value is 32767The largest integer value is 2147483647The largest long value is 9223372036854775807The character S is upper case.The largest float value is 3.4028235E38The largest double value is 1.7976931348623157E308

2.1.2 Referenz-Datentypen

Will man mehr als ein Zeichen oder eine Zahl in einer Variable speichern, mussman einen Referenz-Datentyp verwenden. Der Wert einer solchen Variable isteine Referenz (d.h. eine Adresse) zum Speicherbereich, wo ein Objekt abgelegtist. Der Speicher fur diese Variable muss selbstverstandlich reserviert werden.Zu den Referenz-Datentypen zahlen sowohl Klassen, als auch das Array (=Feldvon Werten).

Jeder Referenz-Datentyp ist von java.lang.Object abgeleitet und erbt die dar-in implementierten Methoden (Abschnitt 4.2). Eine besonders oft verwendeteMethode ist die toString()-Methode, die implizit aufgerufen wird, sobald dasObjekt im Kontext eines Strings verwendet wird.

In Java ist es nicht moglich, direkt auf Adressen zuzugreifen (wie z.B. in C oderC++ mit Pointer). Vor allem fur Anfanger ist das ein großer Vorteil, da man sich

Page 22: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 17

nicht um die Freigabe des Speichers kummern muss. Diese Aufgabe ubernimmtder “garbage collector” (GC, ein Modul in der Virtuellen Maschine). Wir werdenspater (Abschnitt 4.4) noch sehen, welche Methoden einer Klasse zur Verfugungstehen. Zu jedem Primaren-Datentyp gibt es – wie schon mehrfach angesprochen– einen passenden (und unveranderlichen, engl. immutable) Referenz-Datentypder u.a. statische Methoden zur Verfugung stellt.

In den folgenden Abschnitten werden zwei Klassen zum Speichern von Zeichen-ketten betrachten (String und StringBuffer) sowie Felder (Arrays) untersu-chen. Das Klassenkonzept von Java wird im nachsten Kapitel genauer erlautert.

String und StringBuffer

Mit Zeichenketten arbeitet man taglich, daher kommt hier ein kurzer Uberblickuber zwei Klassen, die mit Zeichenketten arbeiten konnen. Die Einsatzgebietefur diese beiden Klassen sind aufgrund der Eigenschaften unterschiedlich.

Die String-Klasse eignet sich zum Speichern von Zeichenketten, die sich nichtandern. Der Wert der gespeicherten Zeichenkette kann nicht mehr verandertwerden, d.h. Strings sind konstant (man sagt, die Klasse ist bzw. Objekte dieserKlasse sind immutable, also unveranderlich). Fur die interne Reprasentationvon Strings hat das den Vorteil, dass unterschiedliche String-Objekte, die dengleichen Wert haben, die selben Speicherbereiche verwenden konnen und damitSpeicherplatz gespart werden kann.

String-Objekte konnen entweder explizit mit dem new-Operator oder impli-zit uber doppelte Anfuhrungszeichen (double quotes) erzeugt werden. Im fol-genden Beispiel sieht man, wie das in einem praktischen Beispiel umgesetztwerden kann. Bis zur zweiten Zeile verwenden die Variablen a string undanother string intern den selben Speicherplatz! Erst in der dritten Zeile wirdein neues String-Objekt erzeugt und der Variablen another string zugewiesen.

String a s t r ing = new String (”some value of the s t r ing ” ) ;Str ing another str ing = ”some value of the s t r ing ” ;another str ing = ”changed value of the s t r ing ” ;

Vorsicht Falle: Die Tatsache, dass Strings konstant sind, muss man akzep-tieren. Ignoriert man diese Tatsache, konnen implizit viele String-Objekteerzeugt werden, die naturlich auch wieder aus dem Speicher entfernt werdenmussen. Das beeinflusst nicht nur das Speichermanagement sondern auch dasLaufzeitverhalten (siehe nachstes Beispiel) der Applikation.

Will man mit Zeichenketten arbeiten, die dynamisch zusammengesetzt werden,macht es Sinn, die StringBuffer-Klasse zu verwenden. Es werden in diesemFall weniger Objekte erzeugt und verworfen. Dadurch wird das Laufzeitver-halten des Programms insgesamt besser als bei der Verwendung von String-Objekten. Wie man mit Objekten arbeitet wird noch genauer im folgendenKapitel behandelt. Ein Beispiel sagt mehr als 1000 Worte.

1 public class StringExample2 {3 public static void main( Str ing [ ] args )4 {5 String a s t r = ”value of a s t r ” ;

Page 23: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 18

6 Str ingBuffer a s t r bu f = new Str ingBuffer (”value of a s t r bu f ” ) ;7 String append = ”append th i s value . . . ” ;8 long s tart t ime ;9 long end time ;

10 f inal int LOOPCOUNT = 1000;11

12 // append now to String−Object13 s tart t ime = System . currentTimeMill is ( ) ;14 for ( int count = 0; count < LOOPCOUNT; count++)15 {16 a s t r += append ;17 }18 end time = System . currentTimeMill is ( ) ;19 System . out . pr int ln (”Working with String−Objects costs ” +20 ( end time − s tart t ime ) + ” msec . ” ) ;21 System . out . pr int ln (” a s t r . length ( ) i s : ” + a s t r . length ( ) ) ;22

23 // append now to StringBuffer−Object24 s tart t ime = System . currentTimeMill is ( ) ;25 for ( int count = 0; count < LOOPCOUNT; count++)26 {27 a s t r bu f . append(append ) ;28 }29 end time = System . currentTimeMill is ( ) ;30 System . out . pr int ln (”Working with StringBuffer−Object costs ” +31 ( end time − s tart t ime ) + ” msec . ” ) ;32 System . out . pr int ln (” a s t r bu f . length ( ) i s : ” + a s t r bu f . length ( ) ) ;33 }34 }

Aufruf auf der Konsole:exttt¿java StringExample

Working with String-Objects costs 598 msec.a_str.length() is: 20014Working with StringBuffer-Object costs 3 msec.a_str_buf.length() is: 20018

Fur die beiden Klassen zur Behandlung von Zeichenketten gibt es selbstverstand-lich noch wesentlich mehr Methoden als die hier vorgestellte Methode length().Da wir Klassen und Methoden erst im nachsten Kapitel eingehender behandelnwerden, macht es zu diesem Zeitpunkt noch keinen Sinn, naher auf die beidenKlassen einzugehen. Der interessierte Leser hat die Moglichkeit, schon jetzt dieonline-Dokumentation der beiden Klassen durchzublattern. Neben Zeichenket-ten werden auch Felder (arrays) in Java speziell behandelt.

Arrays

Arrays sind Referenz-Datentypen, in denen Werte eines beliebigen Datentypsgespeichert werden, d.h. es konnen selbstverstandlich auch Arrays in einem Ar-ray gespeichert werden. Sie sind immer typisiert. Nun einmal zwei Beispiele, wieArrays deklariert werden konnen: Einmal ist [] nach dem Variablennamen, undeinmal nach dem Typ (siehe auch examples/datentypen/IntArrayExample.java).

int in t ar ray [ ] ;int [ ] another int array ;

Die Lange des Arrays spielt bei der Deklaration keine Rolle. Eine Deklarationeiner Variable ist naturlich zu wenig um damit arbeiten zu konnen. Varia-

Page 24: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 19

blen mussen auch definiert werden, damit sie verwendet werden konnen (Ab-schnitt 2.2)!

Wird nun versucht, auf die oben deklarierten Variablen int array bzw. another-int array zuzugreifen, wird bereits beim Compilieren ein Fehler ausgegeben(variable int array might not have been initialized).

Erst bei der Definition wird Speicher fur die Elemente reserviert und damit dieLange des Arrays festgelegt. Die Definition erfolgt uber den new-Operator. Dasnachste Beispiel zeigt Arrays unterschiedlicher Lange vom Typ int:

in t ar ray = new int [ 5 ] ;another int array = new int [ 2 ] ;

Nach dem Erzeugen des Arrays werden die Werte im Array mit dem Default-Wert des Datentyps initialisiert. In unserem Fall (Array mit int Elementen)ist das der Wert 0.

Deklaration und Definition konnen auch in einem Schritt erfolgen: Im folgendenBeispiel in der ersten Zeile das Array mit den Default-Werten initialisiert, inder zweiten Zeile werden den Elementen bereits bei der Definition bestimmteWerte zugewiesen.

int [ ] some int array = new int [ 4 ] ;int [ ] some other int array = { 1 , 2 , 3 } ;

Vorsicht Falle: Werden in einem Array Elemente eines Referenz-Datentypsgehalten, so wird lediglich Speicher fur die Referenzen (nicht fur die Objekteselbst!) reserviert, d.h. die Elemente in dem Array werden auf die Default-Werte von Referenz-Datentypen (=null) gesetzt. Diesen Umstand sollte mannicht ignorieren (siehe ObjectArrayExample.java).

Die Anzahl der Werte (=Lange des Arrays), die in einem Array gespeichertwerden konnen, ist in der Eigenschaft (engl. property) length des Arrays ge-speichert. Der Zugriff auf einzelne Elemente erfolgt intuitiv (wie in C++) uberdie Variable, gefolgt von dem Index in eckigen Klammern. Der Index beginntwie in C/C++ gewohnt bei 0 und geht bis length-1.

in t ar ray [ 1 ] = 1 ;int ar ray [ 2 ] = 3 ;int ar ray [ 3 ] = 5 ;

for ( int count = 0; count < in t ar ray . length ; count++){

System . out . pr int ln (”content of int ar ray at index : ” +int ar ray [ count ] ) ;

}

Wenn versucht wird, mit einem ungultigen Elementindex (kleiner 0 bzw. großerlength-1) auf das Array zuzugreifen, so wird eine java.lang.ArrayIndexOut-OfBoundsException-Exception (siehe Kapitel 5) generiert.

Vorsicht Falle: Die bei der Definition der Array-Variable festgelegte Großekann nachtraglich nicht verandert werden. Wenn man daher ein Array ver-großern will, muss man ein neues Array mit der gewunschten Große anlegenund die Werte in dieses neue Array kopieren. Fur spezielle Anwendungen ste-hen naturlich vorgefertigte Klassen zur Verfugung (java.util.Vector etc.) aufdie jetzt nicht eingegangen wird.

Page 25: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 20

Sollen die Werte von einem Array in ein anderes kopiert werden, so kann mandas entweder selbst implementieren (kopiere Element fur Element), oder manverwendet die arraycopy-Methode vom System-Objekt. Wenn man die Si-gnatur dieser Methode in java/lang/System.java betrachtet, sieht man, dassdiese Methode native in der JVM ausgefuhrt wird. Es ergeben sich dadurchPerformance-Vorteile.

Fur Arrays mit primitiven Datentypen ist das Verhalten beim Kopieren offen-sichtlich: Es werden die Werte der Elemente kopiert. Bei Arrays mit Referenz-Datentypen als Elemente ist das Verhalten auf den ersten Blick vielleicht nichtganz verstandlich: Es werden in diesem Fall nur die Werte der Referenzen ko-piert, nicht die Inhalte selbst! Dieses Verhalten sollte im nachsten Kapitelklarer werden. Die Syntax von System.arraycopy:

System . arraycopy ( src array , s r c s ta r t index ,dest array , dest s tart index , length ) ;

Ist src array und dest array gleich, wird das Feld so kopiert, als ob die Wertevon src array zuerst in ein temporares Objekt kopiert werden, und erst dannuber arraycopy verwendet werden.

Auch hier soll ein Beispiel die Anwendung von arraycopy zeigen:

1 public class ObjectArrayExample2 {3 public static void main( Str ing [ ] args )4 {5 Object [ ] obj array ;6 Object [ ] another array = new Object [ 3 ] ;7 obj array = new Object [ 2 ] ;8

9 // set values of obj array . . .10 String a s t r ing = new String (”Hello ” ) ;11 Str ingBuffer a s t r ing bu f = new Str ingBuffer (”StringBuffer−Object” ) ;12 obj array [0 ] = a s t r ing ;13 obj array [1 ] = a s t r ing bu f ;14

15 System . out . pr int ln (” length of obj array : ” + obj array . length ) ;16 System . out . pr int ln (” length of another array : ” + another array . length ) ;17 System . out . pr int ln (”Copy now contents of obj array to another array . . . ” ) ;18 System . arraycopy ( obj array , 0 , another array , 1 , 2 ) ;19

20 System . out . pr int ln (”Contents of obj array i s : ” ) ;21 for ( int count = 0; count < obj array . length ; count++)22 {23 System . out . pr int ( obj array [ count ] ) ;24 }25

26 System . out . pr int ln (”\nContents of another array i s : ” ) ;27 for ( int count = 0; count < another array . length ; count++)28 {29 System . out . pr int ( another array [ count ] ) ;30 }31

32 System . out . pr int ln (”\nChange now values of r e f e r ence s . . . ” ) ;33 a s t r ing = new String (”Hi ” ) ;34 a s t r ing bu f . append(” changed” ) ;35

36 System . out . pr int ln (”Contents of obj array i s : ” ) ;37 for ( int count = 0; count < obj array . length ; count++)38 {39 System . out . pr int ( obj array [ count ] ) ;40 }41

42 System . out . pr int ln (”\nContents of another array i s : ” ) ;

Page 26: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 21

43 for ( int count = 0; count < another array . length ; count++)44 {45 System . out . pr int ( another array [ count ] ) ;46 }47 }48 }

Aufruf auf der Konsole:exttt¿java ObjectArrayExample

length of obj_array: 2length of another_array: 3Copy now contents of obj_array to another_array...Contents of obj_array is:Hello StringBuffer-ObjectContents of another_array is:nullHello StringBuffer-ObjectChange now values of references...Contents of obj_array is:Hello StringBuffer-Object changedContents of another_array is:nullHello StringBuffer-Object changed

Interessant im obigen Beispiel ist, dass zwar eine Anderung des StringBuffer-Objekts in Zeile 34 in beiden Feldern sich nach dem Kopieren auswirkt, jedochdie Anderung des String-Objekts keine Anderung in den Arrays bewirkt. Nachden Ausfuhrungen zu String- und StringBuffer-Objekten sollte dieses Verhal-ten allerdings klar sein, da Strings immutable sind und sich in Zeile 33 nicht derWert, sondern die Referenz andert!

Zu diesem Zeitpunkt ware es noch viel zu fruh, sich mit weiteren moglichenFehlern auseinander zusetzen (dest array konnte z.B. zu klein sein, oder null,oder...). Hier verweise ich auf spater...

Mehrdimensionale Arrays

Mehrdimensionale Arrays sind einfach Arrays von Arrays [von...], wobei auchdie geschachtelten Arrays unterschiedliche Langen haben konnen. Im folgendenBeispiel wird ein zweidimensionales Array unterschiedlicher Langen erzeugt unddann dargestellt.

1 public class MultidimensionalArrayExample2 {3 public static void main( Str ing [ ] args )4 {5 int [ ] [ ] in t ar ray array = {{ 1 , 2 , 3 } ,6 { 4 , 5 , 6 , 7 , 8 } ,7 { 9 , 10 , 11 , } ,8 { 12 , 13 , 14 }} ;9

10 for ( int rows=0; rows<in t ar ray array . length ; rows++)11 {12 for ( int columns=0; columns<in t ar ray array [ rows ] . length ; columns++)13 {14 System . out . pr int ln (” int ar ray array [ ” + rows + ” ] [ ” + columns + ” ] : ” +15 in t ar ray array [ rows ] [ columns ] ) ;

Page 27: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 22

16 }17 }18 }19 }

Aufruf auf der Konsole:exttt¿java MultidimensionalArrayExample

int_array_array[0][0]: 1int_array_array[0][1]: 2int_array_array[0][2]: 3int_array_array[1][0]: 4int_array_array[1][1]: 5int_array_array[1][2]: 6int_array_array[1][3]: 7int_array_array[1][4]: 8int_array_array[2][0]: 9int_array_array[2][1]: 10int_array_array[2][2]: 11int_array_array[3][0]: 12int_array_array[3][1]: 13int_array_array[3][2]: 14

Auch hier gilt: Sollen Referenz-Datentypen in einem Array gespeichert werden,so muss wieder Speicher fur die eigentlichen Objekte reserviert werden (sieheauch Sun-Tutorial1).

2.2 Variablen

Die Begriffe Deklaration und Definition haben wir bereits verwendet. Zur Si-cherheit kommt noch einmal die Definition der Deklaration und Definition:

Deklaration: Hier wird ein Bezeichner (identifier) bekannt gegeben. Uber die-sen Bezeichner kann dann auf den deklarierten Bereich zugegriffen werden.Es wird bei der Deklaration kein Speicherbereich fur eine Referenztyp-Variable reserviert! Bsp.:

String a s t r ing ;int [ ] an int array ;

Der Bezeichner darf kein Schlusselwort sein (siehe Abschnitt 1.6). Hierkonnte der Compiler nicht feststellen, dass es sich um eine Variablen-Deklaration handelt und wurde eine Fehlermeldung ausgeben.

Definition: Bei einer Definition wird fur Variablen Speicher reserviert oder furMethoden eine Implementation zur Verfugung gestellt. Bei Variablen mitPrimitive-Datentyp ist die Deklaration gleichzeitig die Definition. Auchfur Referenz-Datentypen kann die Deklaration und die Definition in einerZeile erfolgen. Bsp.:

1http://java.sun.com/docs/books/tutorial/java/data/arrays.html

Page 28: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 23

String a s t r ing = new String (”value of the s t r ing ” ) ;int [ ] an int array = new int [ 2 5 ] ;

Eine Variable entspricht einem Speicherbereich eines bestimmten Typs. DieserDatentyp wird bei der Deklaration der Variable angegeben.

So, nun die Definition von Variablen, wie sie in der Spezifikation steht (mit demWissen, dass diese Zeilen hier nicht auf Anhieb verstanden werden konnen):Primitiv-Datentyp Variablen halten genau den Datentyp, der bei der Variablen-Definition angegeben wurde. Referenz-Datentyp Variablen halten entwedereinen null type oder eine Referenz zu einer Variablen mit genau dem Datentyp(oder einem abgeleiteten Datentyp), der bei der Deklaration angegeben wurde.

Variablen vom Typ interface halten entweder einen null type oder eine Instanzeiner Klasse, die dieses Interface implementiert. Schließlich gibt’s dann noch denarray type, der sowohl auf Primitiv- als auch auf Referenz-Datentypen angewen-det werden kann: Bei einem Array von Primitiv-Datentypen ist hier entwedereine null-Referenz gespeichert, oder es ist eine Referenz zu einem Array vomentsprechenden Typ gespeichert. Bei Arrays mit Referenz-Datentyp Variablenkann es sich auch um einen abgeleiteten Datentyp handeln ([Gosling et al.,1996]).

Wer diese beiden Absatze sofort verstanden hat: Meine Gratulation. Auf dennachsten Seiten sind einige Beispiele mit Variablen und den unterschiedlichstenDatentypen zu finden. Diese Beispiele sollten zum Verstandnis beitragen.

2.2.1 Deklaration von Variablen

Variablen mussen deklariert werden, bevor sie verwendet werden konnen. DieseDeklaration schaut generell wie folgt aus:

[ f inal ] type name ;

Implizit ergibt sich je nachdem, wo die Deklaration einer Variablen passiert, einGultigkeitsbereich (scope) fur die Variable (siehe Abschnitt 2.2.3).

final: Eine Variable darf nur einmal initialisiert werden.

type: Primitiv- oder Referenz-Datentyp

name: Der Name einer Variable kann nicht beliebig sein. Die Lange ist zwarunbeschrankt, aber folgende Bedingungen sind einzuhalten:

• Das erste Zeichen darf keine Zahl sein;

• Keine Zeichen, die in der Sprache verwendet werden (z.B. “.”, “,”,“+”, etc.)

• Der Name darf kein Schlusselwort sein (if, while, etc. siehe 1.6).

• Der Name darf kein in Java reserviertes Wort sein (true, false odernull);

• Der Name muss eindeutig im Scope sein, d.h. eine Variable darf nureinmal im Scope deklariert werden.

Page 29: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 24

Fur die Vergabe von Namen der Variablen sind je nach Art (member- oder auto-bzw. lokale-Variable) bestimmte Konventionen einzuhalten (siehe z.B. [PPrakt.Java Coding 2002]).

Vorsicht Falle: Es gibt unterschiedliche Meinungen zu final in Java vs. constin C++. Tatsache ist, dass bei final die Variable nur einmal initialisiert wer-den darf. Fur Primitive-Datentypen ist das Verhalten wie man es sich vorstellt:Einmal initialisiert, darf der Wert der Variable nicht mehr verandert werden.Der Compiler gibt entsprechende Fehlermeldungen aus, wenn man es trotzdemversucht. Arbeitet man nun mit Referenz-Datentypen, die Veranderungsmetho-den anbieten, dann kann der Wert der Variablen nach dem Initialisieren abersehr wohl verandert werden. Dieses Verhalten ist auf den ersten Blick vielleichtnicht ganz intuitiv.

Betrachtet man nun das const-Schlusselwort in C++, dann kann man Objek-te, die mit dem Schlusselwort const deklariert wurden, tatsachlich nicht mehrverandern. Bei genauerer Betrachtung sieht man allerdings sofort, dass manjederzeit mit dem const cast-Operator ein Objekt, das ursprunglich konstantdeklariert wurde, verandern kann!

Eine mogliche Art, ein Objekt konstant sein zu lassen, ist die, dass man keineVeranderungsmethoden fur die jeweilige Klasse implementiert und keine direk-ten Zugriff auf Membervariablen zulasst. Dieser Ansatz wird in Java konsequentverfolgt (siehe z.B. String-Klasse) und sollte auch im eigenen Klassendesignumgesetzt werden.

Nun noch ein Beispiel, dass die Verwendung von final bei einem Primitiven-Datentyp demonstriert:

1 public class PrimitiveFinalExample2 {3 public static void main( Str ing [ ] args )4 {5 f inal int AN INT;6 f inal int ANOTHER INT = 10;7 int some int ;8

9 // the fo l lowing i s allowed . . .10 AN INT = 100;11 // not allowed , because var iab le i s already i n i t i a l i z e d12 // ANOTHER INT = 100;13 // allowed14 some int = AN INT;15 // not allowed , because an int i s already i n i t i a l i z e d16 // AN INT = some int ;17 }18 }

Wenn die Kommentare in Zeile 12 bzw. 16 weggenommen werden, lasst sich dasProgramm nicht ubersetzen:

>javac PrimitiveFinalExample.javaPrimitiveFinalExample.java:12: cannot assign a value to final

variable ANOTHER_INTANOTHER_INT = 100;^

1 error

Page 30: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 25

bzw.

>javac PrimitiveFinalExample.javaPrimitiveFinalExample.java:16: variable AN_INT might already

have been assigned toAN_INT = some_int;^

1 error

Ein Beispiel mit einem Referenz-Datentyp ist bei den Ubungsbeispielen zu finden(example/datentypen/ReferenceFinalExample.java).

2.2.2 Default Werte

Wird einer Variable nicht explizit ein Wert zugewiesen, so wird sie mit einemdefault-Wert initialisiert (ausgenommen sind hier die lokalen Variablen, sieheAbschnitt 2.2.3). In Tabelle 2.3 wird ein Uberblick uber die default-Werteunterschiedlicher Datentypen gegeben. Der Referenz-Datentyp wird mit demreservierten Wort null initialisiert.

Typ Default Wertbyte (byte)0short (short)0int 0long 0Lfloat 0.0fdouble 0.0dchar \u0000boolean falsereference type null

Tabelle 2.3: Default Werte von Variablen

2.2.3 Arten und Scope von Variablen

Je nachdem, in welchem Bereich der jeweiligen Klasse die Variablen definiertwerden, findet die Initialisierung unterschiedlich statt und der Gultigkeitsbereichist unterschiedlich. Grundsatzlich kann an jeder Stelle des Programms eineVariable deklariert werden. In der Java-Spezifikation wird zwischen folgenden7 Variablenarten unterschieden:

Klassenvariable: Variablen, die in einer Klassendefinition static (oder ineiner Interfacedefinition mit oder ohne dem static-Schlusselwort) dekla-riert werden (mehr dazu etwas spater...). Die Variable wird mit einemdefault-Wert initialisiert, sobald die Klasse das erste Mal geladen wird.Alle Instanzen dieser Klasse teilen sich diese Variable! Die Lebenszeitder Variable (lifetime) endet, sobald das letzte Objekt dieser Klasse vomSpeicher entfernt wird (d.h. nicht mehr verwendet wird).

Page 31: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 26

Hinweis: Wie man den Zugriff auf Klassen- und Instanzvariablen vonaußen (d.h. von anderen Klassen und auch Packages) beschranken kann,wird noch ausfuhrlich in Abschnitt 4.5 behandelt.

Instanzvariable: Variablen, die ohne das Schlusselwort static in einer Klassedeklariert werden. Jede Instanz der Klasse, also jedes Objekt der Klasse,hat eine private Instanzvariable. Diese Variable wird auf den default-Wert initialisiert, sobald die Instanz erzeugt wird und noch bevor derKonstruktor der Klasse aufgerufen wird. Wenn das Objekt aus dem Spei-cher geloscht wird (d.h. nicht mehr referenziert wird), wird auch derSpeicherbereich dieser Variable freigegeben und es kann nicht mehr dar-auf zugegriffen werden (wie sollte man auch, wenn keine Referenz mehrda ist?).

Array Elemente: Elemente eines Arrays haben keinen Namen und werdenerzeugt und initialisiert, wann immer das entsprechende Array erzeugtwird. Die lifetime endet, wenn es keine Referenz mehr auf das Array gibt.

Lokale Variablen: Diese Variablen werden bei der Deklaration der Variablengultig, und sobald der Block wieder verlassen wird, werden sie wiederungultig. Es werden hier keine default-Werte gesetzt! Beim Zugriff aufnicht initialisierte lokale Variablen gibt der Compiler eine Fehlermeldungaus.

Vorsicht Falle: Fur lokale Variablen gibt es keine default-Wert Initiali-sierung!

Methoden Parameter: Sobald Methoden aufgerufen werden, werden dieseParameter-Variablen auf den Wert, mit dem sie aufgerufen werden initia-lisiert. Gultig sind die Variablen nur innerhalb der Methode.

Hinweis: Bei Methodenaufrufen gibt es im Unterschied zu C++ keinedefault-Werte fur Parameter!

Vorsicht Falle: In Java werden die Parameter ausschließlich via call-by-value ubergeben. Wenn Referenz-Datentypen verwendet werden, wird derWert der Referenz (also die Adresse der Variable) ubergeben.

Konstruktor Parameter: Sobald ein Objekt instantiiert und der Konstruk-tor der Klasse aufgerufen wird, werden diese Parameter mit dem Wert desubergebenen Parametern initialisiert. Wird der Konstruktor beendet, soverlieren auch die Konstruktor-Parameter ihre Gultigkeit.

Exceptionhandler Parameter: Sobald der catch-Block eines try-catch-Blocksverarbeitet wird, werden diese Variablen auf die entsprechenden Werte in-itialisiert. Der Gultigkeitsbereich endet, wenn der catch-Block verlassenwird. Siehe Kapitel 5.

Page 32: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 27

Da wir Exceptions und Konstruktoren etwas spater behandeln werden, vorabeinmal ein kleines Programm, das den Scope von Variablen zeigt.

1 public class ScopeOfVariables2 {3 // a simple c l a s s wide var iab le shared over a l l instances of4 // th i s c l a s s5 static int a c l a s s i n t = 10;6 // an instance wide var iab le7 int an ins tance int = 10;8

9 // some method with some method parameter , scope of th i s10 // parameters i s r ight in the method !11 public void changeVariables ( int a method int , int another method int )12 {13 // l o ca l var iab le s must be i n i t i a l i z e d before they can be used14 int a l o c a l i n t = 12;15 // note that the fo l lowing var iab le i s shared over a l l16 // instances17 a c l a s s i n t += 10;18 // now the instance integer var iab le19 System . out . pr int ln (”−−−−−−−−−−−−−−−−−−−−\n” +20 ”a method int : ” + a method int + ”\n” +21 ”another method int : ” + another method int + ”\n” +22 ” a l o c a l i n t : ” + a l o c a l i n t + ”\n” +23 ” a c l a s s i n t : ” + a c l a s s i n t + ”\n” +24 ” an ins tance int : ” + an ins tance int ) ;25 }26

27 public static void main( Str ing [ ] args )28 {29 ScopeOfVariables scope tes t = new ScopeOfVariables ( ) ;30 ScopeOfVariables another scope test = new ScopeOfVariables ( ) ;31

32 scope tes t . an ins tance int += 10;33 scope tes t . changeVariables ( 1 , 2 ) ;34 scope tes t . changeVariables ( 1 , 2 ) ;35 another scope test . changeVariables ( 3 , 4 ) ;36 }37 }

Aufruf auf der Konsole:exttt¿java ScopeOfVariables

--------------------a_method_int: 1another_method_int: 2a_local_int: 12a_class_int_: 20an_instance_int_: 20--------------------a_method_int: 1another_method_int: 2a_local_int: 12a_class_int_: 30an_instance_int_: 20--------------------a_method_int: 3another_method_int: 4a_local_int: 12a_class_int_: 40an_instance_int_: 10

Page 33: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 28

Fur ein erstes Verstandnis sollte dieses Programm ausreichend sein. Man solltewirklich den Unterschied zwischen den Arten dieser Variablen verstehen, damitman bei der Softwareentwicklung nicht unerwartete Seiteneffekte produziert.

2.3 Operatoren

Der Abschluss dieses Kapitels bilden die Operatoren, die auf Variablen ange-wendet werden konnen. Operatoren bilden den Grundstein jeder Programmier-sprache.

Ein Operator, der einen Operanden verwendet, heißt unarer Operator (z.B.some int--), einer, der zwei Operanden verwendet, binarer Operator (z.B. some -int + other int). Es gibt – wie in C++ – auch Operatoren, die mit drei Ope-randen verwendet werden, namlich die Kurzform von “if...then...else...”:“op1 ? op2 : op3” (ternarer Operator).

Operatoren werden in einer bestimmten Reihenfolge ausgewertet. Von der Ma-thematik wird bekannt sein, dass “Punkt-vor-Strich”-Rechnung gilt, d.h. eineMultiplikation wird vor einer Addition ausgefuhrt. Die Reihenfolge kann uberKlammerung der Ausdrucke beeinflusst werden.

Auch bei Programmiersprachen wird festgelegt, wann eine Operation ausgefuhrtwird. Jedem Operator wird eine bestimmte Rangordnung (“R” in der Tabelle,je hoher die Rangordnung, desto fruher die Auswertung) zugewiesen. Nachdieser Rangordnung werden Ausdrucke ausgewertet. Die Reihenfolge kann uberKlammerung beeinflusst werden.

Hinweis: Im Vergleich zu C++ gibt es in Java kein Operator-Overloading!Diese Designentscheidung wurde getroffen, um Fehlerquellen fur ungeubte Pro-grammierer von vorne herein auszuschalten. Operatoren konnen uber Metho-den in Klassen implementiert werden. Statt a += b; kann man eine Metho-de add() implementieren, die diese Aufgabe ubernimmt. Der Aufruf waredann a.add(b);. Diese Schreibweise ist man gewohnt und man wird Operator-Overloading gar nicht vermissen...

Hinweis: Der obige Hinweis muss noch erganzt werden: Es gibt fur die Ent-wickler von Java-Programmen kein Operator-Overloading. In Wirklichkeit gibtes namlich Operator-Overloading auch in Java. Als Beispiel kann die String-Klasse hergenommen werden. Hier wurden sehr wohl die Operatoren “+” und“+=” verwendet, um Zeichenketten zu manipulieren.

Nun aber zu den einzelnen Operatoren mit kurzen Erlauterungen. Bei derBeispielsammlung sind einige Tests mit den Operatoren implementiert.

2.3.1 Unare Arithmetische Operatoren

Post-Inkrement (op++) und Post-Dekrement (op--) tragen mit ihren Gegen-stucken Pre-Inkrement (++op) und Pre-Dekrement (--op) wohl am meisten zurVerwirrung von unerfahrenen Softwareentwicklern bei. Im folgenden Beispiel

Page 34: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 29

R Operator Verwendung Beschreibung14 + +op op wird zu int14 - -op Negatives Vorzeichen15 ++ op++ Post-Inkrement: op wird retur-

niert und erst dann inkremen-tiert

15 -- op-- Post-Dekrement: op wird retur-niert und erst dann dekremen-tiert

14 ++ ++op Pre-Inkrement: inkrementiere opund returniere danach op

14 -- --op Pre-Dekrement: dekrementiereop und returniere danach op

Tabelle 2.4: Unare Arithmetische Operatoren:

wird noch einmal gezeigt, wie sich Post-Inkrement und Pre-Dekrement auswir-ken.

// i n i t i a l i z e an intint an int = 5;

// return an int to another int and increment an int ;// another int == 5; an int == 6;

int another int = an int++;

// dekrement an int and return then the value to some int ;// some int == 5; an int == 5;

int some int = −−an int ;

Wenn man sich unsicher ist: Bitte unbedingt einige Programme dazu schreibenund wirklich versuchen zu verstehen, worum es hier geht. Diese Konstruktekommen sehr sehr oft in Programmen vor!

2.3.2 Binare Arithmetische Operatoren

Binare Arithmetische Operatoren funktionieren so, wie man es erwartet. Inter-essant ist der +-Operator, der auch fur Strings angewendet werden kann. Eskann daher notwendig sein, Ausdrucke mit Klammern zu versehen.

// the fo l lowing pr ints ” Hello ! 12”System . out . pr int ln (”Hello ! ” + 1 + 2);

// vs . ” Hello ! 3”System . out . pr int ln (”Hello ! ” + (1 + 2)) ;

Sollten ganzzahlige Datentypen bei der Division (/) verwendet werden, dannwird bei einer Division durch 0 eine Exception (ArithmeticException) abge-setzt. Fur Gleitkomma-Datentypen wird – wie schon in Abschnitt 2.1.1 erlautert– ein spezieller Wert als Ergebnis gesetzt.

Hinweis: Der Modulo-Operator (%) funktioniert im Unterschied zu C/C++nicht nur fur Ganzzahlige-Datentypen, sondern auch fur Gleitkomma-Datentypen.

Page 35: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 30

R Operator Verwendung Beschreibung11 + op1+op2 Addiert op1 zu op211 - op1-op2 Subtrahiert op2 von op112 * op1*op2 Multipliziert op1 mit op212 / op1/op2 Dividiert op1 durch op212 % op1%op2 Berechnet den Rest von op1/op2

Tabelle 2.5: Binare Arithmetische Operatoren:

2.3.3 Vergleichsoperatoren

Bei Kontrollfluss-Steuerungen, die wir im nachsten Kapitel ausfuhrlicher ken-nenlernen werden, sind Vergleichsoperatoren notwendig. Fur Primitive-Datentypenfunktionieren die Operatoren wie man es erwartet. Werden unterschiedlicheDatentypen miteinander verglichen, wird automatisch in den jeweils großerenDatentyp konvertiert.

Bei den speziellen Werten wie sie bei Gleitkomma-Datentypen eingefuhrt wur-den (NaN, etc.) gibt es statische Methoden von Klassen (z.B. Float.isNan()))die Gleichheit bzw. Ungleichheit uberprufen konnen.

Fur Referenz-Datentypen, wo man z.B. die Gleichheit von Strings uberprufenwill, hat man mit dem == so seine Probleme. Die Werte der Referenzen, also dieAdressen, werden miteinander verglichen. Dass diese Adressen fur unterschied-liche Objekte, unterschiedliche Werte haben, ist offensichtlich. Hier bietet dieString-Klasse entsprechende Methoden (z.B. String.equals()) an.

Das Ergebnis von Vergleichsoperatoren ist der Boolean-Wert true oder false.

R Operator Verwendung Beschreibung9 > op1>op2 op1 ist großer als op29 >= op1>=op2 op1 ist großer als oder gleich wie

op29 < op1<op2 op1 ist kleiner als op29 <= op1<=op2 op1 ist kleiner als oder gleich wie

op28 == op1==op2 op1 und op2 sind gleich8 != op1!=op2 op1 und op2 sind ungleich

Tabelle 2.6: Vergleichsoperatoren

2.3.4 Logische Verknupfungsoperatoren

Sehr oft werden nicht nur einzelne Ausdrucke, sondern ganze Ketten von Aus-drucken miteinander verglichen. Um jetzt diese Teilausdrucke von links nachrechts miteinander zu verbinden, werden Verknupfungsoperatoren verwendet.Hier kann es passieren, dass nicht der ganze Ausdruck ausgewertet wird: Wennman z.B. den Ausdruck op1 oder op2 auswerten will, und op1 ist true, dannist von vorne herein das Ergebnis des gesamten Ausdrucks festgelegt.

Page 36: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 31

Diese bedingte Auswertung von Ausdrucken hat enorm viele Vorteile. Auf dereinen Seite verbessert sich das Laufzeitverhalten, da die Auswertung abgekurztwerden kann, sobald das Ergebnis feststeht. Auf der anderen Seite kann manauch sicher sein, dass der linke Ausdruck sicher ausgewertet wurde. Im folgendenBeispiel kann man sich sicher sein, dass str.length() nur dann ausgewertetwird, wenn str != null ist, d.h. es ist mit keiner NullPointerException zurechnen (zu Exceptions siehe bitte Abschnitt 5.1).

i f ( s t r != null && st r . length () > 10){

. . .}

R Operator Verwendung Beschreibung4 && op1&&op2 op1 und op2 beide true (short

eval!)7 & op1&op2 op1 und op2 beide true (full

eval!)3 || op1||op2 entweder op1 oder op2 oder bei-

de true (short eval!)5 | op1|op2 entweder op1 oder op2 oder bei-

de true (full eval!)6 ^ op1^op2 op1 ungleich op214 ! !op op ist false

Tabelle 2.7: Logische Verknupfungsoperatoren

Vorsicht Falle: Man kann es nicht oft genug schreiben: Bitte die Finger wegvon & und |! Kein vernunftiger Programmierer geht von einer vollstandigenAuswertung bei logischen Verknupfungen aus! Diese Operatoren sind optischden Bitoperatoren identisch und sorgen nur fur Verwirrung beim Lesen desProgramms.

2.3.5 Bitoperatoren

Bitoperatoren werden bei Ganzzahlen-Datentypen zum Testen von einzelnenBits verwendet. Dazu sollte man die binare Reprasentation einer Zahl verstehen.

Vorsicht Falle: Wenn man diese Bitoperatoren anschaut, dann fallt der Ope-rator >>> sofort ins Auge. Hier gibt es keinen Operator ’in die andere Rich-tung’ (<<<). Wenn ein <<<-Operator auch keinen Sinn macht (das Vorzeichenbitwurde ja sowieso “links rausfallen” bzw. ware das Vorzeichen vom linkesten Bitder Zahl abhangig...), ware ein solcher Operator aus Grunden der Symmetriedoch wunschenswert.

Page 37: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 32

R Operator Verwendung Beschreibung10 >> op1>>op2 shiftet op1 nach rechts um op2

Bits (Vorzeichenbit wird nichtmitgeshiftet!)

10 >>> op1>>>op2 shiftet op1 nach rechts um op2Bits (Vorzeichenbit wird mitges-hiftet!)

10 << op1<<op2 shiftet op1 nach links um op2Bits (Vorzeichenbit wird nichtmitgeshiftet!)

7 & op1&op2 Bitweises AND von op1 und op25 | op1|op2 Bitweises OR von op1 und op26 ^ op1^op2 Bitweises XOR von op1 und op214 ~ ~op Bitweises Komplement von op

Tabelle 2.8: Bitoperatoren

2.3.6 Shortcut-Zuweisungsoperatoren

Den Zuweisungsoperator (“=”) haben wir nun schon einige Male verwendet. Eswird der gewertete Ausdruck auf der rechten Seite einer Variable zugewiesen.Zusatzlich zum einfachen Zuweisungsoperator gibt es noch 11 weitere Versionen,die implizit Operationen auf den linken Ausdruck ausfuhren. In der Tabelle sindsamtliche verfugbaren Versionen aufgelistet. Auch hier macht es Sinn, wenn manversteht, was genau passiert. Betrachten wir folgendes Beispiel:

an int array [ count++] += 4;an int array [ count++] = an int array [ count++] + 4;

In der ersten Zeile wird count nur einmal ausgewertet, wahrend in der zweitenZeile zweimal count inkrementiert wird! Damit wird in Zeile 2 nicht das Elementbei Index count, sondern bei Index (count+1) verandert (der Wert des Elementsbei Index count wird mit 4 addiert und bei Index (count+1) abgelegt). Wenndiese Operation innerhalb einer Schleife fur alle Elemente ausgefuhrt wird, wirdman sicherlich mit einer ArrayIndexOutOfBoundsException konfrontiert.

2.3.7 Weitere Operatoren

In Tabelle 2.10 sind noch weitere Operatoren aufgelistet. Aus anderen Program-miersprachen ist die Abkurzung zum sehr oft verwendeten if...then...elsebekannt. op2 und op3 mussen den selben Typ haben.

instanceof uberpruft, ob ein Objekt von einer bestimmten Klasse instanti-iert oder abgeleitet wurde. Fur den speziellen null-Wert eines Objekts ergibtinstanceof immer false.

Objekte einer Klasse werden uber den new-Operator instantiiert. Im Kapitel zuKlassen (4) werden wir noch genauer sehen, was hier passiert. In Abschnitt 2.2haben wir den Operator bereits fur Strings und Arrays verwendet. Der cast-Operator wird ebenso erst in Kapitel 4 beschrieben.

Nachdem wir uns jetzt ausfuhrlich mit den Datentypen in Java befasst haben,

Page 38: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 2. DATENTYPEN, VARIABLEN UND OPERATOREN 33

R Operator Verwendung Beschreibung1 += op1 += op2 op1 = op1 + op21 -= op1 -= op2 op1 = op1 - op21 *= op1 *= op2 op1 = op1 * op21 /= op1 /= op2 op1 = op1 / op21 %= op1 %= op2 op1 = op1 % op21 &= op1 &= op2 op1 = op1 & op21 |= op1 |= op2 op1 = op1 | op21 ^= op1 ^= op2 op1 = op1 ^ op21 <<= op1 <<= op2 op1 = op1 << op21 >>= op1 >>= op2 op1 = op1 >> op21 >>>= op1 >>>= op2 op1 = op1 >>> op2

Tabelle 2.9: Shortcut-Zuweisungsoperatoren

R Operator Verwendung Beschreibung2 ?: op1 ? op2 :

op3if (op1) op2 else op3

9 instanceof op1 instanceofop2

true, if op1 is an instanceof op2

13 (type) (type)op1 casts op1 to type13 new new op1 creates a new object or ar-

ray of type op1

Tabelle 2.10: Weitere Operatoren

Variablen solchen Typs verwendet und einige Operationen mit diesen Variablenausgefuhrt haben, befassen wir uns mit der Flusskontrolle in Programmen.

Page 39: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 3

Flusskontrolle

Da im Prinzip die Flusskontrolle in Java der von anderen Programmierspra-chen sehr ahnlich ist, halte ich mich mit den Erklarungen zuruck. Bevor esmit den Schleifen losgeht, noch kurz eine Definition von Begriffen, die wir ver-wenden werden (und die vermutlich intuitiv schon klar sind bzw. aus anderenProgrammiersprachen bekannt sind):

Ausdruck (expression): Eine Folge von Operatoren, Operanden und/oderMethodenaufrufen. Der Datentyp des zuruckgegeben Wertes ist abhangigvon den Werten im Ausdruck. Operatoren werden unterschiedlich be-handelt und jeweils nach ihrem Rang ausgewertet. Haben Operatoren ineinem Ausdruck denselben Rang, so wird der Ausdruck von links nachrechts ausgewertet. Ausdrucke konnen mit Klammern geschachtelt wer-den. Damit kann die Reihenfolge der Auswertung beeinflusst werden.Grundsatzlich ist zu raten: lieber eine Klammerung zu viel, als zu-wenig.Als Beispiel:

d = a + b / c ; // not that easy to read . . .d = a + (b / c ) ; // computes the same value but i s much

// ea s i e r to read . . .

Anweisung (statement): Eine Anweisung entspricht (grob gesprochen) einerProgrammzeile und wird mit einem Strichpunkt (semicolon, ’;’) abge-schlossen. Es gibt drei Arten von Anweisungen:

• Deklarationen und Definitionen: int an_int = 24;

• Zuweisungen: an_int = 27;

• Kontrollflussanweisungen: Regelt, wie der Programmfluss gesteuertwird (das eigentliche Thema dieses Abschnitts), also if...then...elseetc..

Block (block): Ein Block ist eine Zusammenfassung von Anweisungen undkann uberall dort verwendet werden, wo eine einfache Anweisung verwen-det werden kann. Ein Block wird mit geschwungenen Klammern (curlybrace, { }) gebildet. Innerhalb eines Blocks definierte Variablen sind nurim jeweiligen Block gultig.

So, nach diesen kurzen Definitionen, auf zu den Kontrollfluss-Statements!

34

Page 40: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 35

3.1 While...

Bei while gibt es die ersten zwei der drei Schleifenvarianten. Einmal:while ( express ion )

statement

und dann noch das Konstrukt:do

statementwhile ( express ion ) ;

Die Unterschiede sind offensichtlich: Soll vor dem Eintritt in die Schleife einAusdruck expression ausgewertet werden, so ist die erste Variante zu wahlen.Hier kann es passieren, dass die Schleife nicht durchlaufen wird. Soll eine Schleifemindestens einmal durchlaufen werden, bevor ein Ausdruck ausgewertet wird,ist die zweite Variante zu wahlen. Der Ausdruck expression muss einen Wertdes Typs boolean zuruckliefern.

3.2 For...

Bei einer for-Schleife wird ein Schleifenzahler zuerst initialisiert, dann wird dieSchleifenbedingung (condition) gepruft. Wenn diese Bedingung erfullt ist, wirdder Schleifenblock ausgefuhrt. Nach jedem Durchlauf der Schleife wird zuerstdie step-expression ausgewertet. Bei diesem Ausdruck wird ublicherweiseder Schleifenzahler weitergezahlt. Danach wird die Schleifenbedingung erneutgepruft. Bei der Initialisierung und in der step-expression durfen mehrere An-weisungen vorkommen. Diese Anweisungen mussen lediglich durch Beistrichevoneinander getrennt werden.

for ( i n i t i a l i z a t i o n ; condit ion ; step−express ion )statement

Die Schleifeninitialisierung, -bedingung und die Step-Expression sind optional,wobei die Initialisierung auch außerhalb des for-Statements erfolgen kann. Willman den Scope (Gultigkeitsbereich) des Schleifenzahlers so klein als moglichhalten (und das sollte man grundsatzlich wollen...), erfolgt die Deklaration undDefinition im for-Konstrukt.

for ( int counter = 0; counter < 3; counter++){

. . . // counter va l id in th i s block . . .}

Im Gegensatz dazu ein Beispiel der Initialisierung außerhalb des Schleifenkopfs:int counter = 0;for ( ; counter < 3; counter++){

. . . // counter va l id}// counter a l so ava i lab l e outs ide the loop−block . . .System . out . pr int ln (”counter : ” + counter ) ;

Eine Schleife mit leerer condition mutiert zur Endlosschleife.// some i n f i n i t e loopfor ( int counter ; ; counter++){

Page 41: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 36

. . .}// another i n f i n i t e loopfor ( ; ; ){

. . .}

Abschließend zur for-Schleife noch ein kurzes Beispiel mit unterschiedlichenInitialisierungen der Schleifenvariable. Die dritte Schleife fuhrt mehrere Anwei-sungen bei der Initialisierung und Step-Expression aus.

1 public class ForExample2 {3 public static void main( Str ing [ ] args )4 {5 // f i r s t for−loop . . .6 for ( int counter=0; counter < 5; counter++)7 {8 System . out . pr int ln (”1 st : counter : ” + counter ) ;9 }

10 // the fo l lowing w i l l lead to an compiletime error :11 // cannot reso lve symbol12 // System . out . pr int ln (” a f t e r 1 st loop : counter : ” +13 // counter ) ;14

15 // second for−loop . . .16 int counter 2 = 0;17 for ( ; counter 2 < 5; counter 2++)18 {19 System . out . pr int ln (”2nd : counter 2 : ” + counter 2 ) ;20 }21 System . out . pr int ln (” a f t e r 2nd loop : counter 2 : ” + counter 2 ) ;22

23 // third for−loop . . .24 for ( int counter 3 1 =0 , counter 3 2 =10 ; counter 3 1 < 5;25 counter 3 1++, counter 3 2−−)26 {27 System . out . pr int ln (”3rd : counter 3 1 : ” + counter 3 1 +28 ” ; counter 3 2 : ” + counter 3 2 ) ;29 }30 }31 }

Aufruf auf der Konsole:exttt¿java ForExample

1st: counter: 01st: counter: 11st: counter: 21st: counter: 31st: counter: 42nd: counter_2: 02nd: counter_2: 12nd: counter_2: 22nd: counter_2: 32nd: counter_2: 4after 2nd loop: counter_2: 53rd: counter_3_1: 0; counter_3_2: 103rd: counter_3_1: 1; counter_3_2: 93rd: counter_3_1: 2; counter_3_2: 83rd: counter_3_1: 3; counter_3_2: 7

Page 42: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 37

3rd: counter_3_1: 4; counter_3_2: 6

3.3 If...

Bei dem if-Statement wird eine Bedingung (condition) ausgewertet. Ist dieseBedingung wahr (true) wird der Zweig ausgefuhrt, wenn nicht, wird ein eventuellvorhandener else-Zweig ausgefuhrt.

Hinweis: Die Bedingung muss unbedingt einen boolean-Wert zuruckliefern(if (an int != 0)). In C/C++ ist das nicht notwendig (if (an int))!

Als Beispiel:i f ( condit ion )

statement−trueelse // e l s e i s opt ional . . .

statement−false

In Java gibt es wie in C++ das if/else-Statement in Operator-Form. Dieseverkurzte Form der Schreibweise ist bei Zuweisungen und Parameterubergabenvorzugsweise zu verwenden.

op1 ? op2 : op3

Ist op1 true, wird op2 returniert, ansonsten op3.

Im folgenden Beispiel sieht man den Kontrast zwischen Kurzform und ausfuhrli-cher Schreibweise. Es ist offensichtlich, dass die Kurzform schneller und einfachzu lesen ist. Im zweiten Teil des Beispiels sieht man eine geschachtelte Formvon if/else (die sehr schwer zu lesen ist).

1 public class IfExample2 {3 public static void main( Str ing [ ] args )4 {5 int an int = 3;6 int another int = 2;7

8 System . out . pr int ln (” an int : ” + an int ) ;9 System . out . pr int ln (” another int : ” + another int ) ;

10

11 // th i s i s the long form . . .12 i f ( an int > 0)13 {14 another int = 1;15 an int = another int ;16 }17 else18 {19 an int = another int ;20 }21 // . . . o f th i s l i n e ;22 an int = ( an int > 0 ? another int =1 : another int ) ;23

24 // now some nested ( unreadable . . . ) i f / e l s e statements . . .25 int t e s t s co r e = 76;26 char grade ;27 i f ( t e s t s co r e >= 90)28 {29 grade = ’A’ ;30 }31 else

Page 43: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 38

32 i f ( t e s t s co r e >= 80)33 {34 grade = ’B’ ;35 }36 else37 i f ( t e s t s co r e >= 70)38 {39 grade = ’C’ ;40 }41 else42 i f ( t e s t s co r e >= 60)43 {44 grade = ’D’ ;45 }46 else47 {48 grade = ’F ’ ;49 }50 System . out . pr int ln (”Grade = ” + grade ) ;51 }52 }

Aufruf auf der Konsole:exttt¿java IfExample

an_int: 3another_int: 2Grade = C

3.4 Switch...

Im letzten Beispiel hat man gesehen, dass es notwendig ist, mehrere Fallun-terscheidungen elegant zu codieren. If/else-Verschachtelungen sind schwer zulesen und zu durchschauen: Eine Losung fur Ausdrucke, die ganzzahlige Werteliefern, ist das switch-Statement.

switch ( express ion ){

case const1 :statement1

case const2 :statement2

default :defaultstatement

}

Der Ausdruck expression wird ausgewertet und die Verarbeitung beim pas-senden case-Label weitergefuhrt. Die Anweisungen nach diesem Label werdendanach ausgefuhrt. Nicht vergessen sollte man eine break Anweisung, nachdemdie Anweisungen durchgefuhrt wurden, ansonsten wird einfach – wie bei Ein-sprungpunkten ublich – bei der nachsten Anweisung weitergemacht, und daswill man vermutlich nicht...

1 public class SwitchExample2 {3 public static void main( Str ing [ ] args )4 {5 char grade = ’B’ ;6 switch ( grade )7 {

Page 44: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 39

8 case ’A’ :9 System . out . pr int ln (”Very good . . . ” ) ;

10 break ;11 case ’B ’ :12 System . out . pr int ln (”Good . . . ” ) ;13 break ;14 case ’C ’ :15 System . out . pr int ln (”Quite ok . . . ” ) ;16 break ;17 case ’D’ :18 System . out . pr int ln (”Ok . . . ” ) ;19 break ;20 case ’E ’ :21 System . out . pr int ln (”Poor . . . ” ) ;22 break ;23 case ’F ’ :24 System . out . pr int ln (”Failed . . . ” ) ;25 break ;26 default :27 System . out . pr int ln (” Inval id grade . . . ” ) ;28 break ;29 }30 }31 }

Aufruf auf der Konsole:exttt¿java SwitchExample

Good...

Interessant ist das default-Label: Dieses wird verwendet, wenn kein definier-tes Label zum ausgewerteten Ausdruck passt. Eigentlich ware das letzte breaknicht notwendig, weil das switch-Statement sowieso verlassen wird. Es ist aller-dings im Sinne der Erweiterbarkeit und der besseren Lesbarkeit sinnvoll, auchdas letzte break zu schreiben.

Das switch-Statement funktioniert nur mit Expressions, die bei der Auswertungganzzahlige Werte liefern (char hat ja den Wertebereich 0-65535 und funktio-niert aus diesem Grund; siehe Abschnitt 2.1.1).

3.5 break, continue und return

Fur Verzweigungen innerhalb von Schleifen (for, while) und switch-Statementskonnen break und continue verwendet werden.

break: Diese Anweisung beendet die aktuelle Schleife oder die switch-Anwei-sung, wenn kein Label angegeben wurde. Wird ein Label angegeben,so kann auch eine ubergeordnete Schleife, die mit einem Label markiertwurde, beendet werden. Achtung: Es wird die jeweilige Schleife beendet!Der Programmablauf wird nicht beim Label fortgesetzt!!

continue: Springt wieder zum Schleifenkopf einer Schleife, d.h. bei einer for-und while-Schleife wird die Schleifenbedingung erneut gepruft, eine do-Schleife wird ohne weitere Prufung am Beginn der Schleife fortgesetzt. Wiebei break wird ohne Label immer die aktuelle Schleife fortgesetzt. MitLabel kann eine markierte Schleife am jeweiligen Schleifenkopf fortgesetztwerden.

Page 45: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 3. FLUSSKONTROLLE 40

Die beiden Anweisungen konnen mit und ohne Label aufgerufen werden. EinLabel (“Sprungmarke”) wird wie folgt definiert:

the l abe l : statement

Vorsicht Falle: Man sieht, dass break und continue mit Labels einem gotosehr Nahe kommen und unbedingt vermieden werden mussen!! (Aus diesemGrund wird hier auf ein ausfuhrliches Beispiel mit Labels verzichtet!).

1 public class BreakContinueExample2 {3 public static void main( Str ing [ ] args )4 {5 for ( int count =0 ; ; count++)6 {7 i f ( count > 5)8 {9 System . out . pr int ln (”count > 5 . . . ” ) ;

10 break ;11 }12 i f ( count < 100)13 {14 System . out . pr int ln (”continue . . . ” ) ;15 continue ;16 }17 System . out . pr int ln (”never reached , because of continue . . . ” ) ;18 }19 System . out . pr int ln (”Finished for−loop ; ( count out of scope ! ) ” ) ;20 }21 }

Aufruf auf der Konsole:exttt¿java BreakContinueExample

continue...continue...continue...continue...continue...continue...count > 5...Finished for-loop; (count out of scope!)

Mit return wird eine Methode beendet. Bei der Signatur einer Methode wirdfestgelegt, welchen Typ der Return-Wert hat. Wenn eine Methode keinenreturn-Wert liefert, wird sie als void deklariert.

return ;

Wird ein Return-Wert von der Methode geliefert, so muss dieser mit dem in derSignatur vereinbarten Typ ubereinstimmen.

return some value ;

Page 46: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 4

Klassen in Java

In diesem Kapitel werden Eigenschaften und Eigenheiten von Klassen in Javabehandelt. Wir beginnen mit einem kurzen Uberblick und betrachten danachJava spezifische Details.

4.1 Einige Begriffe

Die Begriffe, die nun folgen, sind vermutlich großtenteils schon bekannt. Trotz-dem sollen sie hier noch einmal genannt und erlautert werden. Als Beispielebei den Erklarungen dienen ein Fahrrad und weitere Gegenstande des taglichenLebens.

Klasse (class): Zusammenfassung aller naturgegebenen Moglichkeiten (Me-thoden) und Eigenschaften (Member-Variablen) gleichartiger Objekte. BeiFahrradern kann man z.B. ein Rad wechseln (Methode). Jedes Fahrradhat eine Lenkstange, einen Sattel, zwei Rader etc. (Member-Variable).Ein Einrad ware nach dieser Betrachtungsweise kein Fahrrad! Eigen-schaften einer Klasse konnen nicht einfach “weg-definiert” werden!! EinFahrrad ist ein Fahrzeug.

• Die Beziehung “hat-ein” (HAS-A) wird uber eine Member-Variableausgedruckt.

• Die Beziehung “ist-ein” (IS-A) wird uber Ableitungen realisiert.

Der Zugriff auf einzelne Methoden bzw. einzelne Member-Variablen kann(und soll!) beschrankt werden (siehe Abschnitt 4.5).

Objekt: Eine bestimmte Instanz einer Klasse. Z.B. ist das rote Fahrrad desNachbarn eine Instanz der Klasse Fahrrad. Ein Objekt wird explizit uberden new-Operator erzeugt.

Hinweis: In Java kann mit dem Schlusselwort this auf das “eigene” Ob-jekt zugegriffen werden (z.B. wenn man Methoden aufrufen oder Member-Variablen verandern will).

41

Page 47: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 42

Member-Variable: Eigenschaft einer Klasse. Selbstverstandlich kann eineKlasse mehrere Eigenschaften haben. Es gibt auch unterschiedliche Artenvon Member-Variablen. Wie schon im obigen Beispiel angeschnitten, wareeine Lenkstange eine Eigenschaft eines Fahrrades und musste dementspre-chend als Member-Variable implementiert werden.

Ableitung: Eine Klasse kann von einer anderen Klasse abgeleitet werden, wenndie IS-A-Beziehung zwischen den beiden Klassen gilt.

Hinweis: In Java gibt es (leider) nur einfache Ableitungen. MehrfacheAbleitungen mussen uber Interfaces umgesetzt werden.

Das Fahrrad ist ein Fahrzeug, leitet sich also von der Klasse Fahrzeugab und erbt alle Eigenschaften und Methoden der Fahrzeug-Klasse. DasSchlusselwort fur die Ableitung ist extends.

Interface: Ein Interface beschreibt eine Sammlung von Konstanten- und Methoden-Deklarationen von voneinander unabhangigen Klassen. Uberlegen wir unsein Programm zur Inventur von Artikeln. Diesem Programm sollte esegal sein, ob ein Fahrrad oder ein Fernseher inventarisiert werden soll.Beide (Fahrrad und Fernseher) haben eine Inventar-Nummer und stehenirgendwo herum. Fur dieses Programm sind nun Inventar-Nummer undAufstellungsort (und naturlich viele weitere Eigenschaften, die mit derInventarisierung zu tun haben wie Ankaufdatum, wer hat das Ding ange-kauft, etc.) interessant. Fahrrad muss daher inventarisierbar sein, damites vom Programm inventarisiert werden kann. Soll ein Fernseher inventa-risiert werden, muss auch dieser inventarisierbar sein. Schlusselwort furdie Definition von Interfaces ist interface.

Methode: Eine Funktion, die einer Klasse zugewiesen ist, nennt man Methode.Es gibt statische Methoden sowie Instanz-Methoden. Statische konnen un-abhangig von einer Instanz verwendet werden. Diese haben wir schon furUmwandlungen von Zeichenketten in andere Datentypen kennengelernt(z.B. Integer.parseInt(String);, siehe 2.1.1). Instance methods wer-den uber ein existierendes Objekt aufgerufen und verwenden das Objekt.Die Methode “Reifenwechseln” verwendet ein bestimmtes Fahrrad.

Kapselung (encapsulation): Eine Datenstruktur wird in einer Klasse gekap-selt und dadurch vor dem Benutzer “versteckt”. Der Benutzer der Klassekann nur uber bestimmte zugangliche Methoden auf einzelne Elemente derDatenstruktur zugreifen. Vorteil: Solange sich an den Zugriffsmethodennichts andert, konnen Anderungen an den internen Details der Klasse vor-genommen werden, ohne dass der Benutzer etwas davon merkt. Fur dieKapselung werden die Schlusselworter public, private und protectedverwendet.

Overloading: Von “overloading” spricht man, wenn mehrere Methoden einerKlasse denselben Namen haben, aber mit unterschiedlichen Parameternaufgerufen werden.

Overriding: Eine Methode einer abgeleiteten Klasse “overrided” eine Methodemit den selben Namen und Parametern aus der Super-Klasse. Der Name

Page 48: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 43

der Methode und die Typen der Parameter werden Signatur einer Methodegenannt.

Vorsicht Falle: “Override” (“uberreiten” bzw. “Vorrang haben vor”) hat ab-solut nichts mit “overwrite” zu tun (auch wenn die Aussprache dieser beidenBegriffe sich sehr ahnlich ist!). Eine Methode wird in Java nicht uberschrie-ben – sie ist ja noch immer da und kann uber das Schlusselwort super (z.B.super.methode name();) auch aufgerufen werden. JavaScript-Programmiererhaben den Begriff “overwrite” vermutlich schon gelesen, sollten ihn aber soschnell wie moglich wieder aus ihrem (Programmier-)Wortschatz streichen!

Die oben genannten Begriffe ziehen sich durch die folgenden Abschnitte. InKurze werden wir die Konzepte in Java an Beispielen genauer betrachten.

4.2 Definition einer Klasse in Java

Wie wir schon im ersten Beispiel (siehe Abschnitt 1.1) gesehen haben, wirdjede Klasse in einer Datei abgespeichert. Der Name der Datei entspricht demKlassennamen mit der Erweiterung .java.

In Abschnitt 4.1 haben wir geschrieben:

[Eine Klasse ist die] “... Zusammenfassung aller naturgegebenenMoglichkeiten (Methoden) und Eigenschaften (Member-Variablen)gleichartiger Objekte ... Eigenschaften einer Klasse konnen nichteinfach “weg-definiert” werden!”.

In Java kann man auch Klassen innerhalb von Klassen definieren. Anwendungs-beispiele fur diese Form werden spater noch gezeigt.

Hinweis: Genauer gesagt darf genau eine public-Klassendefinition in einerDatei stehen. Eine Klassendefinition definiert einen neuen Referenz-Datentyp.

Im Gegensatz zu C++ gibt es in Java keine Header-Files, in denen eine Klassedeklariert wird. Dadurch hat man alle notwendigen Informationen einer Klassein einer Datei zusammengefasst.

Nun aber zur Definition einer sog. “top-level class” (d.h. einer Klasse, die nichtinnerhalb einer anderen Klasse definiert wurde) mit einigen Erlauterungen:

[ public ] [ abstract | f inal ] class [ TheClassName ][ extends TheBaseClassName ][ implements SomeInterfaceA [ , SomeInterfaceB ] ]

{// here the de f i n i t i on of member var iab le s and methods . . .

}

Sichtbarkeit der Klasse (“access modifier”): Hier gibt es zwei Moglich-keiten:

public: Die Klasse ist fur alle anderen Klassen sichtbar.

Page 49: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 44

kein Modifier: Die Klasse ist nur fur andere Klassen im selben Packa-ge sichtbar. Es ist moglich (aber nicht sinnvoll!), mehrere solcherKlassen in einem File zu speichern.Generell sollte man jede Klasse, egal ob public oder nicht, in ein ei-genes Sourcecode-File speichern (auch wenn es hier bei einigen Demo-Klassen nicht so gemacht wurde!).

Fur geschachtelte Klassen (“nested-” oder “inner-classes”, d.h. Klassen,die innerhalb von Klassen definiert werden, siehe Abschnitt 4.8) gibt esnoch weitere Schlusselworter, die die Sichtbarkeit beeinflussen, namlichprivate und protected.

Modifier:

abstract: Eine Klasse mit diesem Modifier kann nicht instantiiert wer-den, weil die vollstandige Definition auf dieser Abstraktionsebene desKlassendesigns noch nicht bekannt ist. Einer Ableitung steht abernichts im Weg. Wenn alle Methoden in einer abstrakten Klasse de-finiert sind, kann ein Entwickler trotzdem eine Ableitung fordern.Sind in der Klasse Methoden als abstract deklariert, ist der Mo-difier explizit gefordert (ansonsten kommt ein Fehler wahrend desCompilierens).

final: Von einer final Klasse kann nicht abgeleitet werden (z.B. java.lang.String, ...). D.h. die Methoden, die in dieser Klasse defi-niert wurden, konnen unter keinen Umstanden von einem Entwicklerverandert werden. Bei einigen Systemklassen (wie schon der ange-sprochenen String-Klasse) macht dieser Ansatz durchaus Sinn. ImKlassendesign von Libraries muss man generell sehr vorsichtig mitModifier umgehen. Bei final sind die Auswirkungen besonders deut-lich zu sehen.

TheClassName: Der Gultigkeitsbereich (scope) des Klassennamen beschranktsich auf das Package (siehe Abschnitt 4.11), in dem die Klasse definiertwurde. Es ist daher moglich, gleiche Klassennamen in unterschiedlichenPackages zu verwenden, d.h. man konnte ohne weiteres eine Klasse Stringim Package mypackage definieren, ohne mit java.lang.String in Kon-kurrenz zu stehen. Will man beide String-Klassen gleichzeitig verwenden,muss bei der Instantiierung mit dem full qualified name gearbeitet werden.Klassen mussen nicht unbedingt einen Namen haben (sog. “anonyme”Klasse).

Weitere Schlusselworter bei der Klassendefinition:

extends: Diese Klasse leitet sich von der Klasse mit dem Namen The-BaseClassName ab. In Java ist nur eine einfache Ableitung moglich!Jede Klasse in Java ist von der Klasse java.lang.Object abge-leitet und erbt daher alle Methoden, die dort definiert sind (u.a.toString(), clone(), finalize()...). Mehr dazu ist in Abschnitt 4.7bzw. 4.9 zu finden.

implements: Diese Klasse implementiert ein oder mehrere Interfaces (sie-he 4.10).

Page 50: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 45

Hinweis: Die Modifier, die bei der Definition der Klasse stehen, mussen selbst-verstandlich sinnvoll sein. Widerspruchliche Angaben werden vom Compilererkannt und dementsprechend nicht in Bytecode ubersetzt. Wenn man z.B.eine Klasse sowohl abstract als auch final definiert, wird beim Compilierenein Fehler gemeldet (“illegal combination of modifiers: abstract andfinal”).

Ahnlich ist das Verhalten des Compilers, wenn falsche Modifiers verwendetwerden (z.B. private in einer “top-level” Klasse). Hier meldet der Compiler“modifier private not allowed here”.

Fur Member einer Klasse (d.h. Variablen, Methoden und auch selbst wiederKlassen...) gibt es die Moglichkeit der Zugriffskontrolle mit public, protectedund private, sowie weitere Schlusselworter, die in Kurze erlautert werden. Zu-vor betrachten wir aber noch die Art und Weise, wie Objekte einer bestimmtenKlasse erzeugt werden.

4.3 Der Konstruktor einer Klasse

Objekte werden uber das Schlusselwort new erzeugt. Eine Ausnahme gibt eshier bei der String-Klasse (siehe 2.1.2). Durch den Aufruf von obj = newSomeClassName(); wird ein Objekt vom Typ SomeClassName erzeugt. Wiein C++ gibt es auch in Java spezielle Methoden, die fur die Initialisierung vonObjekten zustandig sind, sog. Konstruktoren (constructors) einer Klasse. DieSignatur eines Konstruktors:

[ public | private |protected ] TheClassName ( [ some parameters ] )[ throws SomeException ]

{// here the implementation of the constructor

}

Der Zugriff auf Konstruktoren wird uber sog. Zugriffsmodifier (public, privateund protected) gesteuert (siehe Abschnitt 4.5). Durch diese kann die Instan-tiierung von Objekten dieser Klasse beeinflusst werden. Mit dem Schlusselwortprivate kann z.B. verhindert werden, dass “irgendeine” anderen Klasse einObjekt dieses Typs erzeugt1.

Hinweis: Ein Konstruktor ist – wie in C++ – kein Member einer Klasse,d.h. er wird z.B. nicht von Parent-Klassen geerbt. Anders als bei normalenMethoden (siehe Abschnitt 4.7) darf ein Konstruktor auch nicht mit den folgen-den Schlusselworten versehen werden: abstract, final, static, synchronizedoder native.

Da der Konstruktor nicht vererbt wird, machen die Schlusselworter abstractund final keinen Sinn. Ebenso wird ein Konstruktor nur bei der Erzeugungeiner Instanz aufgerufen (static ist daher ebenso sinnlos...). Der Zugriff auf

1In diesem Zusammenhang muss man unbedingt das Singleton-Design Pattern nennen([Gamma et al., 1998]). Bei diesem Ansatz wird garantiert, dass nur eine Instanz einer Klasseerzeugt wird.

Page 51: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 46

das Objekt, das gerade instantiiert wird, wird erst nach der Erzeugung gewahrt(dieses Verhalten erubrigt das Schlusselwort synchronized). Schlussendlichwurde noch das Schlusselwort native fur Konstruktoren ausgeschlossen, dadadurch die Implementation der JVM einfacher wurde.

Der Name des Konstruktors entspricht dem Klassennamen. Durch overloa-ding konnen mehrere Konstruktoren in einer Klasse existieren. Ein speziellerKonstruktor – der ohne Parameter – wird default constructor genannt. Kon-struktoren werden beim Instantiieren von Objekten aufgerufen, beim Aufruf derMethoden newInstance(...), beim String-Operator + bzw. in anderen Kon-struktoren. Er kann nicht als Methode aufgerufen werden (zur Erinnerung: derKonstruktor ist ja kein Member einer Klasse!).

Uber die throws-Klausel mussen noch Exceptions (siehe Kapitel 5), die wahrenddes Aufrufs auftreten konnen, angegeben werden2. Im Unterschied zu C++mussen Exceptions, die wahrend der Ausfuhrung des Konstruktors (bzw. aucheiner Methode) auftreten konnen, bei der Signatur angefuhrt werden.

Will man bei der Erzeugung eines Objekts keine speziellen Initialisierungenvornehmen, so muss man nicht unbedingt einen Konstruktor schreiben. Wennkein Default-Konstruktor bei einer Klasse definiert ist, wird automatisch einervon der JVM zur Verfugung gestellt. Ein Konstruktor returniert im Unterschiedzu Methoden keinen Wert (nicht einmal void!).

4.3.1 Konstruktoren in Einfachen Klassen

Beim folgenden Beispiel wurde fur die Klasse BaseClass ein Default-Konstruktorimplementiert, der beim Erzeugen von Objekten aufgerufen wird.

1 public class BaseClass2 {3 protected int some int ;4

5 public BaseClass ()6 {7 System . out . pr int ln (”Default constructor of BaseClass” ) ;8 }9

10 public BaseClass ( int some int )11 {12 System . out . pr int ln (”Some other Constructor of BaseClass : some int : ” + some int ) ;13 some int = some int ;14 }15

16 protected void f i n a l i z e ( ) throws Throwable17 {18 System . out . pr int ln (”F ina l i z e r of BaseClass” ) ;19 }20

21 public int getSomeInt ()22 {23 System . out . pr int ln (”getSomeInt ( ) of BaseClass” ) ;24 return some int ;25 }26

27 public void setSomeInt ( int some int )28 {29 System . out . pr int ln (”setSomeInt ( ) of BaseClass” ) ;30 some int = some int ;

2Im Abschnitt uber Fehlerbehandlung (Kapitel 5) werden wir noch lesen, dass in dieserKlausel nicht alle Typen von Exceptions angegeben werden mussen...

Page 52: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 47

31 }32

33 public String toStr ing ()34 {35 return ”BaseClass : some int : ” + some int ;36 }37

38 public static void main( Str ing [ ] args )39 {40 System . out . pr int ln (”Create an object of type BaseClass . . . ” ) ;41 BaseClass bc1 = new BaseClass ( ) ;42 System . out . pr int ln (”Create another object of type BaseClass . . . ” ) ;43 BaseClass bc2 = new BaseClass ( 2 ) ;44 }45 }

Aufruf auf der Konsole:exttt¿java BaseClass

Create an object of type BaseClass...Default constructor of BaseClassCreate another object of type BaseClass...Some other Constructor of BaseClass: some_int: 2

Interessant sind die Zeilen 10-14 im obigen Beispiel: Durch overloading wirdein zweiter Konstruktor zur Verfugung gestellt. Innerhalb eines Konstruktorskann in der ersten Zeile der Konstruktor-Definition ein anderer Konstruktor derselben Klasse via this(...) aufgerufen werden. Hatten wir wesentlich mehrObject-Members zu initialisieren, konnten wir im ersten (default) Konstruktor(Zeilen 5-8) den zweiten Konstruktor (via this(init value); aufrufen (ver-gleiche dazu den Abschnitt uber Methoden in 4.7).

Hinweis: In Zeile 13 wird einer Member-Variable (some int ) der Wert desubergebenen Parameters zugewiesen. Diese Zeile demonstriert einen (der vie-len) Vorteil des verwendeten Codingstandards: Durch das underline-Zeichenam Ende des Variablennamen erkennt man sofort, dass die Zuweisung auf eineObjekt- oder Class-Variable erfolgt. Man muss sich keine Gedanken uber denNamen des Parameters (some int) machen, da diesem einfach der underscore(“ ”) “weggenommen” wird.

Wurde die Signatur des Konstruktors als Parameter eine Variable mit demselben Namen wie die Klassenvariable (some int ) verwenden (public Base-Class(int some int )), so musste man bei der Zuweisung, die Klassenvariableexpliziter uber this ansprechen. Die Zuweisung musste daher:this.some int = some int ;lauten (this ist die Referenz auf das eigene Objekt). Diese kurze Ausfuhrungsoll die Notwendigkeit eines Codingstandards unterstreichen!

In Zeile 16 wird noch eine Methode finalize() definiert, die im nachsten Ab-schnitt noch genauer beleuchtet wird.

4.3.2 Konstruktoren und Abgeleitete Klassen

Fur einfache Klassen ist das Verhalten also ziemlich einfach und verstandlich:Immer wenn ein Objekt von einer Klasse erzeugt wird, wird auch der Konstruk-

Page 53: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 48

tor der Klasse aufgerufen. Wie schaut das aber bei komplizierteren Klassen aus,die von anderen Klassen (sog. Super-Klassen) abgeleitet wurden?

Betrachten wir ein Beispiel, bei dem eine Klasse UglySubClass von BaseClassabgeleitet wird:

1 public class UglySubClass extends BaseClass2 {3 public UglySubClass ()4 {5 System . out . pr int ln (”Default constructor of UglySubClass” ) ;6 }7

8 public UglySubClass ( int some int )9 {

10 System . out . pr int ln (”Some other Constructor of UglySubClass” ) ;11 setSomeInt ( some int ) ;12 }13

14 protected void f i n a l i z e ( ) throws Throwable15 {16 System . out . pr int ln (”F ina l i z e r of UglySubClass” ) ;17 }18

19 public int getSomeInt ()20 {21 System . out . pr int ln (”getSomeInt ( ) of UglySubClass” ) ;22 return 10 ;23 }24

25 public static void main( Str ing [ ] args )26 {27 System . out . pr int ln (”Create an object of type UglySubClass . . . ” ) ;28 UglySubClass sc1 = new UglySubClass ( ) ;29 System . out . pr int ln (”Create another object of type UglySubClass . . . ” ) ;30 UglySubClass sc2 = new UglySubClass (20 ) ;31 }32 }

Aufruf auf der Konsole:exttt¿java UglySubClass

Create an object of type UglySubClass...Default constructor of BaseClassDefault constructor of UglySubClassCreate another object of type UglySubClass...Default constructor of BaseClassSome other Constructor of UglySubClasssetSomeInt() of BaseClass

Bei abgeleiteten Klassen wird automatisch im Konstruktor der abgeleitetenKlasse der Default-Konstruktor der Super-Klasse aufgerufen. Innerhalb einesDefault-Konstruktors mag dieses Verhalten durchaus erwunscht sein. Im Falledes zweiten Konstruktors (der mit dem Parameter some int) ist dieses Verhal-ten vermutlich nicht gewunscht!

Schauen wir uns die Zeilen 8-12 von UglySubClass.java genauer an: Der Kon-struktor hat die selbe Signatur wie der Konstruktor von BaseClass (Parameterist ein Integer). In Zeile 11 erfolgt eine Zuweisung des Parameters auf dieMember-Variable. Dieselbe Zuweisung passiert auch im zweiten Konstruktorvon BaseClass. Wieso also diese Zuweisung extra noch einmal schreiben, wenn

Page 54: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 49

sie schon in der Basis-Klasse definiert wurde? Es ware doch toll, wenn maneinfach den Konstruktor der Basis-Klasse aufrufen konnte! Bei dieser einfachenKlasse ist dieses Verhalten vielleicht nicht so gravierend, aber wenn man kom-plexere Klassen anschaut, wo wesentlich mehr Member-Variablen initialisiertwerden mussen, ist diese Mehrarbeit unbedingt zu vermeiden.

In Java kann man genau an einer Stelle im Konstruktor (und nur dort) einenanderen aufrufen: In der ersten Zeile der Definition des Konstruktors. DieVerwendung von super ist in diesem Fall gleich wie die Verwendung von thisin Abschnitt 4.3.1.

Eine bessere Implementation (siehe NiceSubClass.java) der Zeile 8-12 musstealso lauten:

public NiceSubClass ( int some int ){

super( some int ) ;System . out . pr int ln (”Some other Constructor of NiceSubClass” ) ;

}

Dadurch ergibt sich der folgende Output:

Aufruf auf der Konsole:exttt¿java NiceSubClass

Create an object of type NiceSubClass...Default constructor of BaseClassDefault constructor of NiceSubClassCreate another object of type NiceSubClass...Some other Constructor of BaseClass: some_int: 20Some other Constructor of NiceSubClass

Zusammenfassend kann man sagen, dass die Konstruktoren aller abgeleitetenKlassen der Klassenhierarchie entsprechend von der Basis-Klasse beginnend auf-gerufen werden. Dieses Verhalten deckt sich mit dem aus C++ bekannten Me-chanismus.

Vorsicht Falle: In Java sind alle Methoden virtuell, d.h. eine Methode wirdzur Laufzeit in der Ableitungshierarchie gesucht und verwendet. Ausgenommensind davon Methoden, die mit final markiert sind. Mit dieser Tatsache mussman leben.

Als Folge ergibt sich, dass es absolut keinen Sinn macht, in einem Konstruk-tor Methoden aufzurufen, da man sich nicht sicher sein kann, welche Methodewirklich aufgerufen wird! Es besteht die Moglichkeit, dass auf noch nicht rich-tig initialisierte Member-Variablen zugegriffen wird! Zur Demonstration dienthier folgende Implementation einer ReallyUglySubClass. Hier ist der Fehleroffensichtlich, weil in der Zeile 11 bereits auf einen Member zugegriffen wird,der erst eine Zeile spater initialisiert wird.

1 public class ReallyUglySubClass extends BaseClass2 {3 public ReallyUglySubClass ()4 {5 System . out . pr int ln (”Default constructor of ReallyUglySubClass” ) ;6 }7

8 public ReallyUglySubClass ( int some int )

Page 55: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 50

9 {10 System . out . pr int ln (”Some other Constructor of ReallyUglySubClass” ) ;11 System . out . pr int ln (” some int i s : ” + getSomeInt ( ) ) ;12 setSomeInt ( some int ) ;13 }14

15 protected void f i n a l i z e ( ) throws Throwable16 {17 System . out . pr int ln (”F ina l i z e r of ReallyUglySubClass” ) ;18 }19

20 public String toStr ing ()21 {22 return ”ReallyUglySubClass : some int : ” + getSomeInt ( ) ;23 }24

25 public static void main( Str ing [ ] args )26 {27 System . out . pr int ln (”Create an object of type ReallyUglySubClass . . . ” ) ;28 ReallyUglySubClass sc1 = new ReallyUglySubClass ( ) ;29 System . out . pr int ln (”Create another object of type ReallyUglySubClass . . . ” ) ;30 ReallyUglySubClass sc2 = new ReallyUglySubClass (20 ) ;31 System . out . pr int ln (”sc2 i s : ” + sc2 . toStr ing ( ) ) ;32 }33 }

Aufruf auf der Konsole:exttt¿java ReallyUglySubClass

Create an object of type ReallyUglySubClass...Default constructor of BaseClassDefault constructor of ReallyUglySubClassCreate another object of type ReallyUglySubClass...Default constructor of BaseClassSome other Constructor of ReallyUglySubClassgetSomeInt() of BaseClasssome_int_ is: 0setSomeInt() of BaseClassgetSomeInt() of BaseClasssc2 is: ReallyUglySubClass: some_int_: 20

4.4 ’Destruktor’ einer Klasse

In C++ wird uber delete ein Objekt explizit geloscht und der Destruktorder Klasse wird aufgerufen. Handelt es sich bei der Klasse um eine abgeleite-te Klasse, werden außerdem automatisch die Destruktoren der Parent-Klassenaufgerufen.

In Java ist die Situation anders. Hier ubernimmt der sog. garbage collector(GC) die Speicherverwaltung. Ist ein erzeugtes Objekt nicht mehr referenzierbar(z.B. weil der Gultigkeitsbereich der Variable verlassen wurde), markiert derGC dieses Objekt. Der ursprunglich reservierte Speicher wird aber noch nichtfreigegeben. Erst wenn der Speicher wirklich gebraucht wird, entscheidet derGC, welches Objekt entfernt wird. Bevor der Speicher des Objekts freigegebenwird, wird noch der Finalizer (d.h. die Methode finalize, ohne Parameter)

Page 56: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 51

aufgerufen. Wann und ob nun der GC von Java das nicht mehr gebrauchteObjekt tatsachlich loscht, steht in den Sternen.

Hinweis: Es gibt zwar einen ’Destruktor’ einer Klasse, es wird aber nichtgarantiert, dass er uberhaupt aufgerufen wird!

Betrachtet man die Ausgaben in den letzten Beispielen, so sieht man, dassniemals die Methode finalize() aufgerufen wurde. Im folgenden Beispiel ver-wenden wir die bereits bekannte Klasse (NiceSubClass):

1 public class DestructorTest2 {3 public static void main( Str ing [ ] argv )4 {5 NiceSubClass nsc = new NiceSubClass ( ) ;6 nsc = null ;7 System . out . pr int ln (” jus t before runFinal izat ion ( ) . . . ” ) ;8 System . runFinal izat ion ( ) ;9 System . out . pr int ln (” a f t e r runFinal izat ion ( ) . . . ” ) ;

10 System . out . pr int ln (” jus t before gc ( ) . . . ” ) ;11 System . gc ( ) ;12 System . out . pr int ln (” a f t e r gc ( ) . . . ” ) ;13 }14 }

Aufruf auf der Konsole:exttt¿java DestructorTest

Default constructor of BaseClassDefault constructor of NiceSubClassjust before runFinalization()...after runFinalization()...just before gc()...Finalizer of NiceSubClassafter gc()...

In Zeile 6 wird explizit dem Objekt nsc null zugewiesen und damit unbrauchbargemacht. Der GC weiss ab diesem Moment, dass auf den ursprunglichen Wertvon nsc nicht mehr zugegriffen werden kann.

Es werden im Anschluss zwei Methoden aufgerufen, die der JVM anweisen,“wenn notwendig” den garbage collector aufzurufen. Aus der Dokumentationgeht hervor, dass hier nicht unbedingt der Finalizer aufgerufen werden muss:

public static void runFinalization(): Runs the finalizationmethods of any objects pending finalization. Calling this methodsuggests that the Java Virtual Machine expend effort toward run-ning the finalize methods of objects that have been found to bediscarded but whose finalize methods have not yet been run. Whencontrol returns from the method call, the Java Virtual Machine hasmade a best effort to complete all outstanding finalizations.

Und dann noch:

Page 57: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 52

public static void gc(): Runs the garbage collector. Callingthe gc method suggests that the Java Virtual Machine expend ef-fort toward recycling unused objects in order to make the memorythey currently occupy available for quick reuse. When control re-turns from the method call, the Java Virtual Machine has madea best effort to reclaim space from all discarded objects. The callSystem.gc() is effectively equivalent to the call: Runtime.getRun-time().gc().

Im Unterschied zu C++ wird in Java nicht automatisch die finalize-Methodeder Parent-Klasse aufgerufen. Man musste daher selbststandig den Parent-Finalizer (via super.finalize();) als erste Zeile des Finalizers aufrufen. Eineakzeptable Implementation eines Finalizers ware:

protected void f i n a l i z e ( ) throws Throwable{

super . f i n a l i z e ( ) ;}

Exceptions, die in einer finalize-Methode auftreten, mussen bei der Methoden-Definition angegeben werden. Diese Exceptions werden aber nicht ausgewertet(wie und wo auch?). Die finalize-Methode wird beim Auftreten einer Excep-tion die nicht behandelt wird, einfach verlassen.

Mit diesem Wissen bewaffnet, kann man sehr schnell uberprufen, ob man ei-ne existierende Java-Library verwenden soll: Wird finalize implementiert undwerden dort Ressourcen freigegeben, ist es sicher nicht sehr gescheit, diese Li-brary zu verwenden. In diesem Fall durfte Java nicht die “Muttersprache” desEntwicklers sein...

Hinweis: Da man nie sicher sein kann, ob und wann der Destruktor fur Objektetatsachlich aufgerufen wird, macht es absolut keinen Sinn, Funktionalitat inden Destruktor (=finalize()) zu stecken!

Hinweis: In C++ werden Destruktoren dafur verwendet, Ressourcen (z.B.Files, Netzwerkverbindungen etc.) wieder freizugeben. Das ist auch sinnvoll,da man sich in C++ ja sicher sein kann, dass der Destruktor der Klasse auchaufgerufen wird. In Java muss man zur Ressourcenfreigabe separate Methodenschreiben (sinnvolle Namen wahren hier z.B. close() oder dispose()), die auchvom Entwickler explizit verwendet werden mussen.

Seit Java 1.3 gibt es eine Methode addShutdownHook(someThread) die einen in-itialisierten, aber noch nicht gestarteten Thread ubergibt. Wird die JVM been-det (via System.exit(int), oder System.halt()), so wird dieser someThreadgestartet. Allerdings gibt es auch hier die Moglichkeit, dass dieser Thread nichtausgefuhrt wird...

4.5 Member-Modifier

Zu den Members einer Klasse gehoren Variablen, Methoden und selbst wiederKlassen. Alle Member verwenden sog. Zugriffsmodifier (access modifier), die

Page 58: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 53

zur Kapselung von Members verwendet werden. Zunachst betrachten wir die-se Access-Modifier, im Anschluss den static-Modifier. Da bei Variablen undMethoden unterschiedliche Modifier zur Anwendung kommen, gibt es dement-sprechend eigene Abschnitte dazu.

Seit Java 1.4 (genauer: Java Platform 2, Version 1.4 ) gibt es noch den Modifierstrictfp, der hier nicht behandelt wird.

4.5.1 Access-Modifier

Der Zugriff auf einzelne Elemente einer Klasse (Methoden, Member-Variablen,Konstruktoren) wird uber sog. Zugriffsmodifier (access modifiers) gesteuert.Generell sollte der Zugriff auf einzelne Elemente so eingeschrankt wie moglichsein. Ein Einblick in Packages wird spater in Abschnitt 4.11 gegeben. Fur dieBetrachtungen in diesem Abschnitt reicht es, wenn wir wissen, dass Klassen insog. Packages zusammengefasst werden konnen. Die folgende Klasse verwendenwir fur die Demonstration der Zugriffsmodifier:

1 package testpack ;2

3 public class AccessModifierMembersClass4 {5 int a package int = 1;6 private int a p r i va t e i n t = 2;7 protected int a protec ted int = 3;8 public int a pub l i c i n t = 4;9

10 public int getAPrivateInt ()11 {12 return a p r i va t e i n t ;13 }14 }

Folgende Modifier sind in Java definiert:

public: Der Zugriff fur samtliche anderen Klassen ist gestattet. Hier sollte manaufpassen, da wirklich jede Klasse mit einem solchen Member arbeitenkann.

private: Zugriff nur in der Klasse, wo das Element definiert wurde. Will maneine falsche Manipulation von außerhalb der Klasse verhindern, macht esSinn, die Variable private zu markieren. Soll wirklich von Außen auf z.B.eine Variable zugegriffen werden, sollen dafur mit protected markierteZugriffsmethoden (“getter”) verwendet werden. Der Codingstandard siehtfur den Methodennamen einer Zugriffsmethode getNameOfVariable();vor. Auf den Wert von boolean-Variablen sollten via isNameOfVariable();zugegriffen werden.

default: Wird kein Modifier angegeben, so ist der Zugriff auf Klassen be-schrankt, die im selben Package sind. Abgeleitete Klassen außerhalb desPackages haben keinen Zugriff auf diese Elemente!

protected: Es durfen zusatzlich zur eigenen Klasse, auch abgeleitete Klassenund Klassen im selben Package auf das Element zugreifen.

Page 59: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 54

Nun folgen die Beispiele. Die entsprechenden Fehler, die bei einem illegalenZugriff passieren, sind in den Kommentaren notiert:

einfache Klasse:

1 import testpack ;2

3 class AccessModifierTest14 {5 public static void main( Str ing [ ] args )6 {7 AccessModifierMembersClass obj = new AccessModifierMembersClass ( ) ;8

9 // i l l e g a l access : a package int i s not publ ic in10 // testpack . AccessModifierMembersClass ; cannot be accessed11 // from outside package12 // System . out . pr int ln ( obj . a package int ) ;13

14 // i l l e g a l access : a p r i va t e i n t has pr ivate access in15 // testpack . AccessModifierMembersClass16 // System . out . pr int ln ( obj . a p r i va t e i n t ) ;17

18 // l e ga l access19 System . out . pr int ln ( obj . getAPrivateInt ( ) ) ;20

21 // i l l e g a l access : a protec ted int has protected access in22 // testpack . AccessModifierMembersClass23 // System . out . pr int ln ( obj . a protec ted int ) ;24

25 // l e ga l access , because var iab le i s publ ic !26 System . out . pr int ln ( obj . a pub l i c i n t ) ;27 }28 }

einfache Klasse, im selben Package:

1 package testpack ;2

3 class AccessModifierTest24 {5 public static void main( Str ing [ ] args )6 {7 AccessModifierMembersClass obj = new AccessModifierMembersClass ( ) ;8

9 // l e ga l access10 System . out . pr int ln ( obj . a package int ) ;11

12 // i l l e g a l access : a p r i va t e i n t has pr ivate access in13 // testpack . AccessModifierMembersClass14 // System . out . pr int ln ( obj . a p r i va t e i n t ) ;15

16 // l e ga l access17 System . out . pr int ln ( obj . getAPrivateInt ( ) ) ;18

19 // l e ga l access20 System . out . pr int ln ( obj . a protec ted int ) ;21

22 // l e ga l access23 System . out . pr int ln ( obj . a pub l i c i n t ) ;24 }25 }

einfache, abgeleitete Klasse:

Page 60: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 55

1 import testpack ;2

3 class AccessModifierTest3 extends AccessModifierMembersClass4 {5 public static void main( Str ing [ ] args )6 {7 AccessModifierMembersClass obj = new AccessModifierMembersClass ( ) ;8

9 // i l l e g a l access : a package int i s not publ ic in10 // testpack . AccessModifierMembersClass ; cannot be accessed11 // from outside package12 // System . out . pr int ln ( obj . a package int ) ;13

14 // i l l e g a l access : a p r i va t e i n t has pr ivate access in15 // testpack . AccessModifierMembersClass16 // System . out . pr int ln ( obj . a p r i va t e i n t ) ;17

18 // l e ga l access , because method i s publ ic !19 System . out . pr int ln ( obj . getAPrivateInt ( ) ) ;20

21 // i l l e g a l access : a protec ted int has protected access in22 // testpack . AccessModifierMembersClass23 // System . out . pr int ln ( obj . a protec ted int ) ;24

25 // l e ga l access26 System . out . pr int ln ( obj . a pub l i c i n t ) ;27 }28 }

einfache, abgeleitete Klasse, im selben Package:

1 package testpack ;2

3 class AccessModifierTest4 extends AccessModifierMembersClass4 {5 public static void main( Str ing [ ] args )6 {7 AccessModifierMembersClass obj = new AccessModifierMembersClass ( ) ;8

9 // l e ga l access10 System . out . pr int ln ( obj . a package int ) ;11

12 // i l l e g a l access : a p r i va t e i n t has pr ivate access in13 // testpack . AccessModifierMembersClass14 // System . out . pr int ln ( obj . a p r i va t e i n t ) ;15

16 // l e ga l access , because method i s publ ic !17 System . out . pr int ln ( obj . getAPrivateInt ( ) ) ;18

19 // l e ga l access20 System . out . pr int ln ( obj . a protec ted int ) ;21

22 // l e ga l access23 System . out . pr int ln ( obj . a pub l i c i n t ) ;24 }25 }

Wie man bei diesen Beispielen sieht, sollte man wissen, wie die Zugriffsmodifierzu verstehen sind. Noch einmal der Hinweis: Grundsatzlich ist der Zugriffauf Variablen von außerhalb der definierten Klasse uber Zugriffsfunktionen zusteuern! Ein direkter Zugriff auf Variablen soll nur in der Klasse, in der dieVariablen definiert sind, erfolgen!

Page 61: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 56

4.5.2 Object- und Class-Members

Wie in C++ gibt es auch in Java die Moglichkeit, Variablen und Methodenfur alle Objekte einer Klasse (Class-Members) zu definieren bzw. sie fur jedesObjekt separat zur Verfugung zu stellen (Object-Member). Die Unterscheidung,ob ein Member einer Klasse ein Object- oder ein Class-Member ist, erfolgt uberden Modifier static.

Fur Variablen in einer Klasse ist das Verhalten offensichtlich: Sie werden beider ersten Instantiierung eines Objekts dieses Typs initialisiert. Alle weiterenInstanzen von diesem Typ “teilen” sich diese Variable.

Aber nicht nur Variablen, sondern auch Methoden konnen mit dem Schlussel-wort static markiert werden. Mit solchen Methoden kann man im Prinzipwie mit Funktionen arbeiten. Es ist keine Instanz der Klasse fur den Auf-ruf notwendig. Bereits in Abschnitt 2.1.1 haben wir von statischen Metho-den gesprochen, die in Referenz-Datentypen Operationen durchfuhren (z.B.Integer.parseInt()). Innerhalb dieser Methoden kann man naturlich nichtauf Object-Member zugreifen (hier wurde der Compiler einen Fehler ausgeben:“non-static variable name cannot be referenced from a static context”).

Das folgende einfache Beispiel hat eine klassenweite Variable (static int num -instances ), die die Anzahl der bereits instantiierten Objekte mitzahlt. Außer-dem gibt es noch eine klassenweite Methode (’static int getNumInstances()’),die diesen Wert returniert. Diese Methode kann auf zwei unterschiedliche Artenaufgerufen werden: Uber eine Instanz der Klasse und auch ohne Instanz. Schau-en wir uns aber zuerst einmal die Klasse mit den unterschiedlichen Members an:

1 class ClassObjectMemberExample2 {3 static int num instances = 0;4 private String name ;5

6 public ClassObjectMemberExample ( Str ing name)7 {8 System . out . pr int ln (” create object : ” + name + ” . . . ” ) ;9 name = name ;

10 num instances ++;11 }12

13 public String getName()14 {15 return name ;16 }17

18 public static int getNumInstances ()19 {20 return num instances ;21 }22 }

Hier noch das dazu passende Testprogramm:

1 class ClassObjectMemberTest2 {3 public static void main( Str ing [ ] args )4 {5 System . out . pr int ln (”There are ” +6 ClassObjectMemberExample . getNumInstances () +7 ” instances of ClassObjectMemberExample . . . ” ) ;8

Page 62: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 57

9 ClassObjectMemberExample otto = new ClassObjectMemberExample (”Otto” ) ;10 ClassObjectMemberExample hugo = new ClassObjectMemberExample (”Hugo” ) ;11

12 System . out . pr int ln (”otto . getNumInstances : ” +13 otto . getNumInstances () +14 ” instances of ClassObjectMemberExample . . . ” ) ;15 System . out . pr int ln (”hugo . getNumInstances : ” +16 hugo . getNumInstances () +17 ” instances of ClassObjectMemberExample . . . ” ) ;18 System . out . pr int ln (” c a l l on c l a s s : ” +19 ClassObjectMemberExample . getNumInstances () +20 ” instances of ClassObjectMemberExample . . . ” ) ;21

22 System . out . pr int ln (”Name of object otto : ” + otto . getName ( ) ) ;23 System . out . pr int ln (”Name of object hugo : ” + hugo . getName ( ) ) ;24 }25 }

Aufruf auf der Konsole:exttt¿java ClassObjectMemberTest

There are 0 instances of ClassObjectMemberExample...create object: Otto...create object: Hugo...otto.getNumInstances: 2 instances of ClassObjectMemberExample...hugo.getNumInstances: 2 instances of ClassObjectMemberExample...call on class: 2 instances of ClassObjectMemberExample...Name of object otto: OttoName of object hugo: Hugo

Beachte bitte die unterschiedlichen Zugriffe auf die statische Methode und dieVerwendung der Variablen name : Jedes Objekt hat eine eigene Variable name !

4.5.3 Variablen-Modifier

Damit Variablen noch bestimmte Eigenschaften bekommen, konnen sie nochmit folgenden Modifier versehen werden:

final: Die Variable darf nach dem ersten Initialisieren nicht mehr verandertwerden. Vorsicht: Leider gibt es in Java keinen const-Modifier. FurKonstanten schlagt Sun Variablen vom Typ static final vor.

transient: Zeigt an, dass diese Variable nicht zum persistenten Zustand einesObjekts gehort, d.h. ihr Wert kann jederzeit wieder berechnet werden.Anwendung findet dieser Modifier bei Objekten, die z.B. uber ein Netz-werk auf einem anderen Computer ubertragen werden mussen. Hier machtes keinen Sinn, diese Variablen auch zu ubertragen.

volatile: Variable kann von unsynchronized Methoden verwendet werden,daher werden einige Optimierungen vom Compiler nicht durchgefuhrt(wird sehr selten verwendet...)

Page 63: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 58

4.5.4 Methoden-Modifier

Auch Methoden konnen noch mit Modifier versehen werden, um ihre Eigen-schaften genauer zu definieren.

final: Diese Methode kann nicht mehr in einer abgeleiteten Klasse anders de-finiert werden. Dadurch erubrigt sich das dynamische Binden von Metho-den bei Ableitungen.

abstract: Es folgt keine Definition der Methode! Es wird nur darauf hinge-wiesen, dass diese Methode von einer abgeleiteten Klasse implementiertwerden muss.

synchronized: Diese Methode kann nicht gleichzeitig von verschiedenen Threadsaufgerufen werden.

native: Die Definition dieser Methode erfolgt nicht in Java sondern in eineranderen Programmiersprache. Ist vor allem sinnvoll, wenn bestehendeLibraries in Java verwendet werden sollen (Stichwort “Java Native Inter-face”, JNI).

4.6 Initialisierung von Member-Variablen

Object- und Class-Variablen werden auf Standardwerte initialisiert. Class-Variablen, wenn die Klasse das erste Mal geladen wird bzw. Object-Variablenbei der Erzeugung von neuen Objekten. Sollen andere Werte als die Standard-werte verwendet werden, kann das in unterschiedlichster Form erfolgen:

Object-Variablen: Object-Members sollten im Konstruktor (siehe 4.3) initia-lisiert werden. Es gibt zwar auch die Moglichkeit, Object-Variablen inner-halb eines Blocks und innerhalb der Klasse zu initialisieren, jedoch sollteman das nicht in dieser Form umsetzen. Die Wartung des Codes ist al-lerdings durch eine solche Initialisierung extrem schwer. Initialisierungeninnerhalb des Konstruktors sind intuitiver. Da ein Konstruktor implizitfur alle Objekte von diesem Typ aufgerufen wird, ist es offensichtlich, dassClass-Variablen nicht uber den Konstruktor initialisiert werden konnen.

Class-Variablen (static): Fur die Initialisierungen von Class-Members kanneine einfache Zuweisung genommen werden:

static int num_instances_ = 0;

Wenn man sich mit Java beschaftigt, ist sofort klar, wo hier Problemauftreten konnen:

• Die Initialisierung ist auf einfache Zuweisungen beschrankt.

• Es konnen einfache Methoden aufgerufen werden, nicht jedoch Me-thoden, die Exceptions werfen (checked und runtime exceptions; sie-he 5).

Page 64: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 59

Ein Ausweg aus dieser Situation bietet ein static-Block, der die Class-Variablen initialisiert:

static{

// performe here high−soph i s t i cated c lass−member i n i t i a l i z a t i o n// inc luding error−handling via exceptions . . .

}

Vorsicht Falle: Class-Variablen werden beim ersten Laden der Klasse (z.B.TestClass) im beschriebenen static-Block initialisiert. Nun kann man indiesem static-Block uber z.B. Methoden einer anderen Klasse (z.B. Static-InitializerProblem) auf einen nicht initialisierten Wert der Klasse TestClasszugreifen. Man sollte sich dessen bewusst sein, und, wenn moglich, auf diesenstatic-Block verzichten.

1 class TestClass2 {3 static int an int ;4

5 static6 {7 System . out . pr int ln (” an int not yet i n i t i a l i z e d : ” +8 Stat i c In i t i a l i z e rProb l em . getAnInteger ( ) ) ;9 an int = 25;

10 }11 }12

13 public class Stat i c In i t i a l i z e rProb l em14 {15 static int getAnInteger ()16 {17 return TestClass . an int ;18 }19

20 public static void main( Str ing [ ] args )21 {22 TestClass obj = new TestClass ( ) ;23 }24 }

Aufruf auf der Konsole:exttt¿java StaticInitializerProblem

an_int_ not yet initialized: 0

4.7 Methoden

In Java gibt es nur Methoden und keine Funktionen. Will man Funktionendefinieren (z.B. berechne die Wurzel einer Zahl...), so mussen diese in Klassengesammelt werden. Hier macht es Sinn, die Methoden als static zu definieren.Ein Beispiel in der im SDK mitgelieferten API ist die Klasse java.lang.Math:In dieser sind viele mathematische Funktionen gesammelt, die uber die MathKlasse aufgerufen werden (z.B. Math.sqrt(25);).

Die Definition von Methoden ist ahnlich wie in C++:

Page 65: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 60

[ public | private |protected ] return−type methodName ( [ argument−l i s t ] )[ throws SomeException ]

• Informationen zu den method-modifier (public, private und protectedbzw. default) sind in Abschnitt 4.5.1 zu finden.

• Der return-type gibt an, welches Ergebnis die Methode liefert. Wird keinWert returniert, so muss void als Typ angegeben werden.

• Fur den Namen gilt dasselbe wie fur Namen von Variablen (siehe Ab-schnitt 2.2.1).

• Die argument-list besteht aus einer definierten, beliebig langen Liste vonArgumenten (incl. Typinformation). Argumente jeden Typs (Primitive-und Referenz-Datentypen) werden via call-by-value verwendet.

• Der letzte Teil der Signatur (throws...) wird in Kapitel 5 genauer unter-sucht.

Soweit scheint sich also im Vergleich zu anderen Programmiersprachen nichtsverandert zu haben. Betrachten wir nun aber einige Spezialitaten in Java.

call-by-value: Alle Parameter von Methoden werden immer uber ihren Wertubergeben. Fur Primitive-Datentypen kann also eine ubergebene Variablenicht in der aufrufenden Methode geandert werden.

Referenz-Datentypen werden speziell behandelt: Hier wird der Wert derReferenz (d.h. die Adresse) ubergeben. In anderen Worten: Es wird beieinem Methodenaufruf nicht das ganze Objekt auf den Stack gelegt, son-dern lediglich die Referenz von dem Objekt. Es ist daher moglich, dieubergebenen Objekte zu manipulieren, sofern sie nicht immutable (un-veranderlich) sind.

Schauen wir uns dieses Verhalten bei einem Beispiel an:

1 public class CallByValueExample2 {3 // change the value of some object4 static void manipulateParameter ( BaseClass bc , int new value )5 {6 bc . setSomeInt ( new value ) ;7 }8 // th i s does ∗not ∗ change the value of bc outs ide the method . . .9 static void dontManipulateParameter ( BaseClass bc , int new value )

10 {11 bc = new BaseClass ( new value ) ;12 }13

14 public static void main( Str ing [ ] args )15 {16 BaseClass bc1 = new BaseClass ( 2 ) ;17 System . out . pr int ln (”bc1 i s : ” + bc1 ) ;18 manipulateParameter (bc1 , 1 0 ) ;19 System . out . pr int ln (”bc1 i s now : ” + bc1 ) ;20 dontManipulateParameter (bc1 , 2 0 ) ;21 System . out . pr int ln (”bc1 i s now : ” + bc1 ) ;22

23 }24

25 }

Page 66: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 61

Aufruf auf der Konsole:exttt¿java CallByValueExample

Some other Constructor of BaseClass: some_int: 2bc1 is: BaseClass: some_int_: 2BaseClass::setSomeInt(...)bc1 is now: BaseClass: some_int_: 10Some other Constructor of BaseClass: some_int: 20bc1 is now: BaseClass: some_int_: 10

KEINE Default-Parameter: Eine lastige Einschrankung bei Methoden inJava ist das Fehlen von Default-Parametern. Als Konsequenz muss manentweder

• beim Aufruf der Methode alle Parameter angeben und gegebenenfallsmit Default-Werten aufrufen, oder

• man uberlad eine Methode mit allen moglichen Parametern (over-loading). Hier ist es sinnvoll, die Funktionalitat in einer Methode(selbstverstandlich jener, mit allen Parametern :)) zu implementie-ren und dann diese in allen anderen Methoden aufzurufen.

Als einfaches Beispiel (mit lediglich 2 Parametern) folgt nun ein Auszugaus java.lang.String:

public boolean startsWith ( Str ing pref ix , int t o f f s e t ){

// here the implementation . . .return . . . ;

}

public boolean startsWith ( Str ing pre f i x ){

return startsWith ( pref ix , 0 ) ;}

Die erste Definition implementiert die Funktionalitat, und die zweite De-finition ruft lediglich die erste auf.

final fur Parameter: In C++ konnen Parameter, die in der Methode nichtverandert werden durfen, mit const markiert. Wenn man eine Libra-ry verwendet sieht man sofort, welche Parameter nicht verandert werdenkonnen.

In Java kann man mit dem schon bekannten final Schlusselwort Parame-ter versehen, die nur einmal – namlich beim Aufruf der Methode – initiali-siert werden durfen (seit Java 1.1). Werden allerdings Objekte ubergeben,konnen diese bei vorhandenen Modifier-Methoden verandert werden.

automatischer cast bei Parameter: Wird als Parameter einer Methode einPrimitiver-Datentyp ubergeben, kann dieser automatisch in einen ’große-ren’ Primitiven-Datentyp umgewandelt werden. Will man explizit eineMethode mit einem bestimmten Primitiven-Datentyp aufrufen, muss manden Parameter explizit casten. Zusatzlich gibt es noch Probleme beimMethod-Overriding... (siehe Abschnitt 4.9).

Page 67: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 62

toString: Wenn eine String-Reprasentation eines Objekts gebraucht wird, dannwird automatisch nach einer Methode mit dem Namen toString ge-sucht (z.B. System.out.println(obj); bedeutet implizit System.out.-println(obj.toString());). Vor allem fur Debug-Zwecke ist eine sinn-volle Implementation dieser Methode wichtig.

Zuweisung vs. clone(): Bei einer “normalen” Zuweisung von einem Objektauf ein anderes, wird lediglich die Referenz auf das Ziel-Objekt zugewie-sen. Es wird also keine echte Kopie des Objekts angelegt. Soll ein Objektkopiert werden, wird die Methode clone() als Implementation vorgeschla-gen. Diese Methode entspricht dem copy-Konstruktor von C++. Der Auf-ruf ist so, wie man es sich erwartet: destination obj = source obj.clone();.

Vergleich vs. equals(...): Ein “normaler” Vergleich (via ==) betrachtet beiReferenz-Datentypen die Referenzen der verwendeten Objekte. Eine un-terschiedliche Referenz sagt aber nicht aus, dass die Inhalte der Objekteverschieden sind! Es kann ja sein, dass das Objekt vorher via clone()mit den gleichen Werten erzeugt wurde! In Java wird vorgeschlagen, dieMethode equals(...) fur Klassen zu implementieren. Ob ein Objektgleich wie das andere ist, hangt von der internen Struktur der jeweiligenKlasse ab. Aufruf: obj.equals(an obj);.

4.8 Inner Classes

Inner Classes (auch bekannt als “nested-classes”) sind Klassen, die innerhalbvon anderen Klassen definiert sind. Wenn die Existenz der inneren Klasse nurim Kontext der außeren Klasse Sinn macht, sollte man dieses Design verwenden.Die innere Klasse hat vollen Zugriff auf Member der außeren Klasse (auch wenndiese mit dem Schlusselwort private gekennzeichnet sind!). Da diese Typen vonKlassen wie “normale” Member einer Klasse behandelt werden, konnen auch dieAccess-Modifier (Abschnitt 4.5.1) verwendet werden.

class EnclosingClass{

. . .static class AStaticNestedClass{

. . .}class InnerClass{

. . .}class // an anonymous c l a s s{

. . .}

}

Wie alle Member von Klassen konnen auch diese Klassen mit dem Schlussel-wort static markiert sein. static Klassen konnen wiederum nur auf statischeMember zugreifen!

Besondere Inner Classes (sog. “Anonyme Klassen”) haben keinen Klassenna-men. Via

Page 68: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 63

new InterfaceName() { // here the implementation } odernew ClassName( arguments ) { // here the implementation }

kann eine Instanz einer solchen Klasse erzeugt werden.

Nested-classes sollten vermieden werden, da die Wartbarkeit des Codes leidet.Beim Compilieren wird Bytecode in der Form EnclosingClass$InnerClass.class erzeugt. Anonyme Klassen werden in den Bytecode-File EnclosingClass$1.class ubersetzt.

Innere Klassen sind schwer zu lesen und sollten wirklich nur fur einfachste Klas-sen (z.B. Event-Handler Adapter) verwendet werden. Aus diesem Grund wirdan dieser Stelle nicht weiter auf die Struktur dieser Klassen eingegangen.

4.9 Ableitung

Bei den Konstruktoren und Destruktoren haben wir bereits mit Ableitungengearbeitet und die Reihenfolge der Aufrufe betrachtet. Nun schauen wir unsEigenheiten bezuglich Methoden und Variablen von Java an.

In Java ist – anders als in C++ – nur eine einfache Ableitung moglich. DasSchlusselwort dazu haben wir schon in Abschnitt 4.2 kennengelernt: extends.

Hinweis: Es kann nicht von Klassen abgeleitet werden, die mit final deklariertwurden!

Eine abgeleitete Klasse “erbt” von ihrer Super-Klasse Methoden. Nicht finaldeklarierte Methoden von Basis-Klassen konnen via overriding neu definiertwerden. Methoden in der abgeleiteten Klasse mit der selben Signatur “overri-den” die Methoden der Super-Klasse3. Dazu haben wir schon einige Beispielegesehen. Wichtig ist, dass alle (nicht final markierten) Methoden virtuell sind,d.h. es wird immer die letzte Implementation in der Ableitungskette gesucht!Auch wenn das Objekt mit einem cast als Typ der Super-Klasse verwendetwird, wird immer die “letzte” Implementation in der Ableitungskette verwen-det. Im folgenden Beispiel sieht man dieses Verhalten in Zeile 46/47: Es wird furdie Methode getSomeInt die Implementation aus der Klasse SimpleSubClassverwendet und nicht, wie man vielleicht annehmen konnte, die Implementationaus SimpleBaseClass. Will man explizit die Implementation aus einer Basis-Klasse verwenden, kann man uber das Schlusselwort super darauf zugreifen.

1 class SimpleBaseClass2 {3 int some int = 1;4

5 int getSomeInt ()6 {7 return some int ;8 }9 }

10

11 class SimpleSubClass extends SimpleBaseClass12 {

3Bitte “override” nicht mit “overload” verwechseln. Beim “overloading” hat die Methodezwar denselben Namen, aber unterschiedliche Parameter!

Page 69: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 64

13 int some int = 2; // shadows some int from SimpleBaseClass14

15 int getSomeInt ( ) // overr ides getSomeInt from SimpleBaseClass16 {17 return −some int ;18 }19

20 int getSuperSomeInt ()21 {22 return super . getSomeInt ( ) ;23 }24 }25

26 public class DynamicMethodExample27 {28 public static void main( Str ing [ ] args )29 {30 SimpleBaseClass basec la s s ob j = new SimpleBaseClass ( ) ;31 SimpleSubClass subc lass obj = new SimpleSubClass ( ) ;32 SimpleBaseClass subc l a s s a s basec l a s s ob j = ( SimpleBaseClass ) subc lass obj ;33

34 System . out . pr int ln (” basec la s s ob j . getSomeInt ( ) : ” +35 basec la s s ob j . getSomeInt ( ) ) ;36 System . out . pr int ln (” basec la s s ob j . some int : ” +37 basec la s s ob j . some int ) ;38

39 System . out . pr int ln (” subc lass obj . getSomeInt ( ) : ” +40 subc lass obj . getSomeInt ( ) ) ;41 System . out . pr int ln (” subc lass obj . getSuperSomeInt ( ) : ” +42 subc lass obj . getSuperSomeInt ( ) ) ;43 System . out . pr int ln (” subc lass obj . some int : ” +44 subc lass obj . some int ) ;45

46 System . out . pr int ln (” subc l a s s a s basec l a s s ob j . getSomeInt ( ) : ” +47 subc l a s s a s basec l a s s ob j . getSomeInt ( ) ) ;48 System . out . pr int ln (” subc l a s s a s basec l a s s ob j . some int : ” +49 subc l a s s a s basec l a s s ob j . some int ) ;50 }51 }

Aufruf auf der Konsole:exttt¿java DynamicMethodExample

baseclass_obj.getSomeInt(): 1baseclass_obj.some_int_: 1subclass_obj.getSomeInt(): -2subclass_obj.getSuperSomeInt(): 1subclass_obj.some_int_: 2subclass_as_baseclass_obj.getSomeInt(): -2subclass_as_baseclass_obj.some_int_: 1

Anders ist das Verhalten bei Variablen: Hier sieht man in Zeile 48/49 desvorherigen Beispiels, dass man den Variablen-Wert jener Klasse bekommt, aufden das Objekt “gecastet” wurde. Im Fall von Zeile 48/49 also den Wert ausSimpleBaseClass. Mit super.some var name kann man explizit in abgeleite-ten Klassen auf die versteckte Variable der Super-Klasse zugreifen.

Vorsicht Falle: Man kann es wirklich nicht oft genug schreiben: Man sollte nievergessen, dass Methoden virtuell sind! Dadurch wird immer die letzte in derAbleitungskette definierte Implementation einer Methode aufgerufen. DiesesVerhalten kann man nur verhindern, indem man die jeweilige Methode in derSuper-Klasse final deklariert.

Page 70: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 65

Eigentlich sollten nur jene Methoden in einer Sub-Klasse neu definieren werden,die exakt dieselbe Signatur haben (“overriding”), wie jene in der Basis-Klasse.Alles andere ist overloading. Betrachten wir folgendes Beispiel, wo versuchtwird, eine Methode mit float-Parameter zu definieren, die bereits in der Basis-Klasse (BaseClass.java) mit einem int-Parameter definiert ist.

1 public class OverloadingExample extends BaseClass2 {3 // overload setSomeInt : watch s ignature ! !4 public void setSomeInt ( f loat some f loat )5 {6 System . out . pr int ln (”setSomeInt ( f l o a t ) of OverloadingExample” ) ;7 some int = ( int ) some f loat ;8 }9

10 public static void main( Str ing [ ] args )11 {12 OverloadingExample obj = new OverloadingExample ( ) ;13 System . out . pr int ln (” c a l l now setSomeInt with f l o a t . . . ” ) ;14 obj . setSomeInt (12.0 f ) ;15

16 System . out . pr int ln (” c a l l now setSomeInt with an int . . . ” ) ;17 // the fo l lowing does ∗not ∗ work i f ca l l ed without the cast ! !18 // OverloadingExample . java : 2 1 : Reference to setSomeInt i s19 // ambiguous . I t i s def ined in void setSomeInt ( f l o a t ) and void20 // setSomeInt ( int ) .21 ( ( BaseClass ) obj ) . setSomeInt (12 ) ;22 }23 }

Aufruf auf der Konsole:exttt¿java OverloadingExample

Default constructor of BaseClasscall now setSomeInt with float...setSomeInt(float) of OverloadingExamplecall now setSomeInt with an int...setSomeInt() of BaseClass

In Zeile 4 wird die Methode setSomeInt via overloading der Klasse hinzugefugt.Interessant ist aber, dass nach der Definition dieser neuen Methode, die MethodesetSomeInt(int...) aus der Basis-Klasse nicht mehr ohne expliziten cast desObjekts auf die Basis-Klasse aufgerufen werden kann!!! Die Erklarung dazu ist(relativ :)) einfach: int ist ein Sub-Typ von float: Nun kann der Compilernicht entscheiden, welche Implementation eingesetzt werden soll, und es ergibtsich die gemeldete Mehrdeutigkeit.

4.10 Interface

Wie im letzten Abschnitt erwahnt, gib es in Java nur eine einfache Ableitung. Eskann also nicht von mehreren Klassen abgeleitet werden. Diese Einschrankungist problematisch, kann aber uber sog. Interfaces teilweise umgangen werden.

Ein Interface definiert einen Referenz-Datentyp, der einer abstrakten Klassesehr ahnlich ist. Aber:

Page 71: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 66

• Es konnen nur static final Member-Variablen definiert werden.

• Alle Methoden sind implizit abstrakt.

• Ein Interface kann nicht instantiiert werden.

Definition eines Interfaces:[ public ] interface TheInterfaceName [ extends AnotherInterface ]

Implizit sind alle Deklarationen innerhalb eines Interface’s public und abstract.Die Implementation des Interfaces erfolgt in einer Klasse, die via implementsTheInterfaceName definiert wurde. Eine Klasse kann mehrere Interfaces imple-mentieren. Samtliche im Interface deklarierten Methoden sollten in der Klassedefiniert werden. Passiert das nicht, muss die Klasse mit abstract als abstraktdefiniert werden und eine Sub-Klasse muss die nicht definierten Methoden im-plementieren.

Da alle Methoden abstrakt sind, kann es keine Default-Implementation fur Me-thoden geben. Es kann also passieren, dass bei einem schlechten Klassendesignaufgrund der Einschrankung der einfachen Vererbung Interfaces verwendet wer-den mussen und dann jede Klasse explizit eine Methode in gleicher Weise im-plementieren muss. Sollte so etwas passieren: Zuruck zum “Zeichentisch” unddie Klassenstruktur redesignen.

4.11 Ein kurzer Einblick in Packages

Klassen konnen in sog. Packages gruppiert werden. Gemeinsam mit dem Na-men des Packages und dem Klassennamen ergibt sich ein full qualified classna-me, mit dem diese Klasse identifiziert werden kann. Das Schlusselwort fur dieGruppendefinition ist package. Wenn man die bisherigen Beispiele betrachtet,sieht man, dass hier dieses Schlusselwort nicht verwendet wurde. Daraus istersichtlich, dass es auch “namenlose” Packages geben kann. In Projekten mitvielen Klassen und einzelnen Modulen ist es aber sinnvoll, die einzelnen Module(d.h. zusammengehorige Klassen) in Packages zu organisieren. Betrachten wireine solche Gruppendefinition in einer Klasse:

// some f i l e . . .package some package name ;public class SomeClassA { . . . }

// some other f i l e . . .package some package name ;public class SomeClassB { . . . }

Die Klasse someClassA hat nun den full qualified name:some package name.SomeClassA. Diese Klasse ist im selben package wie dieKlasse some package name.SomeClassB. Will man Packages weiter unterteilen,so kann man Subpackages (getrennt durch ’.’) definieren. Z.B.

package some package name . sub package ;public class SomeOtherClass { . . . }

In diesem Fall ware dann der volle Name der Klasse:some package name.sub package.SomeOtherClass. Es sollte diese Package-struktur auch in der Verzeichnisstruktur, in der der Sourcecode abgelegt ist,

Page 72: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 4. KLASSEN IN JAVA 67

widergespiegelt werden. Fur unser Beispiel: Die Files SomeClassA.java undSomeClassB.java sollten in einem Verzeichnis some package name gespeichertwerden, Wobei SomeOtherClass.java im Verzeichnis some_package_name/sub_package abgelegt sein sollte. Diese Struktur ist nicht zwingend, jedoch ratsam,da der Bytecode (.class-Files) automatisch in der entsprechenden Verzeichnis-hierarchie abgelegt wird. Aus Grunden der Symmetrie ist das wunschenswert.

Will man diese in Packages organisierten Klassen verwenden, kann man entwederbeim Instantiieren den vollen Klassennamen angeben(obj = new some package name.SomeClassA();) oder das import Statementmit dem full qualified name der Klasse verwenden.

import some package name . SomeClassA ;public class TestClass{

SomeClassA obj = new SomeClassA ( ) ;}

Sollen mehrere Klassen aus einem Package eingebunden werden, so kann manauch import some package name.* (type-import-on-demand) verwenden. Umden Uberblick uber die verwendeten Klassen zu behalten, sollte man jedesimport-Statement explizit schreiben und auf den “*”, soweit sinnvoll, verzich-ten.

Hinweis: Ein Package weiß nichts von eventuell vorhandenen Subpackages!D.h. ein import some package name.* stellt nur die im Package some_package_name definierten Klassen zur Verfugung.

Hinweis: Wird eine Klasse via import eingebunden, dann kann man Objektedieser Klasse einfach uber obj = new TheNameOfTheClass(); instantiieren. Esist aber nicht moglich, direkt auf Member der Klasse zuzugreifen!

Hinweis: Im Vergleich zu C++ wird in Java nicht bei der Ableitung festge-legt, welcher Zugriff (private, protected oder public) auf die Super-Klassezugelassen wird. Es ist daher eine Gruppierung von Klassen in Packages absolutnotwendig.

Von Haus aus werden implizit alle Klassen vom Package java.lang eingebunden(import java.lang.*), d.h. die folgenden Klassen stehen in jedem Programmautomatisch zur Verfugung (Java 1.4):

AssertionError, Byte, Character, Class, ClassCircularityError,ClassLoader, ClassNotFoundException, Compiler, Double, Error,Exception, ExceptionInInitializerError, Float, IllegalAccessError,IllegalAccessException, IllegalThreadStateException,InheritableThreadLocal, Integer, Long, Math, NoSuchFieldException,Number, Object, Package, Process, Runtime, RuntimeException,RuntimePermission, SecurityException, Short, StackTraceElement,StrictMath, String, StringBuffer, System, ThreadDeath, ThreadLocal,Throwable, UnsupportedOperationException

Page 73: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 5

Fehlerbehandlung

Fur die Fehlerbehandlung eignen sich Exceptions außerordentlich gut. Seit Ja-va 1.4 gibt es auch noch sog. Assertions zur Fehlererkennung, die in diesemAbschnitt jedoch nicht behandelt werden.

5.1 Exceptions

Exceptions werden verwendet, um Fehler im Programmablauf zu melden. Me-thoden konnen in einem solchen Fall selbst darauf reagieren oder diese Exceptioneinfach an den Aufrufenden weitergeben.

try{

// try something where exceptions may appear . . .}catch ( SubException ex ){

// catch some type of exception . . .}catch ( Exception ex ){

// catch a l l other exceptions . . .}f inal ly{

// some f i n a l cleanup . . .}

Das Konzept ist ahnlich wie in C++: In einem try-Block werden die Ope-rationen abgearbeitet, die eventuell Probleme bereiten konnten. Im Fehlerfall(=Exception wird von einer Methode “geworfen”) wird dieser try-Block verlas-sen und in den “erstbesten” catch-Block verzweigt. Der “erstbeste” ist jenerBlock, in dem der Typ der geworfenen Exception behandelt wird.

Im Unterschied zu C++ gibt es in Java noch einen optionalen finally-Block,der auf alle Falle ausgefuhrt wird, egal ob eine Exception behandelt wird odernicht. In diesem finally sollten z.B. Files geschlossen werden. Der finally-Block wird nur dann nicht ausgefuhrt, wenn zuvor ein System.exit(...); auf-gerufen wurde.

Vorsicht Falle: Sollte im try-Block ein Wert retourniert werden, muss man

68

Page 74: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 5. FEHLERBEHANDLUNG 69

darauf achten, dass im finally-Block nicht ebenfalls ein Wert retourniert wird,da dieser Wert dann dem Aufrufenden zuruckgegeben wird...

Ein weiterer Unterschied zu C++ existiert: Wahrend in C++ beliebige Objektevia throw “weitergeworfen” werden konnen, muss in Java eine Exception vomTyp Throwable sein. In Java gibt es zwei Sub-Klassen von Throwable: Errorund Exception. Errors weisen auf einen Fehler innerhalb der JVM hin und soll-ten unter normalen Umstanden nicht vom Entwickler behandelt und verwendetwerden. Exceptions konnen (und sollen!) behandelt werden.

Bei den Exceptions gibt es noch eine weitere interessante Sub-Klasse, namlichRuntimeException (z.B. NullPointerException, IndexOutOfBoundsException,etc.). RuntimeExceptions sollten nicht als Basis-Klasse von eigenen Exceptionsdienen, da diese nicht explizit in einer Methode deklariert werden mussen.

Betrachten wir ein einfaches Beispiel:

1 class MyException extends Exception2 {3 MyException ()4 {5 }6 MyException( Str ing message )7 {8 super(message ) ;9 }

10 }

• MyException leitet sich von Exception ab und kann daher via throw ver-wendet werden. Fur eine vernunftige Fehlerbehandlung ist es notwendig,eine eigene Exception-Hierarchie zu erzeugen.

• Die wohl gangigste Methode bei der Behandlung von Exceptions fur De-bugzwecke ist die Methode printStackTrace(). Sie gibt den Status desStacks aus. Diese Methode erleichtert enorm die Fehlersuche (siehe Bild-schirmausgabe in ExceptionExample).

1 public class ExceptionExample2 {3 // th i s method does not handle the exception and simply4 // throws i t to the c a l l e r5 void someMethod( int index )6 throws MyException7 {8 System . out . pr int ln (”In someMethod ( index : ” + index + ”)” ) ;9 i f ( index > 3)

10 {11 throw new MyException(”Index > 3!” ) ;12 }13 }14

15 // handle the exception16 void someOtherMethod( int index )17 {18 System . out . pr int ln (”In someOtherMethod ( index : ” + index + ”)” ) ;19 try20 {21 i f ( index > 3)22 {

Page 75: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 5. FEHLERBEHANDLUNG 70

23 throw new MyException(”Index > 3!” ) ;24 }25 }26 catch (MyException ex )27 {28 System . out . pr int ln (”someOtherMethod : : caught MyException : ” + ex ) ;29 ex . printStackTrace ( ) ;30 }31 catch ( Exception ex )32 {33 System . out . pr int ln (”someOtherMethod : : caught exception : ” + ex ) ;34 ex . printStackTrace ( ) ;35 }36 f inal ly37 {38 System . out . pr int ln (”someOtherMethod : : f i na l l y−Block” ) ;39 }40 }41

42 public static void main( Str ing [ ] argv )43 {44 ExceptionExample exception example = new ExceptionExample ( ) ;45

46 System . out . pr int ln (”Fi r s t try . . . ” ) ;47 try48 {49 for ( int index=0; index <6; index++)50 {51 exception example . someMethod( index ) ;52 }53 }54 catch ( MyException ex )55 {56 System . out . pr int ln (”main : f i r s t try : caught exception : ” + ex ) ;57 ex . printStackTrace ( ) ;58 }59 catch ( Exception ex )60 {61 System . out . pr int ln (”main : f i r s t try : caught some other exception : ” + ex ) ;62 ex . printStackTrace ( ) ;63 }64 f inal ly65 {66 System . out . pr int ln (”main : f i r s t try : in the f i n a l l y block” ) ;67 }68

69 System . out . pr int ln (”Second try . . . ” ) ;70 try71 {72 for ( int index=0; index <6; index++)73 {74 exception example . someOtherMethod( index ) ;75 }76 }77 catch ( Exception ex )78 {79 System . out . pr int ln (”main : second try : caught exception : ” + ex ) ;80 ex . printStackTrace ( ) ;81 }82 f inal ly83 {84 System . out . pr int ln (”main : second try : in the f i n a l l y block” ) ;85 }86 }87 }

• someMethod erzeugt eine Exception, wenn der ubergebene Parameter derMethode großer 3 ist. Bemerkenswert ist Zeile 6: Hier wird definiert, dassdiese Methode eine Exeption werfen kann. Im Unterschied zu C++ isteine Definition absolut notwendig, da sonst das Programm nicht compi-

Page 76: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 5. FEHLERBEHANDLUNG 71

liert. Man sieht auf einen Blick, welche Exceptions auftreten konnen.RuntimeExcpetions mussen in der throws-Anweisung nicht deklariertwerden.

• someOtherMethod behandelt die auftretenden Exceptions selbst. Inter-essant ist hier, dass wirklich der finally-Block ausgefuhrt wird, un-abhangig davon, ob eine Exception geworfen wird oder nicht.

• In der main-Methode werden die oben definierten Methoden ausgefuhrt.Man kann beobachten, wie die Exception, die in someMethod geworfenwird, in main behandelt wird und dass danach sofort der try-Block (Zei-len 47-53) verlassen wird.

• Die Methode someOtherMethod wird im Unterschied zu someMethod 6-mal aufgerufen, da ja die Exception schon in der Methode selbst behandeltwird.

Aufruf auf der Konsole:exttt¿java ExceptionExample

First try...In someMethod (index: 0)In someMethod (index: 1)In someMethod (index: 2)In someMethod (index: 3)In someMethod (index: 4)main: first try: caught exception: MyException: Index > 3!MyException: Index > 3!at ExceptionExample.someMethod(ExceptionExample.java:11)at ExceptionExample.main(ExceptionExample.java:51)

main: first try: in the finally blockSecond try...In someOtherMethod (index: 0)someOtherMethod::finally-BlockIn someOtherMethod (index: 1)someOtherMethod::finally-BlockIn someOtherMethod (index: 2)someOtherMethod::finally-BlockIn someOtherMethod (index: 3)someOtherMethod::finally-BlockIn someOtherMethod (index: 4)someOtherMethod::caught MyException: MyException: Index > 3!MyException: Index > 3!at ExceptionExample.someOtherMethod(ExceptionExample.java:23)at ExceptionExample.main(ExceptionExample.java:74)

someOtherMethod::finally-BlockIn someOtherMethod (index: 5)someOtherMethod::caught MyException: MyException: Index > 3!MyException: Index > 3!at ExceptionExample.someOtherMethod(ExceptionExample.java:23)at ExceptionExample.main(ExceptionExample.java:74)

Page 77: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 5. FEHLERBEHANDLUNG 72

someOtherMethod::finally-Blockmain: second try: in the finally block

Page 78: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 6

Swing

Mit dem Swing-Package (javax.swing, mehr als 500 Klassen und Interfaces)kann man recht einfach graphische Benutzeroberflachen fur Applikationen zu-sammenstellen. Da der Umfang dieser Library recht groß ist, beschrankt sichdieses Kapitel auf die Grundlagen. Damit wird es moglich sein, einfachste Pro-gramme zu schreiben. Eine genauere Beschreibung und Anwendung der ein-zelnen Klassen ist in [Java Tutorial 2002] bzw. in [Java SDK Doc 2002] zufinden. Swing gibt es seit Java 1.2 und ist im Package javax.swing zu finden.Es wird generell geraten, Swing fur grafische Applikationen zu verwenden undnicht die “alten” AWT (“Abstract Windowing Toolkit”) Libraries. Auf keinenFall sollten AWT- und Swing-Komponenten gleichzeitig miteinander in einemProgramm verwendet werden.

Die Java Foundation Classes (JFC) bilden den Grundstock fur Benutzerober-flachen. Swing ist ein Bestandteil dieser JFC. Die Teile dieser Klassensammlungsind:

Swing Komponenten: Eine Sammlung von Klassen, die die graphische Schnitt-stelle zwischen Bentuzer und Applikation ermoglicht.

Pluggable Look and Feel: Es ist moglich, die Komponenten unterschiedlichdarzustellen. Mit der Unterstutzung von verschiedenen Look-and-Feelshat der Benutzer einfach die Moglichkeit Java-Applikationen seinen Ge-wohnheiten entsprechend auszufuhren.

Accessibility API: Graphische Bentuzeroberflachen sollen auch fur alternati-ve Anzeige-/Lesegeraten (z.B. Braille-Zeile) zuganglich sein.

Java 2D API: Einfache 2D-Graphiken konnen mit dieser API erstellt werden.

Drag and Drop Support: Drag and Drop zwischen Java- und anderen Ap-plikationen kann mit dieser API implementiert werden.

Im Rahmen dieser Veranstaltung betrachten wir aus dem JFC nur einen kleinenTeil der Swing-Klassen.

73

Page 79: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 74

6.1 Und wieder ein einfaches Beispiel

Bevor wir uns auf einzelne Klassen sturzen, schauen wir uns das vermutlicheinfachste Swing-Programm an. Es ist wichtig, die Konzepte zu verstehen, diein Swing verfolgt werden. Fur die Umsetzung kann man auch einen GUI-Builderverwenden1.

1 import javax . swing . ∗ ;2

3 public class VerySimpleSwingExample4 {5 public static void main( Str ing [ ] args )6 {7 JFrame a frame = new JFrame(”The Frame” ) ;8 JLabel a l abe l = new JLabel (” I ’m a very simple swing example . ” ) ;9 a frame . getContentPane ( ) . add( a l abe l ) ;

10 a frame . setDefaultCloseOperation (JFrame .EXIT ON CLOSE) ;11 a frame . pack ( ) ;12 a frame . s e tV i s ib l e (true ) ;13 }14 }

In diesen wenigen Zeilen werden viele Konzepte (einzelne Container beinhal-ten irgendwelche Komponenten...) von Swing verwendet. Betrachten wir dieeinzelnen Zeilen des Programms etwas genauer:

import javax.swing.*: Damit die Klassen aus dem Swing-Package direkt imProgramm verwendet werden konnen, muss das Package eingebunden wer-den. Wenn man noch Events behandeln will (was das ist, erfahren wir inKurze...), benotigt man zusatzlich noch Klassen aus dem java.awt- bzw.java.awt.event-Package. Viele der Swing-Klassen basieren auf dem Ab-stract Windowing Toolkit (AWT).

import java.awt.*;import java.awt.event.*;import javax.swing.*;

new JFrame(...): Ein Frame ist ein Container, der mehrere unterschiedlicheKomponenten beinhalten kann und diese auch darstellt. Jede Swing-Applikation muss (zumindest) einen sog. top-level container verwenden(siehe JFrame, JDialog, fur Applets noch JApplet). Unmittelbar nachdem Erzeugen ist ein Frame ’versteckt’. Man sollte daher nicht auf Zei-le 11/12 vergessen :)

new JLabel(...): Ein Label ist nun eine solche Komponente, die innerhalb desFrames dargestellt werden soll. Bevor wir das Label verwenden konnen,muss es selbstverstandlich erzeugt werden. In der darauffolgenden Zeilewird dieses Label dem Frame (genauer einer ’Scheibe’ – pane – diesesFrames) hinzugefugt.

1GUI-Builder sind in einigen IDEs – z.B. JBuilder, Sun ONE Studio (aka Forte) etc. –integriert. Mit diesen Werkzeugen wird es einfacher, einzelne Elemente zu positionieren...).Diese GUI-Builder erzeugen allerdings einen sehr schlechten Code! Man muss der generiertenCode auf alle Falle einem Review unterziehen!

Page 80: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 75

a frame.setDefaultCloseOperation(...): Der Name dieser Methode sagtwohl alles... Seit Java 1.3 ist diese Vorgehensweise moglich. Fur altereVersionen muss ein EventListener (siehe spater) implementiert werden.

a frame.pack(): Letzte Vorbereitungen fur die Darstellung (Berechnung derFenstergroße aufgrund der Komponenten, die im Frame sind).

a frame.setVisible(...): Frame wird nun dargestellt.

Und so sieht das Ergebnis aus:

Abbildung 6.1: Ein einfaches Swing-Beispiel

So einfach ist das. Wie man aber schon bei diesem einfachen Programm sieht,ist es notwendig, einige Eigenschaften von Swing zu kennen (z.B. das Frame perdefault nicht sichtbar sind...), ansonsten sucht man verzweifelt nach dem Fehler.

6.2 Die Model-View-Controller Architektur

Im Zusammenhang mit grafischen Oberflachen fallt immer wieder der BegriffMVC-Architektur. In diesem Abschnitt betrachten wir kurz die Eigenschaftendieses Ansatzes.

Model : Hier wird die interne Datenreprasentation einer Komponente (siehenachster Abschnitt) verstanden. Wenn man ein Texteingabefeld betrach-tet, ist das dahinterstehende Modell die Zeichenkette, die eingegeben wur-de. Fur einen Button, der gedruckt werden kann, ist das Datenmodell derStatus, ob er gedruckt wurde oder nicht usw. Wichtig ist hier zu erkennen,dass ein Model auch ohne visueller Komponente existieren kann.

View : Das ist die visuelle Komponente, die das Modell nach “außen hin” vi-sualisiert. Auch hier soll auf die Abkopplung zum internen Datenmodellhingewiesen werden. Ob ein Textfeld (JTextField) runde Kanten hatoder nicht, oder ob ein Fenster die Titelzeile zentriert oder linkbundigzeichnet, ist fur die interne Reprasentation vollkommen uninteressant2.

Controller : Dieser Teil der Architektur behandelt die Aktionen (events), diemit der Komponente in Verbindung gebracht werden sollen. Was soll z.B.passieren, wenn man einen bestimmten Button druckt, oder wenn manein Feld ausgefullt hat?

Betrachtet man die einzelnen Aufgaben der Teile, dann sieht man folgendenZusammenhang:

2Applikationen, die auf unterschiedlichen Plattformen gestartet werden konnen, sind hierein sehr offensichtliches Beispiel fur unterschiedliche “Views” von ein und derselben Kompo-nente.

Page 81: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 76

• Das Model gibt Informationen an den View zur Darstellung weiter.

• Der3 View bestimmt, welche Aktionen an den Controller weitergegebenwerden konnen.

• Der Controller ist dafur zustandig, dass das interne Datenmodell wiederauf den aktuellen Stand gebracht wird (das also z.B. die Zeichenkette, diein einem Textfeld geandert wurde, auch im Model aktualisiert wird.

Die Komponenten von Swing sind fast nach dieser Architektur aufgebaut. Eswurde eine starkere Kopplung zwischen dem View- und Controller-Element im-plementiert, damit es einfacher wird, die Komponenten zu bedienen. Auchfur diesen Ansatz gibt’s einen Namen: model-delegate. Jede Komponente inSwing hat ein Model und einensiehe letzte Fußnote... Delegate (genauer einenGUI-Delegate). Das Model ist fur die interne Reprasentation zustandig. DerDelegate ist fur die Visualisierung der Komponente sowie fur die Events, diediese Komponente auslosen kann zustandig.

Fur den Entwickler bieten sich durch diese Architektur viele Vorteile. Es istbspw. moglich, unterschiedliche Views an ein Model zu binden, d.h. bestimmteDaten konnen entweder als Tabelle oder als Diagramm dargestellt werden. DieDaten werden nur an einer Stelle verwaltet (d.h. geandert) und die jeweiligenViews stellen automatisch die Daten richtig dar, ohne, dass man besondereAktionen setzen muss.

Fur die ersten Schritte sollte die obige Erklarung ausreichend sein. Durch Bei-spiele, die in der Folge noch betrachtet werden, wird in wenigen Abschnitten dasKonzept von Swing verinnerlicht und es sollte kein Problem mehr sein, bisherunbekannte Komponenten in ein Programm einzusetzen.

6.3 Container und Komponenten

Container sind – wie schon angedeutet – Klassen, die einzelne Komponentenhalten. Da Container auch Komponenten sind, konnen Container selbst wiederin Container gesteckt werden.

Es gibt eine besondere Gattung von Container, die nicht wieder in Containerpositioniert werden konnen: sog. Top-level Container (JFrame, JDialog undJApplet). Versucht man es trotzdem, einen solchen Top-level Container in einenContainer zu stecken, wird eine Exception geworfen (“java.lang.Illegal-ArgumentException: adding a window to a container”).

In Abbildung 6.2 ist zu sehen, wie ein JFrame aufgebaut ist:

Ein Top-level Container stellt eine spezielle content pane (dt. “Scheibe”) zurVerfugung, die via getContentPane() angefordert werden kann. Auf dieser

3Der/die/das View. Hier kann der Leser entscheiden, welcher Artikel einzusetzen ist. Jenachdem, wie man view ubersetzt: In diesem Zusammenhang sehe ich view als “der Dar-stellungteil des Modells”, es kann aber “die Darstellungskomponente des Modells”, oder (furdie Puristen) einfach “das View-Element” heißen. Alle Germanisten mogen mir verzeih’n.Wichtig fur mich ist, dass die Nachricht, die ich weitergeben will, richtig ankommt...

Page 82: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 77

Abbildung 6.2: Container mit ContentPane

content pane wird der Inhalt (also die einzelnen Komponenten, die diesem Con-tainer hinzugefugt wurden) gezeichnet4.

Der einfachste dieser Panes ist JPanel, dann gibt es noch JScrollPane (hierwerden automatisch bei Bedarf Scrollbars zur Verfugung gestellt), JTabbedPane(eine Pane als “Karteikarte”) und einige andere.

6.4 Layoutmanager

Unser erstes Beispiel war relativ einfach: Wir haben einen frame erzeugt, vondiesem die content pane geholt und eine Komponente (ein JLabel) hinzugefugt.

Sollen nun mehrere Komponenten in einen Container positioniert werden, mussein Layoutmanager die Komponenten in die “richtige” Position bringen. Die-ser Layoutmanager wird via setLayout(...) einer bestimmten Pane zugewie-sen. Einer Komponente kann man via setMinimumSize, setPreferredSizeund setMaximumSize (letzteres wird nur vom BoxLayout berucksichtig) in derGroße beeinflussen. Man sollte jedoch wissen, dass nicht alle Großenangabenbei jedem Typ von Komponente berucksichtigt werden...5

Zwischen den einzelnen Komponenten im Container kann uber unterschiedlichs-te Mechanismen ein Freiraum definiert werden. Man kann uber den verwendetenLayoutmanager diese Rander erzwingen, versteckte Komponenten oder spezielleBorder-Objekte verwenden.

Was ist nun die “richtige Position” eines Elements? Hier entscheidet der Lay-outmanager, wo die Elemente am Bildschirm dargestellt werden sollen. Es gibtfolgende Layoutmanager in Swing:

BorderLayout: Die Bereiche werden in Norden, Suden, Osten, Westen und ge-nau in der Mitte (BorderLayout.NORTH, -.SOUTH, -.EAST, -.WEST bzw.

4Wenn man versucht, mehrere Komponenten einer content pane hinzuzufugen, wird jeweilsnur die letzte gezeichnet. Will man daher mit mehreren Komponenten arbeiten, muss mandiese in Gruppen via panes organisieren bzw. einen Layoutmanager verwenden!

5So wird z.B. die Angabe von setMinimumSize bei einem JLabel ignoriert, eine preferredsize wird jedoch richtig ausgewertet...

Page 83: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 78

Abbildung 6.3: Unterschiedliche Layoutmanager in Aktion...

-.CENTER) unterteilt. Vorsicht: Es darf immer nur eine Komponente ineinem Bereich liegen!

Container content pane = getContentPane ( ) ;content pane . setLayout (new BorderLayout ( ) ) ;content pane . add(new JButton (”Button 1” ) , BorderLayout .NORTH) ;content pane . add(new JButton (”2” ) , BorderLayout .CENTER) ;. . .

Man kann via setHgap(...) und setVgap(...) die Rander (in Pixel)zwischen den Bereichen anpassen bzw. im Konstruktor die Rander defi-nieren (siehe auch Sun-Tutorial6).

GridLayout: Hier wird der gesamte Bereich in gleich große Zellen geteilt. Wirdim Konstruktor ein Parameter mit 0 ubergeben, so wird dieser Wert auto-matisch (und dynamisch) festgelegt. Im folgenden Beispiel wird ein Grid-Layout mit einer undefinierten Anzahl von Zeilen und genau zwei Spaltendefiniert.

Container content pane = getContentPane ( ) ;content pane . setLayout (new GridLayout (0 , 2 ) ) ;content pane . add(new JButton (”Button 1” ) ) ;. . .

Auch in diesem Fall kann noch ein Rand zwischen den einzelnen Zellendefiniert werden (entweder uber setHgap(...) bzw. setVgap(...) undauch uber den Konstruktor). Außerdem kann noch festgelegt werden, inwelcher Reihenfolge die Zellen aufgefullt werden – im bzw. gegen denUhrzeigersinn (siehe auch Sun-Tutorial7).

FlowLayout: Bei diesem Layout werden die Komponenten einfach nacheinan-der visualisiert. Bei Bedarf wird eine neue Zeile eingefugt. Die Ausrich-tung der einzelnen Komponenten kann uber den Konstruktor bzw. eineMethode setAlignment() festgelegt werden (FlowLayout.LEFT, -.RIGHT,-.CENTER, -.LEADING, -.TRAILING, siehe auch Sun-Tutorial8).

6http://java.sun.com/docs/books/tutorial//uiswing/layout/border.html7http://java.sun.com/docs/books/tutorial//uiswing/layout/grid.html8http://java.sun.com/docs/books/tutorial//uiswing/layout/flow.html

Page 84: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 79

Container content pane = getContentPane ( ) ;content pane . setLayout (new FlowLayout (FlowLayout .RIGHT) ) ;content pane . add(new JButton (”Button 1” ) ) ;. . .

BoxLayout: Die Komponenten werden in einer einzelnen Zeile oder einer ein-zelnen Spalte dargestellt, wobei auch hier die Ausrichtung der einzelnenKomponenten festgelegt werden kann (siehe auch Sun-Tutorial9).

Container content pane = getContentPane ( ) ;content pane . setLayout (new BoxLayout( content pane ,

BoxLayout .Y AXIS ) ) ;addAButton(”Button 1” , content pane ) ;

In der Methode addAButton kann definiert werden, wie das einzelne Ele-ment in dem Container ausgerichtet werden soll (siehe Sourcecode vonBoxWindow.java).

GridBagLayout: Dieser Manager ist wohl der machtigste der hier vorgestell-ten. Die Komponenten werden in Zeilen und Spalten positioniert, wobeisie uber mehrere Zeilen und Spalten gehen konnen. Die Zeilen und Spal-ten konnen unterschiedliche Hohen und Breiten haben. Ein Beispiel sagtvielleicht mehr als 1000 Worte. Auch in diesem Fall wird absichtlich nichtexakt auf alle Methoden und Parameter dieses Layoutmanagers eingegan-gen, da dies den Rahmen dieser Einfuhrung bei weitem sprengen wurde(siehe auch Sun-Tutorial10).

1 import java . awt . ∗ ;2 import java . awt . event . ∗ ;3 import javax . swing . ∗ ;4

5 public class GridBagWindow extends JFrame6 {7 f inal boolean SHOULD FILL = true ;8 f inal boolean SHOULDWEIGHTX = true ;9

10 public GridBagWindow()11 {12 JButton button ;13 Container content pane = getContentPane ( ) ;14 GridBagLayout gb layout = new GridBagLayout ( ) ;15 GridBagConstraints gb constra ints = new GridBagConstraints ( ) ;16 content pane . setLayout ( gb layout ) ;17 i f (SHOULD FILL)18 {19 gb constra ints . f i l l = GridBagConstraints .HORIZONTAL;20 }21

22 button = new JButton (”Button 1” ) ;23 i f (SHOULDWEIGHTX)24 {25 gb constra ints . weightx = 0.5 ;26 }27 gb constra ints . gridx = 0;28 gb constra ints . gridy = 0;29 gb layout . setConstra ints ( button , gb constra ints ) ;30 content pane . add( button ) ;31

32 button = new JButton (”2” ) ;33 gb constra ints . gridx = 1;34 gb constra ints . gridy = 0;35 gb layout . setConstra ints ( button , gb constra ints ) ;

9http://java.sun.com/docs/books/tutorial//uiswing/layout/box.html10http://java.sun.com/docs/books/tutorial//uiswing/layout/gridbag.html

Page 85: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 80

36 content pane . add( button ) ;37

38 button = new JButton (”Button 3” ) ;39 gb constra ints . gridx = 2;40 gb constra ints . gridy = 0;41 gb layout . setConstra ints ( button , gb constra ints ) ;42 content pane . add( button ) ;43

44 button = new JButton (”Long−Named Button 4” ) ;45 gb constra ints . ipady = 40; //make th i s component t a l l46 gb constra ints . weightx = 0.0 ;47 gb constra ints . gridwidth = 3;48 gb constra ints . gridx = 0;49 gb constra ints . gridy = 1;50 gb layout . setConstra ints ( button , gb constra ints ) ;51 content pane . add( button ) ;52

53 button = new JButton (”Button 5” ) ;54 gb constra ints . ipady = 0; // re se t to de fau l t55 gb constra ints . weighty = 1 .0 ; // request any extra v e r t i c a l space56 gb constra ints . anchor = GridBagConstraints .SOUTH; //bottom of space57 gb constra ints . i n s e t s = new Inse t s (10 ,0 , 0 , 0 ) ; //top padding58 gb constra ints . gridx = 1; // al igned with button 259 gb constra ints . gridwidth = 2; // 2 columns wide60 gb constra ints . gridy = 2; // third row61 gb layout . setConstra ints ( button , gb constra ints ) ;62 content pane . add( button ) ;63

64 addWindowListener (new WindowAdapter ()65 {66 public void windowClosing (WindowEvent e )67 {68 System . ex i t ( 0 ) ;69 }70 } ) ;71 }72

73 public static void main( Str ing [ ] args )74 {75 GridBagWindow window = new GridBagWindow ( ) ;76

77 window . s e tT i t l e (”GridBagLayout” ) ;78 window . pack ( ) ;79 window . s e tV i s ib l e (true ) ;80 }81 }

Fortgeschrittene Programmierer haben auch die Moglichkeit, selbst einen Lay-outmanager zu schreiben. Will man in einem Programm die Elemente absolutpositionieren, dann muss man den Layoutmanager explizit auf null setzen unddie paint()-Methode von Pane uberschreiben. Die Absolutpositionierung hatviele Nachteile (z.B. hat die Anderung der Fenstergroße keine Auswirkung aufdas Layout...) und sollte nur in Ausnahmefallen verwendet werden.

6.5 Ein weiteres Beispiel

In den letzten Beispielen wurde nicht viel getan. Die Interaktion mit dem Be-nutzer hielt sich in Grenzen. Betrachten wir aus diesem Grund nun ein Beispiel,bei dem der Benutzer das Programm steuern kann.

1 import java . awt . ∗ ;2 import java . awt . event . ∗ ;3 import javax . swing . ∗ ;

Page 86: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 81

4

5 public class SimpleSwingApplication6 {7 static f inal String A LABEL PREFIX = ”Number of button c l i c k s : ” ;8 int num clicks = 0;9

10 public Component createComponents ()11 {12 f inal JLabel a l abe l = new JLabel (A LABEL PREFIX + ”0 ” ) ;13 JPanel a pane = new JPanel ( ) ;14

15 JButton a button = new JButton (” I ’m a Swing button ! ” ) ;16 a button . setMnemonic (KeyEvent .VK I ) ;17 a button . addActionListener (new ActionListener ()18 {19 public void actionPerformed (ActionEvent e )20 {21 num clicks ++;22 a labe l . setText (A LABEL PREFIX + num clicks ) ;23 }24 } ) ;25

26 a pane . setBorder (BorderFactory . createEmptyBorder (30 , 30 , 10 , 30 ) ) ;27 a pane . setLayout (new GridLayout ( 0 , 1 ) ) ;28 a pane . add( a button ) ;29 a pane . add( a l abe l ) ;30

31 return a pane ;32 }33

34 public static void main( Str ing [ ] args )35 {36 //Create the top−l e v e l container and add contents to i t .37 JFrame a frame = new JFrame(”SimpleSwingApplication” ) ;38 SimpleSwingApplication app = new SimpleSwingApplication ( ) ;39 Component contents = app . createComponents ( ) ;40 a frame . getContentPane ( ) . add( contents , BorderLayout .CENTER) ;41

42 a frame . setDefaultCloseOperation (JFrame .EXIT ON CLOSE) ;43 a frame . pack ( ) ;44 a frame . s e tV i s ib l e (true ) ;45 }46 }

Abbildung 6.4: SimpleSwingApplication in Aktion...

Nun einige Kommentare zum Programm: Wie man in der Abbildung sieht,wird ein Button erzeugt und dargestellt. Es wird weiters mitgezahlt, wie oft derButton gedruckt worden ist. Das Ergebnis wird in einem Label dargestellt.

main(...): In der main-Methode wird ein Frame erzeugt (Zeile 37) und dieKomponenten der Applikation (Button und Label) in die Mitte des Contai-ners positioniert (Zeile 39). Danach wird noch definiert, was passieren soll,wenn das Fenster geschlossen wird (setDefaultCloseOperation(...)),

Page 87: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 82

das Frame via pack() auf die Visualisierung vorbereitet und schließlichzum Zeichnen freigegeben (setVisible(...)). Danach wird das Fenstermit den Komponenten am Bildschirm von event-handle thread gezeich-net und auf Benutzereingaben gewartet.

createComponents(): Diese Methode erzeugt und retourniert die einzelneKomponenten der Applikation und platziert sie auf einem JPanel.

Das Label: Im Label unter dem Button wird angezeigt, wie oft dieser gedrucktwurde. Nachdem das Label auch in der anonymen Klasse (in Zeile 17-24)verwendet wird, muss es in Zeile 12 mit dem Modifier final deklariert wer-den. Macht man das nicht, kommt eine Fehlermeldung: “local variablelabel is accessed from within inner class; needs to be declaredfinal”. Die Leerzeichen hinter dem Label erzwingen ein breiteres Fra-me11.

Der Button: Der Button wird wie gewohnt via new JButton(...); erzeugt.Zeile 16 definiert den Shortcut fur den Button (Alt-i) bzw. Zeile 17assoziiert einen sog. ActionListener mit dem Button. Hier sehen wirdie Anwendung von Anonymen-Klassen. Diese spezielle Klasse – eine Im-plementation des ActionListener-Interfaces – wird nur in diesem Zu-sammenhang verwendet, daher ist dieser Ansatz hier vertretbar. DasActionListener-Interface verlangt, dass genau eine Methode implemen-tiert werden muss, namlich die Methode actionPerformed.

ActionListener: Der Listener beobachtet alle Actions, die der Button produ-zieren kann. Wird der Button via Shortcut aktiviert oder mit der lin-ken Maustaste gedruckt, wird die Methode actionPerformed(...) aus-gefuhrt. Uber den Methodenparameter e (dieser ist vom Typ ActionEvent)konnte man noch explizit abfragen von welchem Typ der Event ist. Mankonnte also unterschiedlich auf Events von Maus und Tastatur reagie-ren, was man aber hier im speziellen Fall nicht machen will. In deractionPerformed-Methode des Action-Listeners wird die Anzahl der Clickserhoht (Instanzvariable!) und das Label mit dem neuen Text versehen.Bitte beachte, dass Swing automatisch erkennt, dass das Label neu zuzeichen ist.

Dieses Beispiel zeigt, wie einfach es ist, Standardkomponenten (wie in diesemFall Button und Label) zu verwenden und auftretende Events zu behandeln.Von Komponenten konnen unterschiedliche Events “gefeuert” werden.

6.6 Event-Handling

Einzelne Komponenten und Gruppen von Komponenten konnen Events (also“Ereignisse”) erzeugen. In diesem Zusammenhang spricht man sehr haufig auchvon Events feuern. Damit diese Events nicht einfach im Nirgendwo verschwin-den, kann man sog. Event-Listener schreiben, die mit solchen Ereignissen um-gehen konnen. Ein Event-Listener muss zuerst bei der Komponente angemeldetwerden, damit er uber das Auftreten von Events benachrichtigt wird.

11Damit braucht man bei mehr als 9-clicks das Frame nicht zu vergroßern. Trickreich, oder?

Page 88: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 83

6.6.1 Event-Listener Interface und Adapter

Es gibt zwei Methoden, wie man Event-Listener implementieren kann: Entwederman implementiert ein bestimmtes Interface (...Listener.java) oder manleitet von einer bestimmten Klasse ab, die das Interface bereits implementierthat. Diese Klassen heißen Adapter-Klassen (...Adapter.java).

Listener deklarieren Methoden, die in den jeweiligen konkreten Auspragungenimplementiert werden mussen. Einfache Event-Listener mit wenigen Methodenkonnen auf diesen Weg sehr elegant umgesetzt werden. Es muss lediglich dasentsprechende Interface (richtig) implementiert werden.

Ein Event-Listener kann im Prinzip von jeder Klasse implementiert werden, esmuss lediglich ein entsprechendes Interface implementiert bzw. von einem be-stimmten Adapter abgeleitet werden. Abhangig vom implementierten Interfacewerden dem Listener unterschiedliche Events zugestellt und die entsprechendenEvent-Listener Methoden aufgerufen.

Bei komplizierteren Events arbeitet man besser mit den Adapter-Klassen. Adapter-Klassen bieten bereits Default-Implementationen der Methoden. Der konkreteListener wird einfach vom Adapter abgeleitet und die notwendigen Methodenwerden overrided.

Ob nun ein Listener-Interface implementiert, oder von einer Adapter-Klasseabgeleitet wird, ist dem Entwickler freigestellt. Wenn man z.B. einen Mouse-Listener betrachtet, sieht man sofort, dass man 5 Methoden implementierenmuss:

1 package java . awt . event ;2 . . .3 public interface MouseListener extends EventListener4 {5 /∗∗6 ∗ Invoked when the mouse button has been c l i cked ( pressed7 ∗ and re leased ) on a component .8 ∗/9 public void mouseClicked (MouseEvent e ) ;

10

11 /∗∗12 ∗ Invoked when a mouse button has been pressed on a component .13 ∗/14 public void mousePressed (MouseEvent e ) ;15

16 /∗∗17 ∗ Invoked when a mouse button has been re l eased on a component .18 ∗/19 public void mouseReleased (MouseEvent e ) ;20

21 /∗∗22 ∗ Invoked when the mouse enters a component .23 ∗/24 public void mouseEntered (MouseEvent e ) ;25

26 /∗∗27 ∗ Invoked when the mouse ex i t s a component .28 ∗/29 public void mouseExited (MouseEvent e ) ;30 }

Will man in einem Programm beispielsweise nur den mousePressed()-Eventbehandeln, muss man leere Implementationen fur die restlichen 4 Methodenzur Verfugung stellen. In einem solchen Fall sollte man den MouseAdapter

Page 89: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 84

verwenden und von diesem ableiten.

Nun noch zwei kurze Beispiele, die die Implementation des mouseClicked-Events mit Adapter-Klassen skizzieren. Im ersten Beispiel wird eine innerclass “MyAdapter” verwendet. Hier wird eine Instanz dieser Klasse dem Event-Listener (in diesem Fall ist es ein spezieller “Mouse-Event-Listener”) gegeben.Im zweiten Beispiel wird eine anonyme Klasse verwendet, die vom MouseAdapterabgeleitet ist und eine Methode (mouseClicked) overrided.

1 //An example of using an inner c l a s s .2 public class MyClass3 {4 . . .5 some object . addMouseListener (new MyAdapter ( ) ) ;6 . . .7 class MyAdapter extends MouseAdapter8 {9 public void mouseClicked (MouseEvent event )

10 {11 . . . //Event handler implementation goes here . . .12 }13 }14 }15

16 //An example of using an anonymous inner c l a s s .17 public class MyClass18 {19 . . .20 some object . addMouseListener (new MouseAdapter ()21 {22 public void mouseClicked (MouseEvent event )23 {24 . . . //Event handler implementation goes here . . .25 }26 } ) ;27 . . .28 }

Wie so oft bei der Entwicklung von Systemen gibt es hier kein Kochrezept, wiedie Events gefangen und behandelt werden mussen. Es bleibt dem Entwickleruberlassen, eine sinnvolle Implementation zu schreiben.

Vorsicht Falle: Fur die Implementation von Event-Listenern werden haufigAnonyme-Klassen verwendet. Vor allem fur großere Projekte kann es so sehrschnell unubersichtlich werden.

6.6.2 Event-Listener Methoden

Der Code, der ausgefuhrt werden soll, sobald ein passender Event eintritt (Event-Listener Methode), wird in einem einzigen Thread (event-dispatching thread)ausgefuhrt. Daher werden Events sequenziell abgearbeitet. Dieses Verhaltenmacht durchaus Sinn!

Nehmen wir einen Button als Beispiel: Ein Button wird vom Benutzer gedrucktoder nicht gedruckt. Die Aktion, die “hinter” diesem Button steckt soll demnachauch komplett ausgefuhrt werden, wenn er gedruckt wurde, oder nicht. EinButton kann nicht “halb gedruckt” werden...

Vorsicht Falle: Die Implementation einer Aktion sollte nicht zu umfangreich

Page 90: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 85

sein, da diese Aktionen nur in einem Thread abgearbeitet werden. Nachdemzusatzlich in diesem Thread (event-dispatching thread) auch noch die Kompo-nenten gezeichnet werden, kann bei langsamer Ausfuhrung der Bildschirm fureinige Zeit “einfrieren”. In diesem Fall sollte man die Aktion in einem separa-ten Thread ausfuhren und sich selbst um mogliche Synchronisationsproblemekummern!

Informationen zu einem Event (z.B. welches Objekt hat diesen Event ausgelost,wann wurde der Event gefeuert, etc.) werden vom System einer Event-ListenerMethode als Parameter ubergeben (z.B. MouseEvent fur Events, die von einerMaus ausgelost werden; diese Klasse ist – wie alle Event-Klassen – eine Sub-Klasse von EventObject). In EventObject gibt es die Methode getSource(),die die Quelle des Events retourniert. Da getSource() ein Objekt vom TypObject returniert, sollte man auf den expliziten Cast zum gewunschten Typnicht vergessen...

6.6.3 Kurzer Uberblick uber konkrete Events in Swing

Betrachtet man die Events, die innerhalb eines GUI-Systems auftreten konnen,bemerkt man schnell, dass es unterschiedliche Arten von Events gibt: sog. Low-Level- und Semantic-Events. In die erste Kategorie fallen alle Basis-Eventseines Fenstersystems (z.B. die Maus hat sich von x/y auf x1/y1 bewegt unddie Maustaste wurde dabei nicht gedruckt...), in die zweite Kategorie fallenEvents, die bereits eine konkrete Bedeutung haben (z.B. die linke-Maustastewurde auf einem Button gedruckt). Es ist offensichtlich, dass unterschiedlicheKomponenten, unterschiedliche semantische Events erzeugen konnen.

Es folgt nun ein kurzer Uberblick uber einige Event-Listener und -Adapter.Beginnen wir mit einer Liste von Listener, die von allen Swing-Komponentenverstanden werden:

ComponentListener/Adapter: Dieser Listener wird mitaddComponentListener(...) einer Komponente hinzugefugt. Methoden:

• void componentShown(ComponentEvent)

• void componentHidden(ComponentEvent)

• void componentMoved(ComponentEvent)

• void componentResized(ComponentEvent)

Der Parameter dieser Methoden ist vom Typ ComponentEvent, der eineMethode getComponent() zur Verfugung stellt (siehe auch Sun-Tutorial12).

FocusListener/Adapter: Mit addFocusListener(...) wird dieser Listenereiner Komponente hinzugefugt. Event wird gefeuert, wenn eine Kom-ponente den Fokus fur Keyboard-Input erlang bzw. verliert. Methoden:

• void focusGained(FocusEvent)

• void focusLost(FocusEvent)

12http://java.sun.com/docs/books/tutorial//uiswing/events/componentlistener.

html

Page 91: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 86

Der Parameter dieser zwei Methoden ist vom Typ FocusEvent. ViagetComponent() bekommt man wieder die Komponente, die diesen Eventverursacht hat (siehe auch Sun-Tutorial13).

KeyListener/Adapter: Wenn Tasten am Keyboard gedruckt werden, werdendiesem Listener Events zugestellt, wobei nur jene Komponente diese Eventsfeuert, die den aktuellen Keyboard-Fokus hat. Mit addKeyListener(...)kann dieser Event-Listener einer Komponente hinzugefugt werden.

• void keyTyped(KeyEvent)

• void keyPressed(KeyEvent)

• void keyReleased(KeyEvent)

Die wichtigsten Methoden von KeyEvent sind getKeyChar(), getKeyCode()bzw. getKeyText().

Key-Events sind – wie die folgenden Mouse-Events auch – von der KlasseInputEvent abgeleitet. Wenn man diese Events nicht an alle Komponen-ten weitergeben will, kann man sie auch “verbrauchen” (mit consume()).

Von InputEvent werden auch einige interessante Methoden geerbt(getComponent(), isAltDown(), isControlDown(), isMetaDown(),isShiftDown(), siehe auch Sun-Tutorial14).

MouseListener/Adapter: Kann via addMouseListener(...) einer Komponen-te hinzugefugt werden. Methoden:

• void mouseClicked(MouseEvent)

• void mousePressed(MouseEvent)

• void mouseReleased(MouseEvent)

• void mouseEntered(MouseEvent)

• void mouseExited(MouseEvent)

Die wichtigsten Methoden von MouseEvent sind getX(), getY(), getClickCount()und getButton().

1 import java . awt . ∗ ;2 import java . awt . event . ∗ ;3 import javax . swing . ∗ ;4

5 public class MouseEventDemo extends MouseAdapter6 {7 public void mousePressed (MouseEvent event )8 {9 System . out . pr int ln (”In mousePressed : ” ) ;

10 int modif iers = event . getModi f iers ( ) ;11

12 System . out . pr int ln (” Left button ” +13 ( ( ( modi f iers & InputEvent .BUTTON1MASK) != 0) ?14 ”” : ”not ”) + ”pressed” ) ;15 System . out . pr int ln (” Center button ” +16 ( ( ( modi f iers & InputEvent .BUTTON2MASK) != 0) ?17 ”” : ”not ”) + ”pressed” ) ;18 System . out . pr int ln (” Right button ” +

13http://java.sun.com/docs/books/tutorial//uiswing/events/focuslistener.html14http://java.sun.com/docs/books/tutorial//uiswing/events/keylistener.html

Page 92: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 87

19 ( ( ( modi f iers & InputEvent .BUTTON3MASK) != 0) ?20 ”” : ”not ”) + ”pressed” ) ;21 System . out . pr int ln (” Sh i f t i s ” +22 ( event . isShiftDown ( ) ? ”” : ”not ”) + ”pressed” ) ;23 System . out . pr int ln (” Control i s ” +24 ( event . isControlDown ( ) ? ”” : ”not ”) + ”pressed” ) ;25 System . out . pr int ln (” Alt i s ” +26 ( event . isAltDown ( ) ? ”” : ”not ” ) + ”pressed” ) ;27 }28

29 public static void main( Str ing [ ] args )30 {31 JFrame the frame = new JFrame(”MouseEventDemo” ) ;32 the frame . addMouseListener (new MouseEventDemo ( ) ) ;33 the frame . setDefaultCloseOperation (JFrame .EXIT ON CLOSE) ;34 the frame . se tS i ze (400 , 300) ;35 the frame . s e tV i s ib l e (true ) ;36 }37 }

siehe auch Sun-Tutorial15.

MouseMotionListener/Adapter: Kann via addMouseMotionListener(...) ei-ner Komponente hinzugefugt werden. Methoden:

• void mouseDragged(MouseEvent)

• void mouseMoved(MouseEvent)

1 import java . awt . ∗ ;2 import java . awt . event . ∗ ;3 import javax . swing . ∗ ;4

5 public class MouseMotionEventDemo implements MouseMotionListener6 {7 public void mouseMoved(MouseEvent event )8 {9 System . out . pr int ln (”In mouseMoved : ” +

10 event . getX() + ”/” + event . getY ( ) ) ;11 System . out . pr int ln ( event . getSource ( ) ) ;12 }13

14 public void mouseDragged(MouseEvent event )15 {16 System . out . pr int ln (”In mouseDragged : ” +17 event . getX() + ”/” + event . getY ( ) ) ;18 }19

20 public static void main( Str ing [ ] args )21 {22 JFrame the frame = new JFrame(”MouseMotionEventDemo” ) ;23 the frame . addMouseMotionListener (new MouseMotionEventDemo ( ) ) ;24 the frame . setDefaultCloseOperation (JFrame .EXIT ON CLOSE) ;25 the frame . se tS i ze (400 , 300) ;26 the frame . s e tV i s ib l e (true ) ;27 }28 }

(siehe auch Sun-Tutorial16).

15http://java.sun.com/docs/books/tutorial//uiswing/events/mouselistener.html16http://java.sun.com/docs/books/tutorial//uiswing/events/mousemotionlistener.

html

Page 93: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 88

JComponent unterstutzt noch weitere Typen von Listenern, die uns im Momentaber weniger interessieren. Alle oben angefuhrten Listener bzw. Adapter werdenvon allen Komponenten unterstutzt.

Speziellere, auf die Komponenten zugeschnittene Event-Listener sind in dernachsten Aufzahlung aufgelistet. Das werden jene Event-Listener sein, die inden meisten Applikationen direkt verwendet werden.

ActionListener: Benutzer druckt einen Button, auf eine Check-Box, Returnin einem Textfeld oder wahlt einen Menupunkt aus. Methode:

• void actionPerformed(ActionEvent e): Wird ausgefuhrt, sobaldein komponentenspezifischer, sinnvoller Event gefeuert wird. Im Fal-le eines Buttons ist es wichtig zu erfahren, ob er gedruckt wurde odernicht (und nicht ob jetzt die Maus gerade uber den Button lauft...)

Wichtige Methoden von ActionEvent sind getActionCommand() (retur-niert den mit setActionCommand(String) definierten Wert der Kompo-nente) bzw. getModifiers() (returniert den Integerwert von Steuerungs-tasten – ActionEvent.SHIFT_MASK, -.CTRL_MASK, -.META_MASK und -.ALT_MASK). (siehe auch Sun-Tutorial17).

WindowListener: Fenster wird vom Benutzer verandert. Methoden:

• void windowOpened(WindowEvent)

• void windowClosed(WindowEvent)

• void windowIconified(WindowEvent)

• void windowDeiconified(WindowEvent)

• void windowActivated(WindowEvent)

• void windowDeactivated(WindowEvent)

Die Methode getWindow() returniert von WindowEvent das Window-Objekt,welches den Event ausloste (siehe auch Sun-Tutorial18).

ChangeListener: Wenn sich der Status einer Komponente andert (z.B. einesButtons), wird dieser Listener verstandigt.

• void stateChanged(ChangeEvent)

Im ubergebenen ChangeEvent-Objekt gibt es nur die von EventObjectgeerbte Methode getSource() (siehe auch Sun-Tutorial19).

ItemListener: Fur alle Komponenten, die das ItemSelectable-Interface im-plementieren (Button, Check-Box, Combo-Box, Radio-Button...). DieseKomponenten verwalten einen Ein/Aus-Zustand von einem oder mehrerenKomponenten. Methode:

• void itemStateChanged(ItemEvent)

17http://java.sun.com/docs/books/tutorial//uiswing/events/actionlistener.html18http://java.sun.com/docs/books/tutorial//uiswing/events/windowlistener.html19http://java.sun.com/docs/books/tutorial//uiswing/events/changelistener.html

Page 94: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 89

ItemEvent bietet eine Methode getItem() an, bei der ein komponen-tenspezifischer Wert vom veranderten Objekt zuruckgegebn wird (meistein String). Die Methode getItemSelectable() retourniert die Kom-ponente, die den Event ausgelost hat, und mit getStateChange() fin-det man heraus, ob die Komponente selektiert oder deselektiert wurde(ItemEvent.SELECTED bzw. -.DESELECTED; siehe auch Sun-Tutorial20).

Es gibt fur spezielle Komponenten noch weitere Event-Handler-Typen (z.B.fur den JTree gibt es TreeSelectionListener, TreeWillExpandListener undTreeModelListener, fur den Fileselector gibt es wieder andere...). Da dieserAbschnitt nur einen Uberblick uber die Grundelemente von Swing-Komponentengeben soll, wird auf diese speziellen Konstrukte nicht eingegangen.

Wie schon bei den einzelnen Event-Handler Typen beschrieben, kann mit derMethode add[SomeTypeOfListener]Listener(...) einer Komponente ein Lis-tener zur Benachrichtigung eines bestimmten Events hinzugefugt werden. Durchmehrfachen Aufruf dieser Methode werden mehrere Listener registriert. Willman z.B. ein Objekt verstandigen, wenn ein Button mit der Maus gedrucktwird, schaut der Code wie folgt aus:

1 JButton the button = new JButton (”Some Buttonlabel” ) ;2 MouseListener t h e l i s t e n e r = new ClassImplementsMouseListener ( ) ;3 the button . addMouseListener ( t h e l i s t e n e r ) ;

Wird nun der Button gedruckt, wird das Objekt the_listener benachrichtigt.Diese Benachrichtigung erfolgt uber den Aufruf der implementierten Methode(in Fall des MouseListener’s ist das mouseClicked). Weiters gibt es noch Metho-den der Form get[SomeTypeOfListener]Listener() undremove[SomeTypeOfListener]Listener()21.

Mit diesen Grundlagen sollte es nun moglich sein, einfache, interaktive Swing-Applikationen zu entwerfen. Wir betrachten im Folgenden noch einige Spezia-litaten von Swing und beantworten einige Fragen.

6.7 Was passiert beim Zeichnen eines Fensters?

Komponenten in einem Container werden meist von einem Layoutmanager ge-zeichnet. Container haben einen Default-Layoutmanager (z.B. JFrame verwen-det den BorderLayout-Manager). Normalerweise braucht man sich nicht darumkummern, wie und wann welche Elemente gezeichnet werden. Treten jedoch beider Visualisierung Probleme auf, ist es durchaus sinnvoll, wenn man den Vor-gang versteht.

Nachdem in einen Container Komponenten positioniert wurden, sollte mittelspack() der Container zur Visualisierung vorbereitet werden (es wird z.B. dieGroße festgelegt). Mit setVisible(true) wird dann der Container auch sicht-bar gemacht und gezeichnet.

Komponenten zeichnen sich selbst neu, wenn:

• Das Fenster neu aufgebaut wird in dem sie gespeichert sind.20http://java.sun.com/docs/books/tutorial//uiswing/events/itemlistener.html21Beim Button kann man auch einen ActionListener implementieren...

Page 95: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 90

• Die Fenstergroße verandert wird.

• Teile des Fensters in den Vordergrund gebracht werden.

• Sich der Programmstatus andert.

Wobei nur jene Bereiche neu gezeichnet werden, die von der Anderung betroffensind. Beispiel: Nimmt man einen Button, der ein bestimmtes Label hat, undverandert man dann dieses Label, so wird nur dieser Button neu gezeichnet,und alle in der Umgebung liegenden Komponenten (die ja von dieser Anderungnicht betroffen sind) werden nicht neu gezeichnet.

Elemente unter einer durchsichtigen Komponente werden auch neu gezeichnet,d.h. die Komponenten des Bereichs, der neu gezeichnet werden muss, werdenvon unten nach oben neu gezeichnet. Werden Komponenten explizit als nichtdurchsichtig markiert (setOpaque(true)), werden alle darunterliegenden Kom-ponenten in dem Bereich nicht neu gezeichnet.

Werden die Komponenten entgegen aller Norm nicht neu gezeichnet, kann mandie Methode repaint() der Komponente explizit aufrufen. Andert sich dieGroße oder Position einer Komponente, sollte man vor repaint() nochrevalidate() aufrufen.

Das Zeichnen passiert – wie das Abarbeiten eines Events – innerhalb eines be-stimmten Threads (und wieder ist es der event-dispatching thread , zu Threadssiehe bitte spater), d.h., wahrend etwas am Bildschirm gezeichnet wird, werdenkeine Events abgearbeitet und umgekehrt. Der Zeichenvorgang einer Kompo-nente wird jeweils komplett abgeschlossen (halb gezeichnete Komponenten – z.B.ein halb-gedruckter und halb-nichtgedruckter Knopf – machen keinen Sinn...).

Swing verwendet einen sog. double-buffer -Mechanismus, bei dem die Kompo-nenten zuerst versteckt gezeichnet werden und erst danach der Inhalt des fertiggezeichneten Puffers in den sichtbaren Bereich kopiert wird.

6.8 Swing-Komponenten

Nun noch eine kurze Zusammenstellung der Komponenten, die in Swing zurVerfugung gestellt werden. Ein interessanterer (visueller) Index ist in Sun-Tutorial22 zusammengestellt.

6.8.1 Top-Level Container

Eine Applikation benotigt mindestens einen Top-Level Container, in dem wei-tere Komponenten plaziert werden konnen.

JFrame: Viele Beispiele, die in diesem Abschnitt vorgestellt wurden, verwendenFrames, daher kommt hier nur ein ganz, ganz kurzes Beispiel, wie einFrame erzeugt wird:

22http://java.sun.com/docs/books/tutorial//uiswing/components/components.html

Page 96: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 91

1 import javax . swing . ∗ ;2 import java . awt . ∗ ;3

4 public class SimpleJFrame5 {6 public static void main( Str ing [ ] args )7 {8 JFrame the frame = new JFrame(”Some Tit l e of the Frame” ) ;9

10 JLabel the l abe l = new JLabel (”Some labe l ” ) ;11 the frame . getContentPane ( ) . add( the labe l , BorderLayout .CENTER) ;12

13 the frame . pack ( ) ;14 the frame . s e tV i s ib l e (true ) ;15 }16 }

JDialog: Einige Klassen stellen Dialoge zur Verfugung. JOptionPane kannunterschiedliche Arten von Dialogen uber einfache, statische Methodenerzeugen. Ein Dialog kann auch modal sein, d.h. er blockiert samtlicheEingaben des Benutzers fur darunter liegende Fenster. Im folgenden sindnur zwei einfache Aufrufe skizziert. Weitere Infos sind in Sun-Tutorial23

zu finden.

JOptionPane.showMessageDialog(the frame, message,...): Diese Me-thode offnet in einem Frame einen Message-Dialog, der uber einenOk-Button verfugt. Weitere Parameter beeinflussen den Titel desDialogs bzw. das Icon.

JOptionPane.showOptionDialog(the frame, message, ...): Hier kannvom Benutzer eine Auswahl getroffen werden. Eine typische Anwen-dungen fur diesen Dialog sind Ja/Nein/Abbruch-Dialoge. Z.B.:

1 Object [ ] options = {”Yes” , ”No” , ”Cancel”} ;2

3 int answer = JOptionPane . showOptionDialog ( the frame , // the frame4 ”Continue the program?” , // the message5 ”” , // t i t l e of dialg−frame6 JOptionPane .YES NO CANCEL OPTION, // option type7 JOptionPane .QUESTION MESSAGE, // type of dialog , s e l e c t s de fau l t icon8 null , // custom icon9 options , // which options

10 options [ 0 ] ) ; // de fau l t s e l e c ted option

In answer steht nach der Auswahl des Benutzers JOptionPane.YES_OPTION,-.NO_OPTION oder -.CANCEL_OPTION und das Programm kann ent-sprechend darauf reagieren.

...:

JApplet:

6.8.2 Allgemeine Container

Diese Art der Container werden meist zur Gruppierung von Komponenten ver-wendet (siehe auch Sun-Tutorial24).

23http://java.sun.com/docs/books/tutorial//uiswing/components/dialog.html24http://java.sun.com/docs/books/tutorial//uiswing/components/intermediate.html

Page 97: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 92

JPanel:

JScrollPane:

JSplitPane:

JTabbedPane:

JToolBar:

JInternalFrame:

JLayeredPane:

JRootPane:

6.8.3 Kontroll Komponenten

Mit diesen Komponenten erfolgt eine Steuerung vom Programm (siehe auchSun-Tutorial25). Die Komponenten konnen auch deaktiviert werden.

JButton:

JCheckBox:

JRadioBotton:

JComboBox:

JList:

JMenu:

JSlider:

6.8.4 Info Komponenten

Diese Komponenten werden zur Visualisierung von Werten (Informationsdar-stellung) verwendet.

JLabel:

JProgressBar:

JToolTip:

25http://java.sun.com/docs/books/tutorial//uiswing/components/widgets.html

Page 98: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 6. SWING 93

6.8.5 Spezielle Komponenten

JColorChooser:

JFileChooser:

JTable:

text.JTextComponent: • JEditorPane

• JTextArea

• JTextField

JTree:

Page 99: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Kapitel 7

Threads

In Java ist es recht einfach, mehrere Arbeiten gleichzeitig von einem Programmerledigen zu lassen. In diesem Abschnitt betrachten wir das Konzept vonThreads1 in Java und zeigen die Probleme und Stolpersteine.

In einer Applikation konnen viele, aber sinnvollerweise nicht beliebig viele Threadsverwendet werden. Threads lassen sich in sog. thread-groups und in thread-poolszusammenfassen. Da diese Konzepte bei weitem den Rahmen dieser Unter-lagen sprengen wurden, sei nur auf die Limitierung hingewiesen. Wie dieseProbleme zu losen sind, wird nicht diskutiert. Wer sich intensiv mit Thread-Programmierung in Java befasst, kommt nicht um [Oaks and Wong, 1999] her-um. Viel Erfahrung ist notwendig, um vernunftige Programme schreiben zukonnen.

7.1 Motivation

Wir haben schon beim Kapitel uber Swing gehort, dass Event-Handling Routi-nen kurz sein sollen bzw. schnell abgearbeitet werden mussen, da diese im sel-ben Thread ausgefuhrt werden, wie die Zeichenroutinen fur die Komponenten.Betrachten wir folgenden Codeausschnitt eines Action-Listeners (Die MethodesimulateTask() benotigt in unserem Beispiel 5 Sekunden zur Ausfuhrung):16 menu item . addActionListener (new ActionListener ()17 {18 public void actionPerformed (ActionEvent event )19 {20 simulateTask ( ) ;21 }22 } ) ;

Wird nun der Menupunkt ’Excecute ->Some Task’ ausgewahlt, wird die Metho-de simulateTask() ausgefuhrt und samtliche anderen notwendigen Operatio-nen wie z.B. das Verarbeiten weiterer Swing-Events) konnen nicht abgearbeitetwerden. Der Benutzer hat zu Recht das Gefuhl, dass die Applikation langsam

1Thread: 1. Prozess, der innerhalb eines Programms selbststandig ausgefuhrt werden kann,aber nicht unabhangig von ihm (z.B. die Silbentrennung einer Textverarbeitung). HeutigeProzessoren konnen mehrere Threads parallel ausfuhren. 2. Gruppe von News in einer News-group, die zusammengehoren. Brockhaus

94

Page 100: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 95

ist oder mit dem Rechner etwas nicht stimmt. Dieses Verhalten ist naturlichabsolut unpassend fur interaktive Applikationen.

Um das Verhalten der Applikation zu verbessern, muss man die MethodesimulateTask() in einem separaten Thread ablaufen lassen. Dieser Ansatzwurde die weitere Abarbeitung der Applikation nicht behindern (es passiertja zugegebenermaßen nicht sehr viel im Action-Listener) Schauen wir uns derVollstandigkeit halber noch die notwendigen Anderungen an (die im Folgendenausfuhrlicher diskutiert werden):18 menu item . addActionListener (new ActionListener ()19 {20 public void actionPerformed (ActionEvent event )21 {22 Thread act ion thread = new Thread(new Runnable ()23 {24 public void run ()25 {26 simulateTask(++num thread ) ;27 }28 } ) ;29 act ion thread . s ta r t ( ) ;30 }31 } ) ;

Wenn man diese Programme vergleicht, so werden potentielle Benutzer das zwei-te Programm bei weitem besser akzeptieren als das erste. Genug Motivationalso, sich mit threading etwas genauer auseinander zu setzen...

Wenn ein Computer nur eine Recheneinheit (=CPU) hat, kann selbstverstand-lich nur ein Programm zu einem Zeitpunkt ausgefuhrt werden. Um hier dasGefuhl zu vermitteln, dass mehrere Programme “gleichzeitig” ausgefuhrt wer-den, arbeitet das Betriebssystem mit einige Tricks (Diese Ausfuhrungen sindsehr, sehr einfach gestaltet und sollen nur einen Uberblick geben, wie solcheSysteme arbeiten. Ein besserer und ausfuhrlicherer Einblick wird in Buchern zuBetriebssystemen gegeben, siehe z.B. [Silberschatz and Galvin, 1998]).

Das Betriebssystem fuhrt eine Liste von Programmen (Prozessen), die aus-gefuhrt werden sollen. Je nach Verfahren wird nun ein Programm, das aus-gefuhrt werden soll, hergenommen und z.B. fur einen bestimmten Zeitraum ver-arbeitet. Nach diesem Zeitraum wird der Status der CPU und der verwendetenSpeicherbereiche zwischengespeichert und das nachste Programm ausgewahltund ausgefuhrt. Welche Programme nun wann fur wie lange ausgefuhrt werdensollen, ist abhangig von den verwendeten Algorithmen und Strategien. Dasshier Probleme auftreten konnen, liegt auf der Hand (einzelne Programme be-kommen vielleicht nie Rechenzeit zugeteilt und vieles andere mehr). Einige –aber sicher nicht alle – Probleme werden wir hier besprechen.

In Java ist hier die Situation ahnlich: Threads bekommen Prioritaten (zwischenThread.MIN PRIORITY und Thread.MAX PRIORITY). Sind Threads im runnable-Zustand (d.h. die Thread-Objekte sind instantiiert und gestartet) konnen sieausgefuhrt werden. Threads mit hoherer Prioritat haben bei der AusfuhrungVorrang. Der aktuell laufende Thread wird gestoppt, wenn:

1. Ein Thread mit einer hoheren Prioritat in den runnable-Zustand kommt.

2. Der Thread freiwillig zum Arbeiten aufhort (sleep, yield), auf eine be-stimmte Bedingung wartet (wait) bzw. auf Ein-/Ausgabe wartet.

Page 101: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 96

3. Bei Betriebssystemen, die das Zeitscheibenverfahren unterstutzen: Wennder zugeteilte Zeitschlitz aufgebraucht ist.

Stehen mehrere CPUs zur Verfugung, werden die Prozesse bzw. Threads aufdie zur Verfugung stehenden CPUs aufgeteilt. Diesen Vorgang der Auswahlvon Threads auf die CPU nennt man Scheduling (“Ablaufplanung”). Die JVMimplementiert das Scheduling preemptive, d.h. sobald ein hoher priorisierterThread als der aktuell laufende im System angemeldet wird, wird der laufendeThread unterbrochen.

Vorsicht Falle: Prioritatenbasiertes Scheduling ist die Theorie :) Man solltesich aber auf keinen Fall darauf verlassen, dass Threads in einer bestimmtenReihenfolge abgearbeitet werden! Es kann auch passieren, dass ein Threadmit niederer Prioritat ausgefuhrt wird, um sog. starvation (“verhungern”) desThreads zu verhindern.

7.2 Threads in Java

In Java gibt es zwei Moglichkeiten, Anweisungen in Threads abarbeiten zu las-sen, namlich durch:

• Ableiten einer Klasse von java.lang.Thread bzw. durch

• Implementieren vom java.lang.Runnable-Interface.

Es ist wieder abhangig von der Klassenhierarchie, wie man bei einem gegebenenProblem vorgeht. Man ist aber auf alle Falle flexibler, wenn man das Runnable-Interface implementiert, da man unabhangig von einer vorhandenen Elternklas-se Nebenlaufigkeit (=gleichzeitige Abarbeitung) erzielen kann2. Im folgendenBeispiel sieht man, wie diese zwei Typen von Threads gestartet werden konnen.

1 class AThread extends Thread2 {3 public void run ()4 {5 for ( int i =0; i <500; i++)6 {7 System . out . pr int (” −− An extended Thread −− ” ) ;8 }9 }

10 }11

12 class ARunnable implements Runnable13 {14 public void run ()15 {16 for ( int i =0; i <500; i++)17 {18 System . out . pr int (” −− An implemented Runnable −− ” ) ;19 }20 }21 }22

23 public class SimpleThreadExample

2In Java gibt’s ja nur eine einfache Ableitung...

Page 102: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 97

24 {25 public static void main( Str ing [ ] args )26 {27 AThread some thread = new AThread ( ) ;28 some thread . s ta r t ( ) ;29

30 ARunnable some runnable = new ARunnable ( ) ;31 new Thread( some runnable ) . s ta r t ( ) ;32 }33 }

Verwendet man die erste Methode (Ableitung von java.lang.Thread), mussman ein Objekt dieser Klasse erzeugen und die start()-Methode aufrufen (sieheZeile 27-28). Es wird dann implizit ein Thread gestartet und die Methode run()ausgefuhrt.

Bei der zweiten Art (Implementation von java.lang.Runnable) muss man zu-erst ein Objekt vom Typ “Runnable” erzeugen, und dieses Objekt dann demThread-Konstruktor als Parameter ubergeben. Im gleichen Schritt kann manauch die start()-Methode aufrufen.

Man hat die Moglichkeit Threads mit Namen zu versehen. Tut man das nicht,wird automatisch ein Name vom System vergeben. Via setName(String) kannman auch nachtraglich einem Thread einen Namen zuweisen. Der Name mussnicht eindeutig im System sein, d.h. es konnen mehrere Threads ein und den-selben Namen haben3.

Ein gestartet Thread wird so lange ausgefuhrt, bis die run()-Methode verlassenoder eine Exception innerhalb von run() nicht behandelt wird.

In Java wird zwischen zwei Arten von Threads unterschieden:

User-Threads erledigen Aufgaben, die essentiell fur die Applikation sind. EineApplikation lauft so lange, bis alle User-Threads beendet sind. Beim Star-ten einer Applikation gibt es genau einen User-Thread, der die main()-Methode der zu startenden Klasse aufruft.

Daemon-Threads erledigen nicht so wichtige Aufgaben (z.B. garbage collecti-on) die aber notwendig fur den Gesamtablauf der Applikation sind. EineApplikation wird beendet, sobald nur mehr Daemon-Threads in der App-liation laufen. Uber die Methode setDeamon(true) kann ein Thread alsDaemon-Thread markiert werden, bevor er gestartet wurde4.

Threads teilen sich Ressourcen. Sie besitzen zwar einen “eigenen” Stack und“eigene” lokale Variablen, teilen sich aber Instanz-Variablen. Das bei diesem“Ressource-Sharing” einiges daneben gehen kann ist offensichtlich. Betrachtenwir folgendes Beispiel:

1 public class BadRunnable implements Runnable2 {3 int shared int = 0;4

5 public void run ()

3Nachdem es eine setName(String)-Methode gibt, ist es fur den versierten Programmiereroffensichtlich, dass auch eine getName()-Methode existieren muss...

4Wenn der Thread bereits gestartet wurde, wird eine IllegalThreadStateException aus-gelost.

Page 103: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 98

6 {7 shared int ++;8 System . out . pr int ln (Thread . currentThread ( ) . getName() +9 ” : Value i s now : ” + shared int ) ;

10 }11

12 public static void main( Str ing [ ] args )13 {14 BadRunnable bad runnable = new BadRunnable ( ) ;15 Thread thread 1 = new Thread( bad runnable ) ;16 Thread thread 2 = new Thread( bad runnable ) ;17 thread 1 . s ta r t ( ) ;18 thread 2 . s ta r t ( ) ;19 }20 }

Die zwei Threads (thread 1 und thread 2) teilen sich die Variable shared int .Es ist sehr wahrscheinlich, dass auf der Konsole

Thread-1: Value is now: 1Thread-2: Value is now: 2

zu lesen ist. Ebenso ist es wahrscheinlich, dass

Thread-2: Value is now: 1Thread-1: Value is now: 2

oder

Thread-1: Value is now: 2Thread-2: Value is now: 2

auf der Konsole erscheinen. Je nachdem, welcher Thread vorher am Zug ist, istalso das Verhalten der Applikation unterschiedlich.

Wenn Blocke in Threads atomar sein sollen (thread save), so mussen die An-weisungen speziell gekennzeichnet werden. Hierfur wurde das Schlusselwortsynchronized eingefuhrt.

Jede Instanz einer Klasse (i.e. jedes Objekt) besitzt genau einen “Lock”. Willein Thread in einem Objekt einen synchronized-Block abarbeiten, muss er die-sen “Lock” anfordern. Erst wenn der Thread in Besitz dieses “Locks” ist, darf erden Block abarbeiten. Am Ende des synchronisierten Blocks wird der Lock demObjekt wieder zuruckgegeben. Es ergibt sich daraus, dass wahrend ein synchro-nisierter Block mit einem Objekt ausgefuhrt wird, kein anderer synchronisierterBlock mit diesem Objekt ausgefuhrt werden kann.

Man kann ganze Methoden mit synchronized markieren oder aber wirklich nurdie kritischen Bereiche, bei denen Probleme auftreten konnen, wenn zwei odermehrere Threads auf ein und dieselbe Variable zugreifen.

Jedes Objekt hat einen sog. Monitor (oder “lock”). Will ein Thread A in einensynchronized-Block, so muss er den Monitor des Objekts (auf das synchroni-siert wurde) besitzen. Besitzt ein anderer Thread B den Monitor des Objekts,so muss der Thread A so lange warten, bis Thread B den Monitor wieder freigibt(d.h., dass Thread B den synchronized-Block wieder verlassen muss). Es kannnur auf Objekte, und nicht auf Primare-Datentypen synchronisiert werden.

Page 104: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 99

Generell sollte man bedenken, dass geschachtelte synchronized-Blocke erheb-liche Probleme bringen konnen und sog. Deadlocks5 auftreten konnen und lt.Murphy auftreten werden. Als Richtlinie sollte man niemals Methoden inner-halb von synchronisierten Methoden oder Blocken aufrufen (und wenn man dastut, sollte man genau wissen, was passiert...). Ein einfaches und sehr offensicht-liches Beispiel ist in Abschnitt 7.5 zu finden.

synchronized methods: Bei den Methoden haben wir bereits das Schlussel-wort synchronized kennengelernt: Solche Methoden durfen nur von ei-nem Thread zu einem Zeitpunkt mit einem Objekt verwendet werden. Eswird das gesamte Objekt fur den weiteren Zugriff gesperrt, bis die syn-chronisierte Methode wieder verlassen wird!

1 public synchronized void put (Object the object )2 {3 . . .4 }

Wird diese Methode von einem Thread mit einem Objekt A ausgefuhrt,wird verhindert, dass ein anderer Thread ebenso diese Methode mit demObjekt A ausfuhrt.

synchronized blocks: Es ist auch moglich auf bestimmte Objekte zu synchro-nisieren.

1 // . . . some code . . .2 synchronized ( the object )3 {4 . . .5 }

Soweit allgemeine Erlauterungen zum Konzept der Threads in Java. Im Fol-genden werden wir untersuchen, wie der Lebenszyklus eines Threads ausschaut,wie die wichtigsten Methoden der Klasse Thread heißen und wie diese arbeiten,sowie welche Stolpersteine bei der Programmierung mit Threads zu beachtensind.

7.3 Lebenszyklus eines Threads

Bei der Verwendung von Threads sollte klar sein, dass diese schwerer zu debug-gen sind als herkommliche Programme. Wenn man also nicht genau weiß, wasinnerhalb eines Threads passiert und welche Variablen von unterschiedlichenThreads geteilt werden, sind hier enorme Probleme zu erwarten. Ein ungeubterEntwickler sollte sich also bewusst sein, was er alles anrichten kann... EinigeStolpersteine sind in Abschnitt 7.5 aufgelistet.

Um einen Thread zu starten, brauchen wir – wenig uberraschend – zuerst ein Ob-jekt vom Typ Thread. Dieser Thread kann dann mit der start()-Methode ge-startet werden. Bei start() werden dem Thread System-Ressourcen (Speicher,Rechenzeit etc.) zur Verfugung gestellt und der Code in der run()-Methodeausgefuhrt (Status des Threads ist “running”).

5“Nichts geht mehr”, weil z.B. ein Thread A auf die Freigaben von einem Objekt B wartet,welches von Thread B bereits synchronisiert wurde. Thread B wartet aber auf die Freigabevon Objekt A, welches bereits in Thread A synchronisiert wurde...

Page 105: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 100

Abbildung 7.1: Lebenszyklus eines Threads

Vorsicht Falle: Wie wir bereits gesehen haben, ist es extrem leicht, Threadszu erzeugen. Bevor man aber mit Threads arbeitet, sollte man sich bewusstsein, dass das Erzeugen und Starten von Threads eine “teure” Angelegenheit ist(abhangig vom Betriebssystem). Es ist also anzuraten, sich genau zu uberlegen,ob ein Thread wirklich erzeugt werden muss (Losung: thread-pooling).

Der Status eines Threads kann in den ’Not Running’-Status ubergehen, wenn:

• Die sleep(mill_sec)-Methode aufgerufen wird. Es wird also “freiwillig”fur eine bestimmte Zeit auf die Ausfuhrung verzichtet.

• Explizit auf eine bestimmte Bedingung gewartet wird (wait()).

• Auf Ein/Ausgabe gewartet wird.

• Freiwillig auf die Ausfuhrung des eigenen Threads verzichtet wird (yield()).Das passiert nur, wenn ein Thread mit gleicher Prioritat im Runnable-Status ist.

Der Status andert sich von “Not Runnable” wieder auf “Runnable”, wenn:

• Die mill_sec von sleep vergangen sind.

• Via notify() bzw. notifyAll() benachrichtigt wird.

• Die Ein-/Ausgabe abgeschlossen ist.

Schlussendlich muss ein Thread einmal beendet werden. Das passiert, wenn dierun()-Methode verlassen wird. Die stop()-Methode darf nicht mehr verwendetwerden (stop() ist deprecated!)! Der ubliche Ansatz ist, dass man in derrun()-Methode eine while-Schleife verwendet (z.B. while (should run ) ...)und die Schleifen-Bedingung andert, sobald man den Thread beenden will (indiesem Fall also should run = false;). should run muss als Instanzvariableausgefuhrt werden, damit andere Methoden der Klasse den Wert andern konnen.

7.4 Einige Methoden in Thread

Wir haben nun schon einige Methoden der Thread-Klasse kennen gelernt. Indiesem kurzen Abschnitt wird eine Auflistung der Methoden nach Kategorienund Aufgaben gegeben.

Page 106: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 101

Ausfuhrung fur eine bestimmte Zeit deaktivieren (sleep): Sollen von ei-nem Thread immer wiederkehrende Aufgaben gelost werden (z.B. zeichneneiner Animation oder crond-ahnliche Aufgaben), so kann der Thread fureine bestimmte Zeit deaktiviert werden. Das Versetzen in den schlafen-den Zustand erfolgt uber die statische Methode sleep(mill_sec). Z.B.Thread.sleep(1000): der aktuell laufende Thread (current thread) wirdhier fur 1000msec. in den “Not Runnable”-Zustand versetzt. Wahrenddieser Unterbrechung werden die gesperrten Objekte nicht freigegeben.

Ausfuhrung deaktivieren, bis eine Bedingung zutrifft (wait): Es kannpassieren, dass man auf bestimmte Ereignisse warten muss, bis eine Auf-gabe fortgesetzt werden kann. Will man z.B. unter anderem eine Listein Thread A sortieren, so sollte diese zuvor vollstandig mit den zu sor-tierenden Elementen gefullt sein. Ubernimmt diese Aufgabe Thread B,so darf Thread A erst dann weitergefuhrt werden, wenn Thread B sei-ne Aufgabe erledigt hat. Fur diese Art der Kommunikation stehen beiallen Objekten die Methoden wait() und notify() zur Verfuhung (istin java.lang.Object definiert). In Thread A muss daher in etwa derfolgende Code stehen:

while list_object is not readywait for list_object

Und in Thread B sollte, sobald sich das Listen-Objekt in einem richtigenZustand befindet, etwa folgender Code stehen:

notify list_object

Dadurch wird der Thread, der auf das list_object wartet, benachrich-tigt, und die Ausfuhrung kann fortgesetzt werden.

Ausfuhrung kurzfristig unterbrechen (yield): Ein Thread kann freiwilligseine Ausfuhrung unterbrechen und auch anderen Threads die Moglichkeitzur Ausfuhrung geben (yield())

Namen von Threads: Fur Debugging-Zwecke ist es sinnvoll, Threads mitNamen zu versehen (setName(the name)). Man kann dann einfach viagetName() auf den Namen zugreifen.

Thread beendet? Will man herausfinden, ob ein Thread noch am Leben istund Operationen ausfuhrt, kann man die Methode isAlive() des Threadsverwenden. Diese gibt true zuruck, wenn der Thread gestartet, aber nochnicht beendet wurde. Eine weitere Moglichkeit ist die Verwendung vonjoin(). Die Methode join() eines Threads blockiert so lange, bis derThread nicht mehr “am Leben” ist. Will man maximal eine bestimmteZeit warten, bis der Thread beendet wird, kann man noch mit join(longtimeout) die maximale Wartezeit bekanntgeben. join kann daher alseine Kombination von sleep() und isAlive() angesehen werden.

Page 107: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 102

Vorsicht Falle: Es macht naturlich keine Sinn, diese Methoden (isAliveund join) auf den eigenen Thread aufzurufen. isAlive sollte ja immertrue zuruckliefern, wenn der Thread gerade lauft, und das wird er wohl,wenn man selbst danach fragen kann... Ein join auf “sich selbst” wirdwohl nie returnieren.

Prioritaten: Es ist moglich, Threads mit unterschiedlichen Prioritaten zu ver-sehen. Threads mit einer hohen Prioritat bekommen mehr Zeit fur dieAusfuhrung als jene mit einer niederen Prioritat. Mit den MethodensetPriority(...) bzw. int getPriority() kann der entsprechende Pa-rameter fur den jeweiligen Thread gesetzt bzw. gelesen werden.

1 /∗∗2 ∗ The minimum pr i o r i t y that a thread can have .3 ∗/4 public f inal static int MIN PRIORITY = 1;5

6 /∗∗7 ∗ The defau l t p r i o r i t y that i s assigned to a thread .8 ∗/9 public f inal static int NORM PRIORITY = 5;

10

11 /∗∗12 ∗ The maximum pr i o r i t y that a thread can have .13 ∗/14 public f inal static int MAX PRIORITY = 10;

Wird ein Thread erzeugt, bekommt er die selbe Prioritat wie der Thread,der ihn erzeugt hat.

Gruppen von Threads: Es ist moglich, Gruppen von Threads zur besserenVerwaltung zusammenzufassen. Hier muss bei der Erzeugung des Threadsbereits die Gruppe (ThreadGroup) angegeben werden. Wird keine Gruppeangegeben, so wird der Thread einer Default-Gruppe zugeordnet.

Wieviele Threads? Man kann herausfinden, wieviele Threads in einer be-stimmten Gruppe laufen (activeCount).

Hat dieser Thread den Monitor vom Objekt (holdsLock)? Mitsyncronized(the_object) kann man verhindern, dass zwei Threads gleich-zeitig auf ein Objekt zugreifen. Um zu uberprufen, ob ein Objekt von ei-nem Thread gesperrt wird, gibt es die statische Thread-MethodeholdsLock(the_object), die herausfindet, ob der aktuelle Thread dasObjekt sperrt.

Es gibt noch einige Methoden mehr, die allerdings in diesen Unterlagen nichtbehandelt werden. Hier soll lediglich die Idee der Threads verbreitet werden.Wie die optimale (“systemschonende”) Umsetzung ausschaut, kann nicht sooooschnell mitgeteilt werden. Hier benotigt man einiges an Programmierpraxis undErfahrung...

7.5 Stolpersteine

Einige Methoden in der Thread-Klasse sind “gefahrlich” und sollten aus diesemGrund nicht verwendet werden.

Page 108: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 103

Vorsicht Falle: Es gibt in der Thread-Klasse einige sog. deprecated Metho-den6, die nicht mehr verwendet werden sollen und fruher oder spater aus derSprache herausgenommen werden. Diese Methoden bringen Probleme mit sichund konnen soweit fuhren, dass das Programm nicht mehr so funktioniert, wiees sich der Entwickler denkt. Deprecated Methoden sind als solche in der Doku-mentation markiert. Im Zusammenhang mit Threads sind folgende Methodendeprecated: stop(), suspend() und resume().

Sobald zwei Dinge auf einmal von einem Programm erledigt werden konnen,sind Probleme vorprogrammiert. So kann es einfach passieren, dass sich zweiThreads Variablen teilen, die von beiden Threads zur gleichen Zeit verandertwerden. Dass hier dann nur mehr Schwachsinn herauskommt, liegt auf derHand...

Vorsicht Falle: Wenn Variablen von mehreren Threads gleichzeitig verandertwerden konnen, muss das verhindert werden! Gleichzeitiger, ausschließlich le-sender Zugriff ist selbstverstandlich kein Problem!

Wie schon angekundigt, ist es sehr wahrscheinlich, dass Deadlocks auftreten,wenn sich Threads gegenseitig Ressourcen reservieren. Ein einfaches Beispielsoll das Wiedergeben.

1 public class DeadLockExample extends Thread2 {3 protected static Object a shared object = new Object ( ) ;4 protected static Object another shared object = new Object ( ) ;5

6 f inal protected static String FIRST THREAD NAME = ” the f i r s t th r ead ” ;7 f inal protected static String SECONDTHREADNAME = ”the second thread” ;8

9 public DeadLockExample( Str ing name)10 {11 super(name ) ;12 }13

14 public void run ()15 {16 while ( true )17 {18 i f ( this . getName ( ) . equals (FIRST THREAD NAME))19 {20 synchronized ( a shared object )21 {22 System . out . pr int ln ( this . getName() +23 ” : jus t locked a shared object . . . ” ) ;24 synchronized ( another shared object )25 {26 System . out . pr int ln ( this . getName() +27 ” : jus t locked another shared object . . . ” ) ;28 }29 System . out . pr int ln ( this . getName() +30 ” : jus t unlocked another shared object . . . ” ) ;31 }32 System . out . pr int ln ( this . getName() +33 ” : jus t unlocked a shared object . . . ” ) ;34 }35 else36 {37 synchronized ( another shared object )

6to deprecate: missbilligen, verurteilen, verwerfen

Page 109: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 104

38 {39 System . out . pr int ln ( this . getName() +40 ” : jus t locked another shared object . . . ” ) ;41 synchronized ( a shared object )42 {43 System . out . pr int ln ( this . getName() +44 ” : jus t locked a shared object . . . ” ) ;45 }46 System . out . pr int ln ( this . getName() +47 ” : jus t unlocked a shared object . . . ” ) ;48 }49 System . out . pr int ln ( this . getName() +50 ” : jus t unlocked another shared object . . . ” ) ;51 }52 try53 {54 Thread . s l eep (( int )Math . random() ∗ 1000 ) ;55 }56 catch ( InterruptedException exc )57 {58 exc . printStackTrace ( ) ;59 }60 }61 }62

63 public static void main( Str ing [ ] args )64 {65 DeadLockExample t h e f i r s t = new DeadLockExample(FIRST THREAD NAME) ;66 DeadLockExample the second = new DeadLockExample(SECONDTHREADNAME) ;67

68 t h e f i r s t . s ta r t ( ) ;69 the second . s ta r t ( ) ;70 }71 }

In diesem Beispiel wird vom ersten Thread zuerst auf ein Objekt(a shared object ) synchronisiert, danach auf ein anderes Objekt(another shared object ). Fur den zweiten Thread ist es genau umgekehrt.Wird dieses Programm ausgefuhrt, dauert es nicht lange, bis ein Deadlock auf-tritt...

Page 110: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

KAPITEL 7. THREADS 105

Page 111: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Literaturverzeichnis

[Gamma et al., 1998] Gamma, Helm, Johnson, and Vlissides (1998). DesignPatterns: Elements of Reusable Object-Oriented Softwa-re. Addison-Wesley Longman, Inc.

[Gosling et al., 1996] Gosling J., Joy B., Steele G.: The Java Language Spe-fication, Addison-Wesley (1996). Online: http://java.sun.com/docs/books/jls/index.html

[Sun 1999] Sun Code Conventions for the Java Programming Lan-guage, April 20, 1999; Online: http://java.sun.com/docs/codeconv

[Java Tutorial 2002] Sun The Java Tutorial, 2002; Online: http://java.sun.com/docs/books/tutorial/

[Java SDK Doc 2002] Sun JavaTM 2 SDK, Standard Edition, Version 1.4,2002; Online: http://java.sun.com/j2se/1.4/docs/index.html

[Javadoc Homepage] Sun Javadoc Tool Home Page; Online: http://java.sun.com/j2se/javadoc

[Oaks and Wong, 1999] Oaks and Wong (1999). Java Threads. O’Reilly Asso-ciates, Inc., 2nd edition.

[PPrakt. Java Coding 2002] Programmierpraktikum SS2002 Java CodingConvention, 2002; Online: http://courses.iicm.edu/programmierpraktikum/skriptum/java_coding_convention.pdf

[Silberschatz and Galvin, 1998] Silberschatz and Galvin (1998). Operating Sys-tem Concepts. Addison-Wesley Longman, Inc., 5th editi-on.

106

Page 112: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Index

Ubersetzen des Sourcecodes, 2NaN, 30%, 29javax.swing, 73

Abhangigkeit von Klassen, 4Ableitung, 42, 44, 63abstract, 58Access-Modifier, 53Accessibility API, 73ActionListener, 88Allgemeine Container, 91Anweisung, 34ArithmeticException, 29Array, 18

mehrdimensional, 21Array Element, 26atomare Operationen, 98Ausdrucke auswerten, 30Ausdruck, 34

Bitoperatoren, 31Block, 34BorderLayout, 77BoxLayout, 79break, 39Bytecode, 2

call-by-value, 60cast, 32ChangeListener, 88Class Member, 56Classpath, 5

Trennzeichen, 5clone, 62ComponentListener/Adapter, 85const cast, 24Container, 76continue, 39

Daemon-Threads, 97Datentyp, 12

boolean, 12numerisch, 12primitiv, 12referenz, 16

Deadlocks, 99default Wert, 25Default-Parameter, 61Dekrement

post, 28pre, 28

delete, 50Destruktor, 50do, 35Dokumentationskommentar, 11Drag and Drop, 73

Einfaches Applet, 8equals, 62event-dispatching thread, 90Event-Handling, 82Event-Listener Methoden, 84Exceptionhandler Paramter, 26Exceptions, 68expression, 34

Fehlerbehandlung, 68final, 24, 57, 58finalize, 52FlowLayout, 78Flusskontrolle, 34FocusListener/Adapter, 85for, 35full vs. short eval, 30

garbage collector, 50GC, 50GridBagLayout, 79GridLayout, 78GUI-Builder, 74

has-a, 41

107

Page 113: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

INDEX 108

if, 37if-operator, 37Implementation

Threads, 96Info Komponenten, 92Initialisierung, 58Inkrement

post, 28pre, 28

inner classes, 62instanceof, 32Instanzvariable, 26Interface, 42, 65Interpretieren des Bytecodes, 2is-a, 41isAlive, 101ItemListener, 88

Java 2D, 73Java Foundation Classes (JFC), 73Java und Windows 95, 3join, 101

Kapselung, 42KeyListener/Adapter, 86Klasse, 41

abstrakt, 44Definition, 43Destruktor, 50final, 44Konstruktor, 45Sichtbarkeit, 43String, 17StringBuffer, 17

Klassen in Java, 41Klassenpfad, 5Klassenvariable, 25Kommandozeilen-Auswertung, 6Kommentare, 10Konstruktor, 45Konstruktor Parameter, 26Kontroll Komponenten, 92Kontrollfluss, 34

label, 40Layoutmanager, 77Lebenszyklus Thread, 99Lokale Variable, 26

main

argv vs. args, 8Methode, 4

Maschinencode, 2Member-Modifier, 52Member-Variable, 42Methode, 42Methoden, 59Methoden Parameter, 26Model-View-Controller, 75Modulo-Operator, 29MouseListener/Adapter, 86MouseMotionListener/Adapter, 87MVC, 75

native, 58nested classes, 62new, 32NoClassDefFoundError, 5

Object Member, 56Objekt, 41Operator, 28

instanceof, 32new, 32Overloading, 28Reihenfolge Auswertung, 28

overloading, 42overriding, 42

Packages, 66Panes, 77Parameter

call-by-value, 26Performancesteigerung, 2Pluggable Look and Feel, 73private, 53protected, 53public, 53

Referenz-Datentyp, 16return, 40

Schlusselworter, 11Sourcecode, 2Spezielle Komponenten, 93Sprungmarke, 40statement, 34super, 43, 49Swing, 73switch, 38synchronized, 58, 98

Page 114: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

INDEX 109

System.arraycopy, 20

this, 41thread-groups, 94thread-pools, 94Threads, 94Top-Level Container, 90Top-level Container, 76toString, 62transient, 57try...catch, 68

User-Threads, 97

Variabledefault Wert, 25Definition, 22Deklaration, 22Gultigkeitsbereich, 25Initialisierung, 25lokal, 26

Variablen-Modifier, 57Vergleichsoperatoren, 30volatile, 57

while, 35WindowListener, 88

Zeichen von Komponenten, 89Zeichenketten, 17Zeiger, 12Zuweisungsoperator, 32

Page 115: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Changelog

Aktuelle Version: 14.08.2003.

• Anderungen zur Version vom 13.06.2002:

Datentypen: Bei den Beispielen diverse Anpassungen im Codingstyle.

Swing: Swing und JFC...

Swing: Verlinkungen der Beispiele zum Tutorial von Sun.

• Anderungen zur Version vom 20.06.2002:

Datentypen: Zeilennummern in Text adaptiert.

• Anderungen zur Version vom 28.06.2002:

Swing / Datenstrukturen: Hier hat Omar Elschatti viele Typos ge-funden.

Alle Abschnitte: Nina Schmuck hat seeehhhrr viele Typos und Bei-strichfehler gefunden ;)

• Anderungen zur Version vom 22.07.2002:

Index: index-Markups wurden eingesetzt

Folien: Verwendung von dino external slides.sty

Anatomie: Erweiterungen zu “Vom Sourcecode zum Programm”

Datentypen: Vergleiche zu C++; Umstellen einiger Abschnitte

Klassen: Mehr Unterschiede zu C++; Umstrukturierung

• Anderungen zur Version vom 14.05.2003:

Swing: Weitere Hinweise und Kommentare.

• Anderungen zur Version vom 22.05.2003:

Anatomie: Zusatzlicher Hinweis, was alles schiefgehen kann...

Klassen: Korrektur einiger Beispiele bez. Codingstandard.

Threads: Umstrukturierungen

• Anderungen zur Version vom 2.6.2003:

110

Page 116: Harald Krottmaier 14. August 2003 - coronet.iicm.tugraz.at · gew¨ahrleisten (im Speziellen zu C++). Danach wird ein Uberblick¨ ¨uber Datentypen, die in Java zur Verf ¨ugung stehen,

Anatomie: Und wieder: zusatzlicher Hinweis, was alles schiefgehen kann...

Datentypen: Fehler bei der Beschreibung von Operatoren korrigiert.

Klassen: Zusatzlicher Hinweis zu Packages.

Swing: Abschnitt uber MVC-Architektur. Korrekturen bei den Beispie-len bez. Codingstandard :) (Tnx and Edi!)

• Anderungen zur Version vom 2.6.2003:

Alle Abschnitte: Edi Haselwanter hat vieeellle Textstellen korrigiert.

• Anderungen zur Version vom 12.06.2003

Struktur: Die Links vom Index zur jeweiligen Textstellen haben nichtimmer funktioniert. Ivan Maricic hat mir hierzu Hinweise gegeben,sodass diese Links nun funktionieren sollten.

Swing, Threads: Edi Haselwanter war wieder fleißig :)

111