Informatik B - Vorlesungen - Universit¤t Osnabr¼ck

260
Informatik B Objekt-orientierte Programmierung mit Java Sommersemester 2002 Fachbereich Mathematik/Informatik, Universit¨ at Osnabr ¨ uck Ute Schmid (Vorlesung) Elmar Ludwig ( ¨ Ubung) und Tutoren Voraussetzungen: (Vorlesung Informatik A “Algorithmen”) Grundkenntnisse in der (prozeduralen) Programmierung mit Java Grundkenntnisse in Algorithmenentwicklung http://www.vorlesungen.uos.de/informatik/b02/

Transcript of Informatik B - Vorlesungen - Universit¤t Osnabr¼ck

Informatik B

Objekt-orientierte Programmierungmit Java

Sommersemester 2002Fachbereich Mathematik/Informatik, Universitat Osnabruck

Ute Schmid (Vorlesung)Elmar Ludwig (Ubung)

und Tutoren

Voraussetzungen: (Vorlesung Informatik A “Algorithmen”)

• Grundkenntnisse in der (prozeduralen) Programmierung mit Java

• Grundkenntnisse in Algorithmenentwicklung

http://www.vorlesungen.uos.de/informatik/b02/

Ute SchmidFachgebiet InformatikFachbereich 6, Mathematik/InformatikUniversitat OsnabruckAlbrechtstrasse 28, D-49076 Osnabruck

Raum 31/318Tel.: 0541/[email protected]://www.inf.uos.de/schmid/

Dies ist eine uberarbeitete Version des Skripts vom SS 2001. Vielen Dank an Elmar Ludwigfur kritische Durchsicht, Korrekturvorschlage, Anregungen und Diskussionen.

Literatur

Objekt-orientierte Programmierung/Spezielle Aspekte

Zum Thema ‘Objekt-Orientierte Programmierung’:Timothy Budd, An Introduction to Object-Oriented Programming, 2nd Edition, 1997,Addison-Wesley.

Zum Thema ‘Design Patterns’ (und etwas UML):James W. Cooper, Java Design Patterns. Tutorial, 1994, Addison-Wesley.Matthias Felleisen, Daniel P. Friedman, A Little Java, A Few Patterns, 1998, MIT Press.

Zum Thema ‘Abstrakte Datentypen’:Timothy Budd, Classic Data Structures in Java, 2001, Addison-Wesley.

Zum Thema ‘Nebenlaufigkeit’:Doug Lea, Concurrent Programming in Java. Design Principles and Patterns, 2ndEdition, 1999, Sun Books.

Lehrbuch, das den Stoff von ‘Algorithmen’ abdeckt mit Programmen in Pseudo-Java (eherprozeduraler Code):Sara Baase, Allen van Gelder, Computer Algorithms – Introduction to Design andAnalysis, 3rd Edition, 2000, Addison-Wesley.

Uberblick uber verschiedene Programmierkonzepte:Ravi Sethi, Programming Languages: Concepts & Constructs, 2nd Edition, 1997,Addison-Wesley.

Java

D. Flanagan, Java in a Nutshell, 3rd Edition, 1999, O’Reilly.

D. Flanagan, Java Examples in a Nutshell, 2nd Edition, 2000, O’Reilly.

Bruce Eckel, Thinking in Java, 2nd Edition, 1998, Prentice-Hall.

Mary Campione, Kathy Walrath, The Java Tutorial, Object-Oriented Programming for theInternet, 2nd Edition, 1997, Addison-Wesley. (auch in deutscher Ubersetzung erhaltlich)

Ken Arnold, James Gosling, The Java Programming Language, 3rd Edition, Addison-Wesley.(auch in deutscher Ubersetzung erhaltlich)

Das Skript bezieht sich auf folgende weitere Quellen:

J. R. Anderson, Kognitive Psychologie, 3. Auflage, 2001, Spektrum. (Hierarchischessemantisches Gedachtnis)

R. G. Herrtwich und G. Hommel, Nebenlaufige Programme, 2. Auflage, Springer, 1994.

Atsushi Igarashi, Benjamin Pierce and Philip Wadler, Featherweight Java: A Minimal CoreCalculus for Java and GJ. In Proc. of ACM Conference on Object-Oriented Programing,Systems, Languages, and Applications (OOPSLA), ACM SIGPLAN Notices, 34(10), pp./132-146, 1999.

Atsushi Igarashi and Benjamin C. Pierce. On Inner Classes. Accepted for publication inInformation and Computation as of November 24, 2000.

P. Pepper, Grundlagen der Informatik, 2. Auflage, Oldenbourg, 1995.

A. T. Schreiner, Vorlesungsskript Programming with Java 2, Universitat Osnabruck undRochester Institute of Technology. http://www.cs.rit.edu/˜ats/java-2000-1/

Sperschneider und Hammer, 1996, Theoretische Informatik. Eine problemorientierteEinfuhrung. Springer.

Oliver Vornberger und Olaf Muller, Skript Informatik A.

Inhaltsverzeichnis

1 Einfuhrung: Programmier-Paradigmen und -Sprachen 11.1 Entwicklung von Paradigmen und Sprachen . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Uberblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.2 Entwicklung von Hochsprachen . . . . . . . . . . . . . . . . . . . . . . . . 11.1.3 Motivation: Kenntnis mehrere Paradigmen . . . . . . . . . . . . . . . . . . 3

1.2 Prozeduren und Parameterubergabe-Mechanismen . . . . . . . . . . . . . . . . 41.2.1 Programmstruktur bei imperativen Sprachen . . . . . . . . . . . . . . . . 41.2.2 Prozeduren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2.3 Parameterubergabe-Methoden . . . . . . . . . . . . . . . . . . . . . . . . 61.2.4 Call-by-Value versus Call-by-Reference . . . . . . . . . . . . . . . . . . . 71.2.5 Call-by-Value versus Call-by-Name . . . . . . . . . . . . . . . . . . . . . . 71.2.6 Call-by-value in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.3 Sprach-Implementierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.4 Syntaktische Struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

1.4.1 Formale Sprachen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.4.2 BNF und EBNF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.5 Semantik und Pragmatik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2 Java und Objekt-Orientierung 172.1 Grundkonzepte der Objekt-Orientierung . . . . . . . . . . . . . . . . . . . . . . . 17

2.1.1 Eigenschaften Objekt-Orientierter Sprachen . . . . . . . . . . . . . . . . . 172.1.2 Prinzipien der Objekt-Orientierten Programmierung . . . . . . . . . . . . 17

2.2 Die Sprache Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.1 Entstehungsgeschichte . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.2.2 Java Buzzwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.2.3 Sprache, Virtuelle Maschine, Plattform . . . . . . . . . . . . . . . . . . . . 19

2.3 Das 8-Damen Problem Imperativ und Objekt-Orientiert . . . . . . . . . . . . . . . 212.3.1 Problemstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.3.2 Identifikation von Schlagstellungen . . . . . . . . . . . . . . . . . . . . . . 222.3.3 Imperative Losung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.3.4 Objekt-Orientierte Losung . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3 Klassen und ihre Komponenten 283.1 Klassen in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.2 Members: Felder, Methoden, Klassen . . . . . . . . . . . . . . . . . . . . . . . . 283.3 Beispielcode ‘Circle’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293.4 Klassen- und Instanz-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.4.1 Klassen-Felder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293.4.2 Klassen-Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303.4.3 Instanz-Felder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303.4.4 Erzeugung und Initialisierung von Objekten . . . . . . . . . . . . . . . . . 313.4.5 Instanz-Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313.4.6 Funktionsweise von Instanz-Methoden: ‘this’ . . . . . . . . . . . . . . . . 323.4.7 Instanz- oder Klassen-Methode? . . . . . . . . . . . . . . . . . . . . . . . 32

3.5 Referenztypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333.5.1 Kopieren von Objekten (und Arrays) . . . . . . . . . . . . . . . . . . . . . 34

3.5.2 Gleichheit von Objekten (und Arrays) . . . . . . . . . . . . . . . . . . . . . 353.6 Wrapper-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.7 Dokumentation mit ‘javadoc’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.8 Packages und Namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.8.1 Java API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.8.2 Packages und Namespaces in Java . . . . . . . . . . . . . . . . . . . . . 403.8.3 Namens-Kollisionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.8.4 Verhaltensanderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

4 Konstruktoren und Vererbung 444.1 Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

4.1.1 Definition von Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . 444.1.2 Definition mehrerer Konstruktoren . . . . . . . . . . . . . . . . . . . . . . 45

4.2 Defaults und Initialisierung fur Felder . . . . . . . . . . . . . . . . . . . . . . . . . 454.2.1 Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454.2.2 Initialisierung von Instanz-Feldern: Konstruktoren . . . . . . . . . . . . . . 464.2.3 Initialisierung von Klassen-Feldern: Initialisierungs-Blocke . . . . . . . . . 47

4.3 Zerstoren und Finalisieren von Objekten . . . . . . . . . . . . . . . . . . . . . . . 484.3.1 Garbage Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484.3.2 Anmerkung: Finalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

4.4 Unterklassen und Vererbung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494.4.1 Exkurs: Hierarchische Semantische Netze . . . . . . . . . . . . . . . . . . 494.4.2 Erweiterung von ‘Circle’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514.4.3 Erweiterung einer Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.5 Kapslung und Zugriffskontrolle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524.5.1 Zugriffs-Kontrolle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.5.2 Vier Ebenen von Zugriffsrechten . . . . . . . . . . . . . . . . . . . . . . . 534.5.3 Zugriffs-Kontrolle und Vererbung . . . . . . . . . . . . . . . . . . . . . . . 544.5.4 Daumenregeln fur Sichtbarkeits-Modifikatoren . . . . . . . . . . . . . . . 554.5.5 Daten-Zugriffs-Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

5 Klassenabh angigkeiten 575.1 Klassenhierarchie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.1.1 Finale Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575.1.2 Die Klasse ‘Object’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575.1.3 Klasse ‘String’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575.1.4 Hierarchische Klassenstruktur . . . . . . . . . . . . . . . . . . . . . . . . 58

5.2 Erganzung: Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605.2.1 Unterklassen-Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . 605.2.2 Default-Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605.2.3 Konstruktor-Verkettung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

5.3 Vererbung: Shadowing und Overriding . . . . . . . . . . . . . . . . . . . . . . . . 615.3.1 Verdecken von Feldern der Oberklasse . . . . . . . . . . . . . . . . . . . 615.3.2 Shadowing von Klassen-Feldern . . . . . . . . . . . . . . . . . . . . . . . 625.3.3 Uberschreiben von Instanz-Methoden der Oberklasse . . . . . . . . . . . 635.3.4 Uberschreiben vs. Verdecken . . . . . . . . . . . . . . . . . . . . . . . . . 635.3.5 Dynamisches ‘Method Lookup’ . . . . . . . . . . . . . . . . . . . . . . . . 645.3.6 ‘Final’ Methoden und Statisches ‘Method Lookup’ . . . . . . . . . . . . . 64

5.3.7 Aufruf einer uberschriebenen Methode . . . . . . . . . . . . . . . . . . . . 645.4 Overloading und Polymorphismus . . . . . . . . . . . . . . . . . . . . . . . . . . 65

5.4.1 Operator-Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655.4.2 Operator-Overloading in Java . . . . . . . . . . . . . . . . . . . . . . . . . 665.4.3 Method-Overloading in Java . . . . . . . . . . . . . . . . . . . . . . . . . . 675.4.4 Polymorphismus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675.4.5 Casting und Polymorphismus . . . . . . . . . . . . . . . . . . . . . . . . . 685.4.6 Casting vs. Parameterisierte Klassen . . . . . . . . . . . . . . . . . . . . 69

6 Exceptions 716.1 Fehler und Ausnahmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716.2 Vorteile von Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

6.2.1 Separierung von Code und Fehlerbehandlung . . . . . . . . . . . . . . . 726.2.2 Propagierung von Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . 73

6.3 Exception Handling – ‘try’, ‘catch’, ‘finally’ . . . . . . . . . . . . . . . . . . . . . . 746.4 Spezifikation von Exceptions – ‘throws’ . . . . . . . . . . . . . . . . . . . . . . . . 786.5 Vererbung und ‘throws’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

6.5.1 Gruppierung von Fehler-Typen . . . . . . . . . . . . . . . . . . . . . . . . 796.6 Definition eigener Exception-Klassen und Auslosen von Exceptions . . . . . . . 806.7 Exkurs: UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

6.7.1 Klassendiagramme in UML . . . . . . . . . . . . . . . . . . . . . . . . . . 816.7.2 Klassen-/ Unterklassenbeziehungen in UML . . . . . . . . . . . . . . . . 826.7.3 Assoziationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836.7.4 Kommentare und Annotierung in UML . . . . . . . . . . . . . . . . . . . . 846.7.5 UML-Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

6.8 Exkurs: Design Patterns – Factory Pattern . . . . . . . . . . . . . . . . . . . . . . 85

7 Input/Output 897.1 Ein-/Ausgabe-Strome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

7.1.1 Klassenstruktur in ‘java.io’ . . . . . . . . . . . . . . . . . . . . . . . . . . . 897.1.2 Character und Byte Strome . . . . . . . . . . . . . . . . . . . . . . . . . . 907.1.3 Wichtige Reader- und Writer-Klassen . . . . . . . . . . . . . . . . . . . . 92

7.2 Datei-Strome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937.3 Puffern von Daten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947.4 Filter-Strome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957.5 Standard-Ein- und Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 977.6 IO-Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 987.7 RandomAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 997.8 Weitere Aspekte von I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

7.8.1 Tokenizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 997.8.2 Serializable, Externalizable . . . . . . . . . . . . . . . . . . . . . . . . . . 1007.8.3 Pipe-Strome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

8 Vererbung und Typsicherheit 1018.1 Formale Modelle fur Programmiersprachen . . . . . . . . . . . . . . . . . . . . . 1018.2 Featherweight Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

8.2.1 Programmbeispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038.2.2 Syntax fur FJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

8.2.3 Subtyping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048.2.4 Hilfsfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

8.3 Typisierung und Reduktion in FJ . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078.3.1 Typisierungsregeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078.3.2 Reduktionsregeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078.3.3 Veranschaulichung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

9 Abstrakte Klassen und Interfaces 1129.1 Abstrakte Klassen und Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . 1129.2 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

9.2.1 Implementation eines Interfaces . . . . . . . . . . . . . . . . . . . . . . . 1149.2.2 Interfaces und Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . 1159.2.3 Benutzung von Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . 1159.2.4 Interface vs. Abstrakte Klasse . . . . . . . . . . . . . . . . . . . . . . . . . 1169.2.5 Implementation mehrerer Interfaces und Erweitern von Interfaces . . . . . 1179.2.6 Marker-Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

9.3 Das Enumerator-Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

10 Innere Klassen 12210.1 Member Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

10.1.1 Anschauliches Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12210.1.2 Beispiel ‘Enumerator’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12410.1.3 Eigenschaften von Member-Klassen . . . . . . . . . . . . . . . . . . . . . 12510.1.4 Implementation von Member-Klassen . . . . . . . . . . . . . . . . . . . . 12610.1.5 Member-Klassen und Vererbung . . . . . . . . . . . . . . . . . . . . . . . 127

10.2 Static Member Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12810.2.1 Anschauliches Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12810.2.2 Eigenschaften von Static Member Classes . . . . . . . . . . . . . . . . . 12910.2.3 Implementation von statischen Member-Klassen . . . . . . . . . . . . . . 129

10.3 Lokale Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13010.3.1 Anschauliches Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13010.3.2 Beispiel: ‘Enumerator’ als lokale Klasse . . . . . . . . . . . . . . . . . . . 13010.3.3 Eigenschaften Lokaler Klassen . . . . . . . . . . . . . . . . . . . . . . . . 13110.3.4 Geltungsbereich Lokaler Klassen . . . . . . . . . . . . . . . . . . . . . . . 132

10.4 Anonyme Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13310.4.1 Beispiel: ‘Enumerator’ als anonyme Klasse . . . . . . . . . . . . . . . . . 13310.4.2 Eigenschaften von Anonymen Klassen . . . . . . . . . . . . . . . . . . . . 13310.4.3 Implementation von Lokalen und Anonymen Klassen . . . . . . . . . . . . 13410.4.4 Adapter-Klassen als Anonyme Klassen . . . . . . . . . . . . . . . . . . . 13410.4.5 Anwendung und Konventionen . . . . . . . . . . . . . . . . . . . . . . . . 135

10.5 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13510.6 Beispiel-Code ‘Enumeration’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13610.7 Adapter-Patterns und Java Adapter-Klassen . . . . . . . . . . . . . . . . . . . . . 13810.8 Innere Klassen und Lexical Closures . . . . . . . . . . . . . . . . . . . . . . . . . 139

10.8.1 Code as Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14010.8.2 Adder-Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

11 Abstrakte Datentypen und Collections 14111.1 Abstrakte Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

11.1.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14111.1.2 Funktionalitaten von Collections . . . . . . . . . . . . . . . . . . . . . . . 141

11.2 Implementation von Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14211.3 Implementation mit Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

11.3.1 MyCollection/Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14311.3.2 Erlauterungen zu ‘MyCollection’ . . . . . . . . . . . . . . . . . . . . . . . 14511.3.3 Test-Protokoll fur ‘MyCollection’ . . . . . . . . . . . . . . . . . . . . . . . . 14511.3.4 Bag/Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14611.3.5 Erlauterungen zu ‘Bag’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14711.3.6 Set/Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14711.3.7 Erlauterungen zu Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14811.3.8 Test-Protokoll fur ‘Set’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14911.3.9 EquivalenceSet/Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14911.3.10Erlauterungen zu ‘EquivalenceSet’ . . . . . . . . . . . . . . . . . . . . . . 15011.3.11Test-Protokoll fur ‘EquivalenceSet’ . . . . . . . . . . . . . . . . . . . . . . 150

11.4 Implementation mit Offener Hash-Tabelle . . . . . . . . . . . . . . . . . . . . . . 15111.4.1 Array versus Hash-Tabelle . . . . . . . . . . . . . . . . . . . . . . . . . . . 15111.4.2 MyCollection/Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15111.4.3 Erlauterungen zu ‘MyCollection’ . . . . . . . . . . . . . . . . . . . . . . . 15411.4.4 Bag/Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15411.4.5 Set/Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

11.5 ADT-Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15511.5.1 Anforderungen an ‘Test’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15511.5.2 Test/ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15611.5.3 Erlauterungen zu ‘Test’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

11.6 Implementation mit Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15911.6.1 Dynamische Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . 15911.6.2 Bag/List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16111.6.3 Erlauterungen zu ‘Bag’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16311.6.4 Unterklasse ‘Set’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16411.6.5 Unterklasse ‘EquivalenceSet’ . . . . . . . . . . . . . . . . . . . . . . . . . 164

11.7 Implementation mit Suchbaum . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16511.7.1 Suchbaume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16511.7.2 Set/Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16611.7.3 Erlauterungen zu ‘Set’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

11.8 Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17211.8.1 Konzept eines Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17211.8.2 ‘Visitor’, ‘Visitable’/ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17311.8.3 Suchbaum mit Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

11.9 Java Collection Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17411.9.1 Grundstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17411.9.2 Illustration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

12 Reflections 17812.1 Methoden des Reflection-API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17812.2 Die Klassen ‘Class’, ‘Method’, ‘Field’ und ‘Constructor’ . . . . . . . . . . . . . . . 17812.3 Inspektion von Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179

12.3.1 Abruf eines ‘Class’ Objekts . . . . . . . . . . . . . . . . . . . . . . . . . . 17912.3.2 Abruf des Klassen-Namens eines Objekts . . . . . . . . . . . . . . . . . . 18012.3.3 Abruf von Klassen-Modifikatoren . . . . . . . . . . . . . . . . . . . . . . . 18112.3.4 Abruf von Oberklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18112.3.5 Abruf des implementierten Interfaces einer Klasse . . . . . . . . . . . . . 18212.3.6 Interface oder Klasse? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18212.3.7 Abruf von Klassen-Feldern . . . . . . . . . . . . . . . . . . . . . . . . . . 18312.3.8 Abruf von Klassen-Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . 18412.3.9 Abruf von Methoden-Information . . . . . . . . . . . . . . . . . . . . . . . 184

12.4 Manipulation von Objekten zur Laufzeit . . . . . . . . . . . . . . . . . . . . . . . 18612.4.1 Dynamische Erzeugung von Objekten . . . . . . . . . . . . . . . . . . . . 18612.4.2 Exceptions beim dynamischen Erzeugen von Objekten . . . . . . . . . . 18612.4.3 Dynamische Erzeugung mit Konstruktor-Argumenten . . . . . . . . . . . 18712.4.4 Abruf und Belegung von Feldern . . . . . . . . . . . . . . . . . . . . . . . 18812.4.5 Method Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

12.5 Bemerkungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

13 Multi-Threading – Grundlagen der Nebenl aufigkeit 19113.1 Sequentialitat, Determinismus, Determiniertheit . . . . . . . . . . . . . . . . . . . 191

13.1.1 Nebenlaufigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19113.1.2 Nicht-Determinismus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19213.1.3 Nicht-Determiniertheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19213.1.4 Verzahnung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

13.2 Nebenlaufigkeit in Java: Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 19313.2.1 Definition von Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19413.2.2 Die Klasse Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19413.2.3 Einfaches Beispiel: ‘ThreadDemo’ . . . . . . . . . . . . . . . . . . . . . . 19513.2.4 Erlauterungen zu ‘ThreadDemo’ . . . . . . . . . . . . . . . . . . . . . . . 19713.2.5 Zustande von Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

13.3 Kooperierende und Konkurrierende Prozesse . . . . . . . . . . . . . . . . . . . . 19813.3.1 Kooperierende Prozesse . . . . . . . . . . . . . . . . . . . . . . . . . . . 19813.3.2 Konkurrierende Prozesse . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

13.4 Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20113.5 Monitore in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

13.5.1 Synchronized . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20113.5.2 Funktion von ‘synchronized’ . . . . . . . . . . . . . . . . . . . . . . . . . . 20313.5.3 Warten auf Ereignisse mit Monitoren . . . . . . . . . . . . . . . . . . . . . 203

13.6 Beispiel: Produzent/Konsument . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

14 Multi-Threading: Semaphoren und Deadlocks 20714.1 Semaphoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

14.1.1 Konzept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20714.1.2 Klasse ‘Semaphore’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20714.1.3 Einseitige und Mehrseitige Synchronisation . . . . . . . . . . . . . . . . . 208

14.1.4 Erzeuger-/Verbraucher-Problem mit Semaphoren . . . . . . . . . . . . . . 20814.2 Conditional Critical Regions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

14.2.1 Monitore, CCRs, Semaphoren . . . . . . . . . . . . . . . . . . . . . . . . 21114.3 Deadlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

14.3.1 Losung mit Semaphoren . . . . . . . . . . . . . . . . . . . . . . . . . . . 21114.3.2 Dining Philosophers – Losung mit globaler Kontrolle . . . . . . . . . . . . 21314.3.3 Dining Philosophers – Bedingter Zugriff auf Gabel . . . . . . . . . . . . . 21614.3.4 Deadlocks durch falsche Anordnung . . . . . . . . . . . . . . . . . . . . . 218

14.4 Threads: Erganzungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21814.5 Pipe-Strome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

15 Regul are Ausdrucke und Pattern-Matching 22515.1 String Pattern-Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

15.1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22515.1.2 Straightforward Losung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22515.1.3 String-Matching mit endlichen Automaten . . . . . . . . . . . . . . . . . . 22515.1.4 Der Knuth-Morris-Pratt (KPM) Algorithmus . . . . . . . . . . . . . . . . . 22715.1.5 Pattern-Matching mit Regularen Ausdrucken . . . . . . . . . . . . . . . . 229

15.2 Java 1.4 ‘regex’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23015.2.1 Konstruktion regularer Ausdrucke . . . . . . . . . . . . . . . . . . . . . . . 23015.2.2 Die Pattern-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23115.2.3 Die Matcher-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23115.2.4 Beispiel: Suche und Ersetze . . . . . . . . . . . . . . . . . . . . . . . . . 231

16 Assertions 23416.1 Zusicherungskalkul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23416.2 Die ‘assert’-Anweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

17 Ausblick: GUIs und Event Handling 23617.1 Java Foundation Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23617.2 Swing-Komponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

17.2.1 Erstes Beispiel ‘HelloWorldSwing’ . . . . . . . . . . . . . . . . . . . . . . 23617.2.2 Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23817.2.3 Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23817.2.4 Layout Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24017.2.5 Anmerkungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241

17.3 Event-Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24217.3.1 Event-Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24217.3.2 Event Listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24217.3.3 Event Handling mit Inneren Klassen . . . . . . . . . . . . . . . . . . . . . 243

17.4 Applets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24517.4.1 Unterschiede zwischen Applets und Applications . . . . . . . . . . . . . . 24517.4.2 Schreiben von Applets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24517.4.3 Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

17.5 GUIs und Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24717.6 Beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

18 Ausblick: Verteilte Systeme 248

19 Andere Objekt-Orientierte Sprachen 248

Informatik B • SS 02 1

1 Einfuhrung: Programmier-Paradigmen und -Sprachen

1.1 Entwicklung von Paradigmen und Sprachen

1.1.1 Uberblick

• Zur Zeit existieren vier Programmier-Paradigmen:imperativ , funktional , logisch, objekt-orientiert .

• Objekt-Orientierung ist das jungste Paradigma (80er Jahre).

• Jedem Paradigma lassen sich konkrete Programmiersprachen zuordnen.

• Java ist eine relativ junge Sprache, die das objekt-orientierte Paradigmaunterstutzt (1995).

• Imperative/Prozedurale Sprachen(Fortran, Pascal, Modula, C): Zuweisung vonWerten an Variablen durch Befehle, Zustandstransformation.

• Logische Sprachen(Prolog): Programm als Menge von logischen Klauseln,Interpretation: Beweis der Anfrage bei gegebenem Programm.

• Funktionale Sprachen(Lisp, ML): Programm als Menge (typisierter) Funktionen,nur call by value ↪→ keine Seiteneffekte.

• Objekt-orientierte Sprachen (C++, Smalltalk, Java): Programm als Menge vonObjekten, die miteinander interagieren.

Is a programming language a tool for instructing machines? A means forcommunicating between programmers? A vehicle for expressing high-leveldesigns? A notation for algorithms? A way of expressing relationshipsbetween concepts? A tool for experimentation? A means for controllingcomputerized devices? My conclusion is that a general-purposeprogramming language must be all of those to serve its diverse set ofusers. The only thing a language cannot be – and survive – is be a merecollection of “neat” features. (Stroustrup, 1994)

1.1.2 Entwicklung von Hochsprachen

Die Entwicklung von Hochsprachen wird in Abbildung 1 skizziert:

• Am Beginn der Entwicklung von Computern wurde mit Maschinensprachen(“erste Generation”) und Assembler-Sprachen (“zweite Generation”)programmiert.

• Hochsprachen(“dritte Generation”; seit Ende der 50er Jahre) brachten einenwesentlichen Fortschritt: Lesbarkeit, Fehlerprufung, Maschinenunabhangigkeit,Bibliotheken.strukturierte Programmierung (Dijkstra): Zerlegung eines Programms(Prozeduren, Abstrakte Datentypen, Module)

2 Informatik B • SS 02

FortranAlgol−58

Algol−60 CobolSimula I

Simula−67Algol−68

C

Modula−2Fortran−77

Ada−83

Modula−3

Ada−95 Java

Eiffel

Objective C

C++

CLOS

Haskell

Standard−ML

Common Lisp

ML

Scheme

Lisp

Fortran−90

Smalltalk

Prolog

195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995

Pascal

IMPERATIV OBJEKTORIENTIERT FUNKTIONAL LOGISCH

Abbildung 1: Entwicklung von hoheren Programmiersprachen

• Hochsprachen werden entweder von einem Compiler in Maschinencodeubersetzt oder uber einen Interpreter ausgefuhrt. Dazwischen stehenjust-in-time Compiler, bei denen Teile des Programms erst wahrend derAusfuhrung ubersetzt werden.

• (“vierte Generation”: anwendungsspezifische Sprachen wie SQL, Mathematica)

• Funktionale und logische Sprachen werden gemeinsam auch als deklarativeSprachenbezeichnet (“funfte Generation”, KI-Sprachen).

• Eine Programmiersprache ist eine formale Sprachemit Syntax (Grammatik, diebeschreibt, wie die Symbole der Sprache kombiniert werden durfen), Semantik(Bedeutung der Sprachkonstrukte, ihr Laufzeitverhalten), und Pragmatik(Verwendung von Sprachmerkmalen; Sprachimplementation)

• Sprachen sind sich mehr oder weniger ahnlich. Sprachen innerhalb desselbenProgrammierparadigmas basieren auf ahnlichen Grundstrukturen.

• Naturliche Sprachen – Deutsch, Englisch, Hopi-Indianisch, Japanisch,Esperanto – fallen in verschiedene Sprachfamilien. Indogermanische Sprachenbasieren auf anderen Konzepten als indianische Sprachen und damit sindandere Vorstellungen von der Welt verbunden (z. B. Zeit als Pfeil versus Zyklus).

Informatik B • SS 02 3

1.1.3 Motivation: Kenntnis mehrere Paradigmen

Die Grenzen meiner Sprache sind die Grenzen meiner Welt. (L.Wittgenstein)

Grunde, warum man mehrere Paradigmen/Sprachen kennen sollte:

• Großeres Repertoire an Ausdrucksmoglichkeiten

– Sprache beschrankt nicht nur was wir formulieren, sondern auch, was wirdenken konnen (Whorf, Language, Thought, and Reality, 1956)

– Die Sprache, in der Programme entwickelt werden, beschrankt diemoglichen Kontrollstrukturen, Datenstrukturen und Abstraktionen, dieverwendet werden konnen. Damit ist auch die Bandbreite der realisierbarenAlgorithmen beschrankt.

– Zum Teil konnen Konzepte einer Sprachklasse in einer anderen simuliertwerden. Aber: Es ist immer besser, die Konzepte der Sprache, in der manarbeitet, voll auszunutzen, als nicht gut unterstutzte Konzepte zu simulieren(weniger elegant, weniger effizient).

• Hintergrund f ur geeignete Sprachwahl

– Die Kenntnis einer großeren Menge von Sprachen aus verschiedenenParadigmen erlaubt es, fur ein gegebenes Problem die geignetste Sprachezu wahlen.

• Bessere Voraussetzung um neue Sprachen zu lernen

– Programmierer mit wenig formaler Ausbildung lernen haufig nur ein oderzwei Sprachen. Ist die Ausbildung zudem an der Syntax der Sprache undnicht an den Konzepten orientiert, ist es nur schwer moglich, sich schnell inneue Sprachen einzuarbeiten.

– Kenntnis des Vokabulars und der Konzepte von Programmiersprachen istVoraussetzung, um Sprachdokumentationen verstehen zu konnen.

• Verstandnis von Implementations-Details

– Wenn man etwas daruber weiss, wie eine Sprache entworfen undimplementiert ist, kann man die Sprache oft intelligenter, ihrem Designentsprechend, nutzen. Man wird ein besserer Programmierer, wenn manversteht, warum bestimmte Konstrukte in einer Sprache realisiert wurdenund was die Konsequenzen davon sind.

– Verstandnis daruber, wie Programme ausgefuhrt werden, kann dieFehlervermeidung, -erkennung und -beseitigung erleichtern und hilft oft,Programme effizienter zu realisieren.

4 Informatik B • SS 02

• Voraussetzung fur Sprachentwicklung

– Die Entwicklung neuer Allzweck-Programmiersprachen kommt nicht allzuhaufig vor, und es arbeitet nur eine relativ kleine Gruppe von Informatikernin der Sprachentwicklung.

– Aber: Viele Programmierer werden ab und zu kleine Sprachen fur spezielleAnwendungen entwerfen.

• Allgemeine Entwicklung von Programmiersprachen

– Nicht immer ist die popularste Sprache die beste Sprache. Wenndiejenigen, die sich fur die Verwendung einer Sprache entscheiden, besserinformiert sind, konnen sich gute Sprachen vielleicht besser/schnellerdurchsetzen.

1.2 Prozeduren und Parameterubergabe-Mechanismen

1.2.1 Programmstruktur bei imperativen Sprachen

• In objekt-orientierten Sprachen sind Klassen/Objekte die kleinsten autonomenBausteine.

• In imperativen Sprachen gliedert sich ein Programm dagegen in

– einen Deklarationsblock (Typdefinitionen, globale Variablen undKonstanten),

– eine Menge von Prozeduren und

– ein Hauptprogramm.

• In Abbildung 2 ist ein Modula-2 Programm abgedruckt.

1.2.2 Prozeduren

• Prozeduren dienen der Strukturierung des Programms. Wie Methoden in Javasind Prozeduren benannt (↪→ Rekursion als Kontrollstruktur moglich).

• Prozeduren bestehen aus einem Kopf und einem Rumpf.

• Der Kopf besteht aus einem Schlusselwort (z.B. PROCEDURE), einembenutzerdefinierten, moglichst vielsagenden Namen (z.B. ReadMaxIndex ),einer Folge von (0 bis beliebig vielen) formalen Parametern, und moglicherweiseeinem Ergebnistyp (Funktion). (vgl. Java Methoden mit Ruckgabetyp bzw.void ).

• Wie bei Java-Methoden konnen im Rumpf lokale Variablen und Konstantendeklariert werden. Die Berechnungsvorschrift wird als Folge von Anweisungenangegeben.

Informatik B • SS 02 5

MODULE ggt;

FROM InOut IMPORT ReadCard, WriteCard, WriteString, WriteLn;

PROCEDURE ReadMaxIndex(VAR maxindex : CARDINAL) : BOOLEAN;BEGIN

WriteString("Gib eine ganze, positive Zahl ein : ");ReadCard(maxindex);RETURN (maxindex > 0) (* TRUE wenn maxindex > 0 *)

END ReadMaxIndex;

PROCEDURE ggT(arg1, arg2 : CARDINAL) : CARDINAL;VAR x, y, z : CARDINAL; (* Hilfsvariablen zur ggT-Bestimmung *)

BEGINx:=arg1; (* ggT(arg1, arg2) bestimmen *)y:=arg2;WHILE y#0 DO

z:=x MOD y;x:=y;y:=z

END;RETURN x

END ggT;

PROCEDURE WriteGGTs(maxindex : CARDINAL);VAR line : CARDINAL; (* Zeilenindex *)

column : CARDINAL; (* Spaltenindex *)

BEGINWriteString(" "); (* Tabelle *)FOR column:=1 TO maxindex DO WriteCard(column, 3) END;WriteLn;WriteLn;FOR line:=1 TO maxindex DO

WriteCard(line, 3);FOR column:=1 TO maxindex DO

WriteCard(ggT(line, column), 3)END;WriteLn

ENDEND WriteGGTs;

VAR maxindex : CARDINAL; (* Zeilenanzahl=Spaltenanzahl der Tabelle *)

BEGINIF ReadMaxIndex(maxindex) THEN WriteGGTs(maxindex)ELSE

WriteString("falsche Eingabe");WriteLn

ENDEND ggt.

Abbildung 2: Modula-2 Programm zur Berechnung des ggT

6 Informatik B • SS 02

1.2.3 Parameterubergabe-Methoden

• Formale Parameter werden im Kopf einer Prozedur angegeben. Im Rumpftauchen sie in Anweisungen auf.

• Formale Parameter sind Platzhalter fur konkrete Parameter, die beimProzeduraufruf ubergeben werden.

• Parameterubergabe meint das Matching der konkreten mit den formalenParametern.

• Es gibt verschiedene Parameterubergabe-Methoden:

– Call-by-value: Argumente werden zunachst ausgewertet. Die resultierendenWerte werden dann ubergeben. Zuweisungen an die Parameter innerhalbder Prozedur haben keine Auswirkung auf die im aufrufenden Kontextvorhandenen Variablen. (Man spricht auch von strict evaluation.)Beim Aufruf ggT(line, columnn) in der Prozedur WriteGGTs werdenzunachst line und column durch die aktuellen Werte dieser Variablenersetzt. Mit diesen Werten werden dann die Parameter von ggT – arg1,arg2 – initialisiert.

– Call-by-reference: Die Referenz (Adresse) der Argument-Variablen wird andie Prozedur ubergeben. Ausfuhrung der Prozedur kann Seiteneffekte aufdie Werte der Argumente im aufrufenden Kontext haben.Im Modula-2-Programm in Abb. 2 ist maxindex ein call-by-referenceParameter. maxindex wird in der Prozedur ReadMaxIndex belegt. Wirddie Prodzedur WriteGGTs aufgerufen, so hat maxindex den inReadMaxIndex ermitteltend Wert.

– Call-by-name: Argumentausdrucke werden unausgewertet (als Referenzauf Code, der den Wert des Arguments liefert, zusammen mit einerUmgebung fur die Werte von freien Variablen) ubergeben. (lazy evaluation)Um Mehrfachauswertung zu vermeiden, wird ublicherweise mitGraphreduktionsmethoden gearbeitet (call-by-need).Call-by-name wurde im Rahmen von Algol-60 entwickelt und wird heute vorallem bei funktionalen Sprachen verwendet. Vorteile: Termination beiunendlichen Datenstrukturen (lazy lists) und Rekursion.

Informatik B • SS 02 7

1.2.4 Call-by-Value versus Call-by-Reference

MODULE ParaPass;

FROM InOut IMPORT WriteCard, WriteLn;

PROCEDURE P(x : CARDINAL; y : CARDINAL; VAR z : CARDINAL);VAR help : CARDINAL;BEGIN

help := x;x := 15;z := 2 * x + help;y := 0

END P;

VAR a, b, c : CARDINAL;

BEGINa := 1;b := 2;c := 3;P(a, a+b, c); (* call by value: Ausdruecke moeglich *)

(* call by reference: muss Variable sein *)WriteCard(a); (* immer noch 1 *)WriteCard(b); (* immer noch 2 *)WriteCard(c) (* 31 *)

END ParaPass.

Abbildung 3: Call-by-Value und Call-by-Reference in Modula

1.2.5 Call-by-Value versus Call-by-Name

(Beispiel in ML)

fun sqr(x) : int = x*x; (* uses its argument twice *)fun zero(x :int) = 0; (* ignores its argument *)

Auswertung von zero(sqr(sqr(sqr(2)))) mit call-by-value:zero(sqr(sqr(sqr(2)))) ⇒ zero(sqr(sqr(2 × 2)))

⇒ zero(sqr(sqr(4)))...⇒ zero(256)⇒ 0

Auswertung von zero(sqr(sqr(sqr(2)))) mit call-by-name:direkt Ruckgabe von 0.

8 Informatik B • SS 02

Aber (ohne Graphreduktion) resultiert unnotige Mehrfachberechnung:sqr(sqr(sqr(2))) ⇒ sqr(sqr(2))× sqr(sqr(2))

⇒ (sqr(2)× sqr(2))× sqr(sqr(2))⇒ ((2× 2)× sqr(2))× sqr(sqr(2))⇒ (4× sqr(2))× sqr(sqr(2))⇒ (4× (2× 2))× sqr(sqr(2))...

1.2.6 Call-by-value in Java

• In Sprachen wie Modula und C + + existieren sowohl call-by-value als auchcall-by-reference als Parameterubergabe-Mechanismen.

• Call-by-reference macht auch dann Sinn, wenn die Parameterwerte nichtinnnerhalb der Prozedur geandert werden sollen: Speicherersparnis undEffizienz (z.B. fur die Ubergabe von Arrays entfallt Kopieren)

• In Java existiert call-by-value als einziger Parameterubergabe-Mechanismus.

• Meist liest man Aussagen wie “primitive types are passed by value, but objectsare passed by reference”, die Verwirrung stiften konnen.

• Auch wenn Objekte naturlich als Referenzen ubergeben werden, ist derParameterubergabe-Mechanismus call-by-value!

• Das Programm PassByValue “missbraucht” die Klasse Button ausjava.awt etwas: genutzt wird nur das Feld label .

// Copyright (C) Andrew D. Mackie, 1999.// http://www.javamain.com/import java.awt.*;

public class PassByValue {//Demonstrates that Java parameters are always passed by value

public static void main(String[] args){System.out.println("In main");//the reference to an object is passed by valueButton b = new Button("AAA");System.out.println("The value of b’s label is " + b.getLabel());methodX(b);System.out.println("Back in main");System.out.println("The value of b’s label is " + b.getLabel());System.out.println("");//primitives are passed by value as wellint i = 5;System.out.println("The value of i is " + i);methodZ(i);System.out.println("Back in main");

Informatik B • SS 02 9

System.out.println("The value of i is " + i);System.exit(0);

}

//the reference to an object is passed by valuepublic static void methodX(Button y){

System.out.println("In methodX");System.out.println("The value of y’s label is " + y.getLabel());//update the button object that both y and b refer toy.setLabel("BBB");System.out.println("The value of y’s label is " + y.getLabel());//make y reference a different object - doesn’t affect variable by = new Button("CCC");System.out.println("The value of y’s label is " + y.getLabel());//updating button that y now references//has no affect on button referenced by by.setLabel("DDD");System.out.println("The value of y’s label is " + y.getLabel());

}

//primitives are passed by value as wellpublic static void methodZ(int j){

System.out.println("In methodZ");System.out.println("The value of j is " + j);//change value of j - doesn’t affect variable i within mainj = 6;System.out.println("The value of j is " + j);

}}

Ausgabe:

In main

The value of b’s label is AAA

In methodX

The value of y’s label is AAA

The value of y’s label is BBB

The value of y’s label is CCC

The value of y’s label is DDD

Back in main

The value of b’s label is BBB

The value of i is 5

In methodZ

The value of j is 5

The value of j is 6

Back in main

The value of i is 5

10 Informatik B • SS 02

ButtonObjectb

y

ButtonObjectb

ButtonObject

Anothery

Abbildung 4: Call-by-Value in Java (siehe KlassePassByValue )

1.3 Sprach-Implementierung

• Ein Programm (Code, Quellcode) wird geschrieben, um Aufgaben automatischvon einem Rechner ausfuhren zu lassen.

• Ublicherweise wird ein Programm gestartet, erhalt eine Eingabe, fuhrtBerechnungen in Abhangigkeit von dieser Eingabe durch, liefert eine Ausgabeund wird beendet. (Programmausfuhrung)

• Die Laufzeit des Programms meint die Zeit vom Aufruf bis zur Termination; dieCompilezeit meint die Zeit, wahrend das Programm in Maschinen- oderZwischencode uberfuhrt wird.

• In anderem Zusammenhang meint Laufzeit auch die Zeitdauer, die zuurAusfuhrung eines Programms benotigt wird: Diese ist abhangig von derMaschine und insbesondere von der Aufwandsklasse der zugrundeliegendenAlgorithmen. (Die Komplexitat von Problemen, die gelost werden sollen, bedingtdie untere Schranke des Aufwands von Algorithmen. Thema in der Vorlesung“Theoretische Informatik”)

• Ein Compiler ubersetzt ein Programm in eine Ausgabesprache (haufigMaschinencode). Beispiele fur Compilersprachen sind C und Pascal. (sieheAbb. 5)

• Ein Interpreter ist eine Maschine auf hoherer Ebene, die das Programm direktausfuhrt. Beispiele fur Interpretersprachen sind Common Lisp und Prolog.(siehe Abb. 5)

• Alternativ gibt es hybride Implementationssysteme: Das Programm wirdzunachst in einen Zwischencode (Bytecode) ubersetzt, der auf beliebigeMaschinen portierbar ist, fur die ein entsprechender Bytecode-Interpreter unddazugehoriges Laufzeitsystem existiert. Beispielsweise erzeugt der

Informatik B • SS 02 11

Ausgabe

Interpreter

Eingabe

Quellprogramm Quellprogramm

Lexikalische Analyse

Syntaxanalyse

Zwischencode−Erzeugung

Eingabe Zwischencode

Interpreter

Ausgabe

Quellprogramm

Ausgabe

Lexikalische Analyse

Codeerzeugung

Symbol−tabelle Semantische Analyse

Zwischencode−Erzeugung

Syntaxanalyse

(Optimierung)

Compiler

ÜB

ER

SE

TZ

ZE

ITLA

UF

ZE

ITMaschinencode

Maschine

Eingabe

Abbildung 5: Implementations-Systeme: Compiler, Interpreter, Hybrid

Java-Compiler Bytecode, der von der Java Virtual Machine (rechnerspezifisch)ausgefuhrt wird. (siehe Abb. 5)

• Arbeitsschritte eines Compilers:

– Lexikalische Analyse: Zerlegung des Programmtextes in lexikalischeEinheiten (Reservierte Worte, Operatoren, Identifier; Kommentare werdenignoriert)

– Syntaktische Analyse (Parsierung): Erzeugung eines Parse-Baums, der diesyntaktische Struktur des Programms reprasentiert.

– Semantische Analyse: ublicherweise TypisierungZwischencode-Erzeugung (wenn ohne Optimierungsoption, z. B.Assembler)

– Optimierung (optional): Methoden der Programmtransformation, partielleEvaluation (Ersetzen von Ausdrucken durch ihr Ergebnis)

– Codegenerierung: aquivalentes Maschinencode-Programm

– Symboltabelle: Datenbasis fur die Compilierung, enthalt insbesondereTypen und Eigenschaften der benutzergenerierten Namen im Programm.

• Vor der Ausfuhrung mussen noch die entsprechenden Programme desBetriebssystems und eventuell Bibliotheksfunktionen mit demMaschinenprogramm verbunden werden (linking, Einfugen der entsprechendenAdressen in das Maschinencode-Programm).

• Ausfuhrung: In fetch-execute-Zyklen: Jede Maschineninstruktion muss vomSpeicher in den Prozessor ubertragen werden und Ergebnisse/Verweisemussen in den Speicher zuruckgeschrieben werden. (von-NeumannFlaschenhals)

12 Informatik B • SS 02

1.4 Syntaktische Struktur

1.4.1 Formale Sprachen

• Die Syntax einer Sprache legt fest, wie einzelne Symbole zu großerenStrukturen zusammengefugt werden durfen.

• Die Syntax einer Sprache wird – fur naturliche wie fur formale Sprachen – durcheine Grammatik beschrieben: G = (N, T, P, S) mit

– N als Menge der Nonterminal-Symbole

– T als Menge der Terminalsymbole

– P als Menge der Grammatikregeln (Produktionen) und

– S ∈ N als Startsymbol.

• Beispiel (einfacher Ausschnitt des Englischen)G = ({S,NP, V P,Det,N, V }, {the, cat, dog,mouse, eats, barks}, P, S) mit P :

S → NP V PNP → Det N (noun phrase)V P → V | V NP (verbal phrase)Det→ the (determiner)N → cat | dog | mouse (noun)V → eats | barks (verb)

Es konnen syntaktisch korrekte (aber nicht unbedingt semantisch sinnnvolle)Satze abgeleitet werden, wie “the mouse eats the cat”.

• Beispiel: G = ({S,A,B}, {0, 1}, P, S) mit P :S → 0A | 1BA→ 1 | 1SB → 0 | 0Sbeschreibt eine einfache Sprache uber dem Alphabet {0, 1}.

• Mit den Regeln aus P kann eine unendliche Menge von Worten generiertwerden, die zu dieser Sprache gehoren.

• Fur naturliche Sprachen geben Grammatiken meist an, wie korrekte Satze ausWorten geformt werden. Fur Programmiersprachen geben Grammatiken an, wieProgramme als wohlgeformte Ausdrucke uber Schlusselwortern undBezeichnern konstruiert werden. Eine formale Sprache wird als die Menge derwohlgeformten Worte uber einem endlichen Alphabet definiert.

• Worte, die zu obiger Sprache gehoren, sind 01, 10, 0101, 0110, 1010, 1001. DieKonstruktion der Wortmenge kann mit einem Ableitungsbaum dargestelltwerden (siehe Abb. 6).

Informatik B • SS 02 13

S

1B

01S

0101S 0110S 1001S 1010S

010A 011B 100A 101B

0A

10S01 10

0101 0110 1001 1010

Abbildung 6: Ableitungsbaum fur die einfache regulare Sprache(01 + 10)+

• Die Sprache ist regular und kann durch den regularen Ausdruck (01 + 10)+

dargestellt werden. R + S bezeichnet R ∪ S, R+ bezeichnet die positive Hulle(Menge aller Konkatenationen von Elementen aus R ohne das leere Wort), R∗

bezeichnet die Kleene’sche Hulle.)

• Regulare Sprachen sind die einfachsten Sprachen in der sogenannten ChomskyHierarchie. Sie konnen durch endliche Automaten erkannt werden.

• Programmiersprachen sind im Wesentlichenn kontextfreie Sprachen.Kontextfreie Sprachen folgen in der Chomsky-Hierarchie auf die regularen.

• Wahrend Grammatikregeln fur regulare Sprachen links- bzw. rechts-linear sind(S → aS bzw. S → Sa), sind bei kontextfreien Sprachen beliebigeKombinationen aus Terminal- und Nonterminalsymbolen erlaubt.

• Beispiel: P : S → 0S1, S → 01 beschreibt die Sprache 0n1n, also n 0-en gefolgtvon genauso vielen 1-en.

• Die Kenntnis formaler Sprachen ist wichtig fur die Implementierung vonProgrammiersprachen. Das Sprachdesign (die Grammatik) bedingt wieaufwendig die Parsierung von Programmen (siehe Phasen der Compilierung) ist!Formale Sprachen sind Gegenstand der Vorlesung “Theoretische Informatik”.

1.4.2 BNF und EBNF

• Die Syntax von Programmiersprachen wird ublicherweise in Backus-Naur Form(BNF) oder erweiterter Backus-Naur Form (EBNF) dargestellt.

• BNF und EBNF sind zu kontextfreien Grammatiken aquivalent.

• BNF und EBNF sind Meta-Sprachenzur Beschreibung von Sprachen.

• Produktionsregeln haben die Form Kopf ::= Korper.

• Nichtterminale werden in spitzen Klammern dargestellt, dadurch konnen auchganze Worter statt nur einzelne Symbole als Nonterminale verwendet werden.

• Alternative rechte Seiten werden durch einen senkrechten Strich getrenntdargestellt.

14 Informatik B • SS 02

class_declaration::={ modifier } "class" identifier[ "extends" class_name ][ "implements" interface_name { "," interface_name } ]"{" { field_declaration } "}"

for_statement::="for" "(" ( variable_declaration | ( expression ";" ) | ";" )[ expression ] ";"[ expression ] ";"")" statement

Abbildung 7: Klassen-Definition und For-Statement von Java in EBNF

• Runde Klammern regeln Zusammenfassung und Vorrang. Alternativen habenden geringsten Vorrang.

• In der EBNF sind zusatzlich folgende Abkurzungen eingefuhrt: eckige Klammern([ ]) umschliessen Symbolfolgen, die null oder einmal auftreten durfen;geschweifte Klammern ({ }) umschliessen Symbolfolgen, die beliebig oft (auchnull-mal) vorkommen durfen.

• Anschaulich stellt man BNF durch Syntaxdiagrammedar.

• Java in EBNF findet sich unter: http://cui.unige.ch/db-research/Enseignement/analyseinfo/JAVA/

• Beispiele sind in Abb. 7 angegeben. (Hier werden Terminalsymbole inAnfuhrungszeichen angegeben und Nonterminale erscheinen ohne spitzeKlammern.)

• Die eindeutige und vollstandige Beschreibung der Syntax einerProgrammiersprache ist wichtig fur den Programmierer, um syntaktisch korrekteProgramme zu schreiben, und Grundlage fur den Parser.

Informatik B • SS 02 15

else S2S

E2 then S1if

E1 then

S

ifif

else S2

E1 then

S

S

E2 then S1if

Abbildung 8: ‘Danglinge-else’ Uneindeutigkeit

• Ein Parser ist ein Akzeptor fur einen Programmtext. Ein syntaktisch korrektesProgramm wird ein einen Syntaxbaum uberfuhrt. Ein guter Parser gibtinformative Fehlermeldungen, falls das Programm nicht der Grammatik derProgrammiersprache genugt.

• Programmiersprachen sollten syntaktisch eindeutig sein. Das heisst, jede Folgevon Symbolen entspricht genau einem Parse-Baum.

• Wenn Uneindeutigkeiten existieren, werden sie durch Konventionen aufgelost.

• Beispiel: “dangling-else ambiguity”< S >::= if < E > then < S > [else < S >]entspricht den Alternativen:< S >::= if < E > then < S >< S >::= if < E > then < S > else < S >Zu welchem if gehort das else?if E1 then if E2 then S1 else S2

(Parse-Baume siehe Abb. 8)

• Typische Auflosung: Matche else mit dem am nachsten stehenden nochungematchten if. ↪→ Die Kenntnis entsprechender Konventionen sindVoraussetzung fur die Vermeidung von Programmierfehlern!

1.5 Semantik und Pragmatik

• Die formale Beschreibung der Syntax einer Programmiersprache ist relativ leichtnachvollziehbar.

• Ublicherweise verbinden wir durch die Wahl der Schlusselworte bereits eine(intuitive und nicht immer zutreffende) Bedeutung mit den Sprachkonstrukten.Aber: Dem Parser ist es vollig egal, ob im Programm “for” oder “bla” steht,solange er die entsprechende Regel in der Grammatik finden kann!

• Es ist wunschenswert, dass die Semantik einer Sprache genauso eindeutig undprazise beschrieben wird wie die Syntax.

• Nur fur wenige Sprachen ist jedoch eine formale Semantik angegeben (z.B. furdie funktionale Sprache ML). Meistens (z.B. bei Java) wird die Bedeutung derSprachkonstrukte informell naturlichsprachig beschrieben.

16 Informatik B • SS 02

• Fur voll durchformalisierte Sprachen ist es moglich, Korrektheitsbeweisewenigstens zum Teil automatisch durchzufuhren (Spezifikationssprachen wie Z).

• Verschiedene Moglichkeiten, die Semantik einer Sprache formal anzugeben:(siehe Vorlesung “Theoretische Informatik”, Thema Algebraische Spezifikation)

– Operationale Semantik: Regeln, nach denen Ausdrucke ausgewertetwerden (Reduktionssemantik).

– Denotationale Semantik: Interpretation der Sprachkonstrukte in eine“bekannte” Sprache (z.B. Algebra).

– Axiomatische Semantik: Angabe von Gesetzen und Regeln (Hoare Kalkul).

• Spater wird fur einen kleinen Ausschnitt von Java (“Featherweight Java”) dieformale Semantik dargestellt. ↪→ Beweis von Typsicherheit

• Die Pragmatik einer Sprache beschreibt, wie die Konstrukte einer Sprachesinnvoll eingesetzt werden.(Entscheidung, ob eine pre-check-loop (while) oder eine post-check-loop(do-while) verwendet werden soll; Entscheidung zwischen Schleife undrekursiver Losung.)

• Um das, was eine Sprache bietet, optimal auszunutzen, ist genaue Kenntnis desrealisierten Paradigmas sowie der Implementierung der Sprache wichtig!

Informatik B • SS 02 17

2 Java und Objekt-Orientierung

2.1 Grundkonzepte der Objekt-Orientierung

2.1.1 Eigenschaften Objekt-Orientierter Sprachen

(nach Alan Kay, einem der Smalltalk-Entwickler)

• Alles ist ein Objekt: Objekte sind “machtige Daten”. Sie halten Daten undkonnen Operationen auf ihren eigenen Daten ausfuhren. Der “Datentyp” einesObjekts ist die Klasse mit der es erzeugt wurde.Beispiel: Objekt circle vom Typ Circle kann seinen Flacheninhaltberechnen.Anmerkung: In Java ist im Gegensatz zu Smalltalk nicht alles ein Objekt(primitive Datentypen).

• Ein Programm ist eine Menge interagierender Objekte: Ein Objekt kannBotschaften an ein anderes Objekt schicken, z.B. eine Aufforderung, einebestimmte Methode auszufuhren.

• Objekte konnen zu komplexen Objekten kombiniert werden: Komplexe Objektekonnen aus einfachen Bausteinen aufgebaut werden, indem ObjekteReferenzen auf andere Objekte enthalten.

• Alle Objekte eines Typs konnen dieselben Botschaften erhalten: Dies wird vorallem im Hinblick auf Klassenhierarchien interessant. Jedes circle -Objektkann alle Methoden ausfuhren, die in der Circle Klasse definiert sind. IstCircle ein spezieller Shape , so konnen auch (nicht-uberschriebene)Shape -Methoden ausgefuhrt werden.

2.1.2 Prinzipien der Objekt-Orientierten Programmierung

• Zwei wesentliche Prinzipien der objekt-orientierten Programmierung sind↪→ Kapslung (Encapsulation) und↪→Wiederverwendbarkeit (reuse).

• Zur Kapslung gehort die Organisation von Daten und Methoden in Klassensowie das Verstecken von Implementierungsdetails(information hiding).

• Kapslung ist in mehrfacher Hinsicht guter Programmierstil:

– Das Problem wird in kleinere, unabhangige Komponenten gegliedert und istdamit leichter zu uberschauen, leichter zu testen und weniger fehleranfallig.

– Das Verstecken von Implementationsdetails erlaubt eine bessereAustausch von Code. Beispielsweise ist es notwendig zu wissen, dass dieeine Klasse Tree eine Methode insert anbietet, aber nicht, wie insertgenau realisiert ist (z.B. wie gewahrleistet wird, dass der Baumausgewogen ist).

18 Informatik B • SS 02

– Schrankt man zudem die Zugriffsrechte fur Felder ein (z.B. private Feldermit public Zugriffsmethoden) kann man unerwunscht Seiteneffektevermeiden, wie etwa, dass ein zu einer anderen Klasse gehoriges Objektein Feld unkontrolliert andert und moglicherweise Inkonsistenzen erzeugt.

– Neben Klassen dienen Pakete zur Kapslung von Information(Zugriffsrechte). Pakete dienen insbesondere der Strukturierung.

• Wiederverwendbarkeit ist moglich, weil Klassen unabhangig von konkretenDaten definierbar sind. Aussderdem konnen bereits definierte Klassen durchVererbung fur spezielle Bedurfnisse angepasst werden. Generell sollte Code sogeschrieben und dokumentiert werden, dass die Funktionalitat der Klassetransparent ist und so Wiederverwendbarkeit (in eigenen Projekten oderNutzung durch andere) erleichtert wird.

• Java bietet eine Menge vordefinierter Klassen an (Java APIs). Es ist guter Stil,diese (gut getesteten, bewahrten) Klassen zu verwenden.Es ist wichtig, sich einen Uberblick uber die Java APIs zu verschaffen:http://www-lehre.inf.uos.de/manuals/jdk1.4/docs/

2.2 Die Sprache Java

2.2.1 Entstehungsgeschichte

• Start 1990 bei Sun, Gruppe von James Gosling

• Angelehnt an C++, Elemente aus Smalltalk (Bytecode, Garbage Collection) –via Objective C ↪→ objekt-orientiert.Bytecode Compilierung und Garbage Collection sind Konzepte, die ursprunglichim Rahmen von Lisp entwickelt wurden. (Guy Steele, der aus dem BereichCommon Lisp bekannt ist, ist bei Sun mitverantwortlich fur die Entwicklung derJava Sprachspezifikation!)

• Ziel: Entwicklung einer Hochsprache fur hybride Systeme imConsumer-Electronic Bereich: Steuerung von Waschmaschinen,Telefonanlagen, ... ( ursprunglicher Name “Oak”)

• Boom des WWW 1993 ↪→ Einsatz fur Internet-Anwendungen

• Java-Applets: kleine Programme, die in HTML-Seiten eingebunden werdenkonnen (Sun Demo Web-Browser HotJava in den 90-ern)

• Durchbruch 1995: Netscape Navigator 2.0 mit integrierter Java Virtual Machine

• Java-Versionen, siehe Tabelle 1.

• Anmerkung: Java 1 (Java 1.0 und 1.1), Java 2 (ab Java 1.2) bezeichnenVersionen mit vielen neuen Features; Java 1.1, 1.2, 1.3, 1.4 bezeichnetVersionen mit einigen neuen Features; von Java 1.2 zu 1.3 vor allemGeschwindigkeitsverbesserungen; Java 1.1.3 und andere dreistellige Nummernbezeichnen in kleineren Details verschiedene Implementierungen einer Version(“minor releases”).

Informatik B • SS 02 19

Tabelle 1: Java VersionenVersion ≈ # Klassen # Pakete Ersch. Anmerkungen1.0 212 8 Jan. 19961.1 504 23 Feb. 19971.2 1520 59 Dez. 1998 auch “Java 2, Release 1.2”1.3 1840 76 Mai 2000 auch ”Java 2, Release 1.3, Standard Edition”1.4 Feb. 2002 (1.4.0)

2.2.2 Java Buzzwords

Portabel: JVM (virtuelle Maschine ist bewahrtes Prinzip); alle Datentypen sindunabhangig von der Implementierung festgelegt (Standards)

Objekt-Orientiert: Kapslung in Klassen, Vererbung

Multithreaded: Zerlegung in einzelne “Prozesse” (Threads), die unabhangigvoneinander ablaufen konnen

Verteilt: Remote Method Invocation (RMI), Netzwerk-Programmierung basierend aufClient-Server Architekturen

Robust: kein explizites Arbeiten mit Zeigern, Speicherverwaltung wird von Javagehandhabt (Garbage Collection),

Sicher: Plattform erlaubt Laden von unbekanntem Code, der in einer sicherenUmgebung ablauft (kein Lesen und Schreiben von Festplatte, ...)

Dynamisch, Erweiterbar: Organisation des Programmcodes in Klassen, inverschiedenen Dateien gespeichert, load when needed

Internationalisierung: 16-bit Unicode (statt ASCII)

2.2.3 Sprache, Virtuelle Maschine, Plattform

• Java, die Programmiersprache:

– Sprache, in der Java Programme geschrieben werden.

– Compilation in Byte-Code mit javac Dateinamen (inklusive Suffix,.java )

– portable Maschinensprache

– Ausgabe: *.class Datei(en)

– Das Kommando javac erlaubt verschiedene Optionen, wie:

∗ -classpath path : Liste von Verzeichnissen, in denen nach weiterenim Quellcode benutzten Klassen gesucht wird. (default: aktuellesVerzeichnis)∗ -d directory : Verzeichnis, in dem die erzeugten class-Dateien

abgelegt werden . (default: Verzeichnis der *.java Dateien)

20 Informatik B • SS 02

∗ -verbose : Ausgaben des Compilers

– In einer Datei *.java konnen mehrere top-level Klassen definiert werden.Maximal eine davon darf public sein.Fur jede der Klassen wird bei Ubersetzung eine eigene *.class Dateierzeugt.

• Java Virtual Machine (JVM):

– Kann in Hardware oder Software realisiert sein (ublicherw. in Software)

– Interpretation und Ausfuhrung des Byte-Codes; JVM fur Solaris, MicrosoftWindows, Linux, ...

– Interpretersprachen sind meist langsam, ubliche Technik just-in-timeCompilierung, Java: Byte-Code wird in die Maschinensprache dergegebenen Plattform ubersetzt (gute Ausfuhrungsgeschwindigkeit furCode, der mehrfach ausgefuhrt wird)

– Ausfuhrung des Bytecodes Klassenname.class mitjava Klassenname .

– Die entsprechende Klasse muss eine Methode main() mit folgenderSignatur enthalten: public static void main(String[] args) .Diese Methode ist der Einstiegspunkt ins Programm: hier beginnt derInterpreter die Ausfuhrung. Das Programm lauft so lange, bis die mainMethode (und evtl. erzeugte Threads) verlassen werden.

– Das Kommando java erlaubt verschiedene Optionen, wie:

∗ -classpath path : Liste von Verzeichnissen und JAR Dateien, indenen gesucht wird, wenn eine Klasse geladen wird. (Kurzform: -cp )

∗ -D propertyname=value : Setzt eine Property mit Namenpropertyname auf den Wert value. Im Java-Programm konnenProperties dann abgefragt werden.

Hinter dem Klassennamen konnen Daten angegeben werden, die anString[] args weitergegeben werden.

• Java Plattform:

– Vordefinierte Menge von Java Klassen, die auf jeder Java Installationvorhanden sind und von allen Java Programmen genutzt werden konnen

– Klassen sind in Paketen organisiert (Input/Output, Graphik,Netzwerkfunktionen, ...)

– Auch Java Runtime Environment oder Java APIs (Application ProgrammingInterface) genannt.

Informatik B • SS 02 21

2.3 Das 8-Damen Problem Imperativ und Objekt-Orientiert

2.3.1 Problemstellung

• Problem: Plaziere 8 Damen auf einem (8×8) Schachbrett so, dass keine Dameeine andere schlagen kann.

• Eine Dame kann eine Figur schlagen, die in derselben Reihe oder derselbenSpalte oder derselben Diagonale ist.

• Losung(en) fur das 4-Damen Problem:

1 2 3 4

2

1

4

3

2

4

3

1

1 2 3 4

• Allgemein: n× n Problem (n Damen auf n× n Brett)

• Keine Losung fur n ≤ 3.

• Standard-Beispiel fur generate and test Algorithmen (backtracking)

• Aufwand:

– naiv: 8 aus 64 (Binomialkoeffizient n2 uber n)(nk

)=

n!

(n− k)! · k!

fur n = 8: 4.426.165.368

– in jeder Spalte nur eine Dame: nn

fur n = 8: 16.777.216

– in keine Spalte die gleiche Position: n!fur n = 8: 40320

↪→ Problem mit exponentieller Komplexitat!

• Es kann keinen vollstandigen Algorithmus geben, der das Problem effizient lost.Verwendung von heuristischen Suchverfahren bzw.Constraint-Erfullungstechniken (Kunstliche Intelligenz).

• Komplexitat von Problemen wird in der Vorlesung Theoretische Informatikbehandelt

• Aktuelle Literatur zum n-Damen Problem:http://www.liacs.nl/˜kosters/nqueens.html

22 Informatik B • SS 02

2

aufw.

abw.

4

3

1

1 2 3 4

testRow testColumn colDif upRowDif downRowDiftestRow - row row - testRow

1 1 -2 -2 21 2 -1 -2 21 3 0 -2 21 4 1 -2 2. . . . . . . . . . . . . . .4 1 -2 1 -14 2 -1 1 -14 3 0 1 -14 4 1 1 -1

Abbildung 9: Bedrohte Diagonalen

• Sequenz der Anzahl von Losungen:1,0,0,2,10,4,40,92,352,724,2680,14200,73712,365596,2279184,14772512,95815104,666090624,4968057848,39029188884,314666222712,2691008701644,24233937684440eine kompakte Formel wurde bisher nicht gefunden (siehehttp://mathworld.wolfram.com/QueensProblem.html )

2.3.2 Identifikation von Schlagstellungen

• Wenn in jede Spalte genau eine Dame gesetzt wird, dann kann eine Dame mitPosition (row, column) folgende Stellungen bedrohen:

– die Zeile row

– die Aufwartsdiagonale (testColumn − column) = (testRow - row)

– die Abwartsdiagonale (testColumn − column) = (row − testRow)

• Erlauterung: Diagonalen haben eine Steigung von 1 (aufwarts) bzw. −1(abwarts). Das heisst, Spaltendifferenz (Waagerechte) und Zeilendifferenz(Senkrechte) sind identisch.

• Beispiel fur row = 3 und column = 3 in Abb. 9

• Bedrohung auf Diagonalen existiert also, wenn:row + (testColumn − column) = testrow oderrow − (testColumn − column) = testrow

Informatik B • SS 02 23

• Da beidesmal die Spaltendifferenz benotigt wird, kann diese auch vorabberechnet werden.

• siehe Methode predecCanAttack()

• Die von einer Dame bedrohten Positionen konnen global in entsprechendeboolesche Arrays eingetragen werden. Alternativ zum Eintragen undDurchmustern der Arrays konnen die bedrohten Stellungen auch jeweils fur jedeDame gepruft werden.

2.3.3 Imperative Losung

• Im folgenden geben wir Programme zum Finden einer gultigen Losung an.(Alternativ: Finden aller gultigen Losungen )

• Die Anzahl von Queens (MAX) wird als Property uber die −D Option von javagesetzt. Default ist 8.

• Globale Kontrolle: In der main() Methode wird ein Array queens[]spaltenweise mit einer legalen Zeilenposition fur die aktuelle Dame belegt.Existiert fur eine Dame keine legale Position wird die bisherige Losungzuruckgenommen (die Vorgangerdame, evtl. deren Vorganger, etc.) ↪→backtracking

public class QueensIM {final static int MAX = Integer.getInteger("MAX", 8).intValue();

// Current row for queens at columns 0..MAX-1final static int[] queens = new int[MAX]; // initialized with 0s// CAUTION: The "real" column is (array index) + 1!// predecCanAttack() depends on the real chessboard positions// therefore we define an array shift and an advance functionstatic int queens(int i) {

return queens[i-1];}static void advance(int i) {

queens[i-1]++;}

// Test whether a queen (with position row, column)// or any of its predecessors can attack another positionstatic boolean predecCanAttack(int row, int column,

int testRow, int testColumn) {// Case 1: current Queen can attackint columnDifference = testColumn - column;if ((row == testRow) || // same row

(row + columnDifference == testRow) || // same up-diagonal(row - columnDifference == testRow)) // same down-diagonal

return true;

24 Informatik B • SS 02

// Case 2: can neighbor Queen attack?if (column > 1) // there are queens to the left

return predecCanAttack(queens(column-1), column-1,testRow, testColumn);

// Case 3: Position cannot attack, is okreturn false;

}

// Prints the position of all queens via loop through the arraystatic void printSolution() {

for (int i = 1; i <= MAX; i++) {System.out.println(i + " : " + queens(i));

}}

// Global control of positioning of queens.// backtrack if current queen cannnot be positioned without conflictpublic static void main(String[] args) {

int i = 1;while ((i <= MAX) && (i > 0)) { // there are queens to the right

// and backtracking does not go beyond leftmost queenadvance(i); // advance current queen one rowSystem.out.println("Queen in column " + i + " set on row " +

queens(i));if (i > 1)

while ( queens(i) <= MAX &&predecCanAttack(queens(i-1),i-1,queens(i),i) ) {

advance(i);System.out.println("Advance to row " + queens(i));

}if (queens(i) > MAX) {

queens[i-1] = 0; // reset queen, CAUTION: using the array indexi--; // backtrack

} else i++;} // end while (i <= MAX) && (i > 0)printSolution();

}}

2.3.4 Objekt-Orientierte Losung

• Statt einer Klasse mit der Kontrolle in der main() Methode wird nun eineKlasse Queen definiert: Jede Dame kennt ihre eigene Position und kann sichselbst verschieben.

• Dazu existiert eine Dame, die ihre direkte Nachbarin kennt, als Unterklasse vonQueen. Sie kann prufen, ob sie mit dieser in Konflikt steht, sowie diese“anschubsen”.

Informatik B • SS 02 25

public class QueensOO {// Number of Queens set as propertypublic final static int MAX = Integer.getInteger("MAX", 8).intValue();

// Loops from first to last Queen// and tries to generate a solution via backtracking.public static void main(String[] args) {

// The current Queen.Queen lastQueen = new Queen(1);

for (int i = 2; i <= MAX; i++) {lastQueen = new NeighborQueen(i, lastQueen);lastQueen.findSolution();

}lastQueen.printSolution();

}}

class Queen {// data fields// row position of a Queen:// can be changed to obtain a conflict free solution

protected int row;// column position of a Queen: is unchangableprotected final int column;

// Initializes a new Queen object.public Queen (int c) {

row = 1; // always start in first rowcolumn = c;

}

// A single Queen is always at a conflict free position.public boolean findSolution() {

return true;}

// Advance one row if possibleprotected boolean advance() {

if (++row <= QueensOO.MAX)return true;

row = 1; // start again (backtrack) for the current Queenreturn false;

}

// Test whether this Queen can attack another queenprotected boolean predecCanAttack(Queen queen) {

// current Queen can attack

26 Informatik B • SS 02

int columnDifference = queen.column - column;return (row == queen.row) || // same row

(row + columnDifference == queen.row) || // same up-diagonal(row - columnDifference == queen.row); // same down-diagonal

}

// Prints the position of the current Queenpublic void printSolution() {

System.out.println(column + " : " + row);}

}

class NeighborQueen extends Queen {// data fields// immediate left neighbor of a Queenprotected final Queen neighbor;// Initializes a new NeighborQueen objectpublic NeighborQueen (int c, Queen n) {

super(c);neighbor = n;

}

// Tries to advance the Queen to a conflict free position.public boolean findSolution() {

while (neighbor.predecCanAttack(this))if (! advance()) return false;

return true;}

// Advance one row if possible (realizes the backtracking)protected boolean advance() {

return super.advance() ||// test if neighbor advance and findSolution is ok:

neighbor.advance() && neighbor.findSolution();}

// Test whether this Queen// or any of its predecessors can attack another Queen

protected boolean predecCanAttack(Queen queen) {// can current Queen or neighbor Queen attack?return super.predecCanAttack(queen) || neighbor.predecCanAttack(queen);

}

// Prints the position of the current Queen and all predecessorspublic void printSolution() {

neighbor.printSolution();super.printSolution();

}}

Informatik B • SS 02 27

28 Informatik B • SS 02

3 Klassen und ihre Komponenten

3.1 Klassen in Java

• Java als objekt-orientierte Sprache ↪→ Klassen sind die fundamentale Struktur.

• Jedes Java Programm ist als Klasse definiert; alle Java Programme benutzenObjekte.

• Eine Klasse ist die kleinste Einheit an Java-Code, die fur sich allein stehen kannund vom Java-Compiler und -Interpreter erkannt wird

• Jede Klasse definiert einen neuen Datentyp!primitiver Datentyp – Wert (int 42)Klasse – Objekt (Circle ‘Kreis c mit Radius 2’)

• Klasse: Sammlung von Attributen (typisierte Platzhalter fur Daten) und vonProgrammcode (gespeichert in benannten Methoden, die auf diesen Datenarbeiten)

• Klassendefinition: siehe Abb. 7 fur die vollstandige Spezifikation. Im einfachstenFall: class <Name> { <Members> }

• Konvention: Erster Buchstabe des Klassennamens wird gross geschrieben.

• Die erste Zeile der Klassendefinition reprasentiert die “Klassen-Signatur” (vgl.erste Zeile einer Methodendefinition)

• Der Java-Interpreter ladt Klassen dynamisch (dynamic loading): Wenn das ersteMal ein Objekt dieser Klasse erzeugt bzw. eine statische Komponente benotigtwird. Wie der Java-Interpreter die Klassen findet, wird im Abschnitt “Packagesund Java Namespace” dargestellt.

3.2 Members: Felder, Methoden, Klassen

• Member (Komponente): Felder, Methoden und (seit Java 1.1) weitere (innere)Klassen

• Eine Klasse, die nur Felder und keine Methoden definiert, ist lediglich eineSammlung von Daten, ahnlich einem Record (Modula).

• Zentral fur objekt-orientierte Programmierung ist, dass Nachrichten (Methoden)an Empfangerobjekte (Receiver) gesendet werden, die diese dann ausfuhren(a.f() : a ist ein Objekt, das die Nachricht “erledige f() ” empfangt).

• zwei Typen von Members:

– class members: als static deklariert, assoziiert mit Klasse selbst

– instance members: assoziiert mit individuellen Instanzen (Objekten!) derKlasse

Informatik B • SS 02 29

3.3 Beispielcode ‘Circle’

public class Circle {// A class fieldpublic static final double PI = 3.14159; // A useful constant

// A class method: just compute a value based on the argumentspublic static double radiansToDegrees(double rads) {

return rads * 180/PI;}

// An instance fieldpublic double r; // The radius of the circle

// Two instance methods: they operate on the instance fields// of an objectpublic double area() { // Compute the area of the circle

return PI * r * r;}

public double circumference() { // Compute the circumferencereturn 2 * PI * r; // of the circle

}}

3.4 Klassen- und Instanz-Komponenten

3.4.1 Klassen-Felder

public static final double PI = 3.14159;

• assoziiert mit Klasse selbst durch static modifier: Klassen-Feld (static field)

• Es existiert nur eine einzige Kopie eines statischen Feldes!

• Feld vom Typ double mit Namen PI und zugewiesenem Wert 3.14159

• final modifier: Wert des Feldes andert sich nach erster Zuweisung nicht mehr(Konstante)

• public modifier: “jeder” kann das Feld benutzen (visibility modifier)

• lokale Variable/Konstante: innerhalb einer Methode oder eines BlocksFelder: Komponenten einer Klasse!ahnlich einer globalen Variable in einem Programm

• Innerhalb der Klasse Circle kann PI mit seinem einfachen Namen referenziertwerden;ausserhalb: Circle.PI (eindeutige Spezifikation: “das PI, das in Klasse Circledefiniert ist”)

30 Informatik B • SS 02

3.4.2 Klassen-Methoden

public static double radiansToDegrees(double rads) {return rads *

180/PI; }

• assoziiert mit Klasse selbst durch static modifier: Klassen-Methode (staticmethod)

• Aufruf (invocation) von ausserhalb der Klasse:Circle.radiansToDegrees(2.0)oft guter Stil Klassennamen auch innerhalb der Klasse mitanzugeben, um klarzu machen, dass eine Klassen-Methode benutzt wird

• Klassen-Methoden sind “globale Methoden” (in anderen Programmiersprachensind alle Prozeduren/Funktionen global), “imperativer Programmierstil” kann inJava realisiert werden, wenn nur Klassen-Methoden benutzt werden.

• radiansToDegree() ist eine “utility”-Methode, die in Circle definiert ist, weilsie beim Arbeiten mit Kreisen nutzlich sein kann.

• benutzt das Klassen-Feld PI

• Klassen-Methoden konnen alle anderen Klassen-Komponenten der eigenenKlasse (oder auch anderer Klassen) benutzen.

• Klassen-Methoden konnen nicht direkt (mit this ) auf Instanz-Felder oder-methoden zugreifen! (weil die Klassen-Methoden nicht mit einer Instanzassoziiert sind)

3.4.3 Instanz-Felder

public double r;

• Jedes Feld, das nicht static deklariert ist, ist ein Instanz-Feld.

• Instanz-Felder sind mit den Objekten der Klasse assoziiert.

• Jedes Objekt der Klasse Circle hat seine eigene Kopie des Felds r . JederKreis hat seinen eigenen Radius.

• Innerhalb von Klassen werden Instanz-Felder durch ihren Namen referenziert. InCode ausserhalb wird der Name uber eine Referenz zu dem Objekt, das dasFeld enthalt, angegeben.

• Instanz-Felder sind der Kern des objekt-orientierten Programmierens: MitInstanz-Feldern wird ein Objekt (uber seine Eigenschaften) definiert. Die Wertedieser Felder machen Objekte zu unterschiedlichen Identitaten.

Circle c = new Circle(); // Create a new Circle object// store it in variable c

c.r = 2.0; // Assign a value to its instance field rCircle d = new Circle(); // Create a different Circle objectd.r = c.r * 2; // Make this one twice as big

Informatik B • SS 02 31

circle1: Circle circle2: Circle

Circle

PIr

+ radiansToDegrees()+ area()+ circumference()

r=1 r=42

Abbildung 10: Jedes Objekt hat seine eigenen Instanzkomponenten

3.4.4 Erzeugung und Initialisierung von Objekten

• Erzeugung von Objekten mit new

• <Klasse > <name> = new <Konstruktor >

• Ein Objekt mit Namen name vom Typ des Konstruktors (Klasse oderUnterklasse der Klasse) wird erzeugt und durch Aufruf eines Konstruktors furdiese Klasse initialisiert.

• Konstruktoren konnen selbst definiert werden. (Kapitel ‘Konstruktoren undVererbung’)

• Wenn eine Klasse keinen eigenen Konstruktor definiert, dann bekommt sieautomatisch einen Default-Konstruktor ohne Parameter.

3.4.5 Instanz-Methoden

public double circumference() {return 2 * PI * r; }

• Jede Methode, die nicht static deklariert ist, ist eine Instanz-Methode.

• Instanz-Methoden arbeiten auf einer Instanz einer Klasse (auf einem Objekt)und nicht auf der Klasse selbst.

• Instanz-Methoden sind der zweite wesentliche Kern der Objektorientierung.

• Um eine Instanz-Methode ausserhalb der Klasse, in der sie definiert ist, zuverwenden, muss zunachst ein entsprechendes Objekt erzeugt werden.

• Objekte – nicht Funktionen – stehen im Mittelpunkt!(a = area(c) vs. a = c.area() )

• An die Methode area() muss kein Parameter ubergeben werden, weil alleInformationen uber das Objekt implizit in der Instanz c vorhanden sind.

32 Informatik B • SS 02

• Instanz-Methoden konnen auf Klassen- und Instanz-Members zugreifen.In circumference() ist r mit dem Wert aus der gerade betrachteten Instanzbelegt.

Circle c = new Circle(); // Create a new Circle object;// store it in variable c

c.r = 2.0; // Assign a value to its instance field rdouble a = c.area(); // Invoke an instance method of the object

3.4.6 Funktionsweise von Instanz-Methoden: ‘this’

a = c.area();

• area() ist scheinbar parameterlos, aber die Methode hat einen implizitenParameter this .

• this hat als Wert die Referenz auf das Objekt, uber das die Methodeaufgerufen wurde.

• this muss haufig nicht explizit angegeben werden: Wenn eine Methode aufKomponenten zugreift, wird – wenn nichts anderes gesagt wird – angenommen,dass die Komponenten des aktuellen Objekts gemeint sind.

• this kann/sollte explizit angegeben werden, wenn man klar machen will, dassdie Methode auf ihre eigenen Komponenten zugreift.

public double area(){return Circle.PI * this.r * this.r;

}

• this wird explizit benotigt, wenn Parameter oder lokale Variablen einerMethode denselben Namen haben wie Felder. Der Name wird zunachst auflokale Grossen bezogen!

public void setRadius(double r) {this.r = r; //Assign the argument r to the field this.r

}

r = r ist sinnlos: weist Parameter r seinen eigenen Wert zu.

• Klassen-Methoden konnen das this Schlusselwort nicht benutzen! (weil sienicht mit einer Instanz, sondern mit der Klasse assoziiert sind)

3.4.7 Instanz- oder Klassen-Methode?

• Instanz-Methoden sind zentral fur objekt-orientierten Programmierstil.

• Dennoch kann es sinnvoll sein, Klassen-Methoden zu definieren.

Informatik B • SS 02 33

• Design-Entscheidung: Wenn haufig die Flache eines Kreises berechnet werdensoll, aber es ansonsten nicht notwendig ist, dafur extra ein Objekt der KlasseCircle zu erzeugen, sollte area() als Klassen-Methode definiert werden.

• Die Methode kann zweimal definiert sein (hier: einmal als Klassen-, einmal alsInstanz-Methode). Unterscheidung: verschiedene Signaturen!

public static double area(double r){ return PI * r * r;}

• Design-Entscheidung: Wie soll eine Methode realisiert werden, die dengrosseren von zwei Kreisen zuruckliefert?

// Compare the implicit ‘this’ circle to the ‘that’ circle passed// explicitly as an argument and return the bigger one.public Circle bigger(Circle that) {

if(this.r > that.r) return this;else return that;

}

...Circle biggest = c.bigger(d); // Instance method:

// alternatively d.bigger(c)

// Compare circle a to circle b and return the one with the larger radiuspublic static Circle bigger(Circle a, Circle b) {

if(a.r > b.r) return a;else return b;

}

...Circle biggest = Circle.bigger(x,y); // Static method

3.5 Referenztypen

• Klassen (und Arrays) sind Referenztypen. Objekte haben einen bestimmten Typ:

– Circle c = new Circle(); ↪→ c ist ein Objekt vom Typ Circle

– int[] a = {1,2,3,4,5 }; ↪→ a ist ein Array-Objekt

– String s = "Hello"; ↪→ s ist ein String-Objekt

• Array und String haben speziellen Status:

– In der Object -Hierarchie findet sich keine Unterklasse Array : Es gibtpotentiell unendlich viele Arrays (Dimensionalitat, Typ der Elemente). Wiebei der Definition und Erzeugung anderer Objekte steht links der Typ desArrays (Dimensionalitat und Typ der Elemente), aber nicht die Lange desArrays! (siehe Vorlesung Informatik A)

34 Informatik B • SS 02

int x = 42;int y = x;Circle c = new Circle();c.r = 2.0;Circle d = c;

c

d

2411

2412

4711

4711

4711

x

y

1124

1125

42

42

Objectr=2.0

Abbildung 11: Kopieren von Werten/Referenzen

– Fur String kannn ein Objekt direkt initialisiert werden: Text vom Typ String(Zeichen in doppelten Anfuhrungszeichen) kann direkt an eine Variablevom Typ String zugewiesen werden.

• Primitive Datentypen: feste, bei Deklaration bekannte Grosse (z. B. intbekommt 32 Bit)Klassen und Arrays: sind zusammengesetzte Typen (composite types), fur diekeine Standardgrosse angegeben werden kann und die haufig mehrSpeicherplatz benotigen ↪→ Manipulation by reference

• Referenz: fester Wert (Speicheradresse), der auf das Objekt verweistZuweisung eines Objekts an eine Variable: Variable halt Referenz auf diesesObjekt; Ubergabe eines Objekts als Parameter: Methode erhalt die Referenz,uber die das Objekt manipuliert werden kann.

• null Referenz: Referenz auf “Nichts”, Abwesenheit einer Referenz; Wert nullkann an jede Variable fur einen Referenztyp zugewiesen werden.

• Java erlaubt keine explizite Manipulation von Referenzen.

• Wichtiger Unterschied zwischen primitiven Datentypen und Referenztypen:Kopieren von Werten und Prufung von Gleichheit.

3.5.1 Kopieren von Objekten (und Arrays)

• Fur die int-Variablen x und y existieren zwei Kopien des 32-bit Integers 42.

• Variable d enthalt eine Kopie der Referenz, die in Variable c steht. Man sprichthier auch von aliasing.

• Achtung: Wenn zwei Referenzen a und b auf dasselbe Objekt zeigen, kann einMethodenaufruf (z.B a.f() ) an das eine Objekt den Wert eines Feldes andern(“calling a method for its side effects”). Das Feld ist dann beim Objekt geandert.Sowohl a.feld als auch b.feld liefern den aktuellen Wert!

• Eine Kopie des Circle Objekts in der Java VM, aber zwei Kopien der Referenzauf dieses Objekt!

Informatik B • SS 02 35

System.out.println(c.r); // Print out radius of c: 2.0d.r = 4.0; // Change radius of dSystem.out.println(c.r); // Print out radius of c again: 4.0

• Kopieren des Objektes selbst: clone()

• Objekte mussen zu einer Klasse gehoren, die als Cloneable deklariert ist(Implementieren des Cloneable -Interfaces und der clone() -Methode)

• Arrays sind immer Cloneable

• clone() erzeugt eine flache (“shallow”) Kopie: alle primitiven Werte undReferenzen werden kopiert. Das heisst, Referenzen werden nicht ge-cloned!↪→ rekursives Kopieren muss explizit implementiert werden.

• Casting ist notwendig (clone() liefert Object )

int[] data = {1,2,3,4,5}; // An arrayint[] copy = (int[]) data.clone(); // A copy of the array

int[][] data = {{1,2,3},{4,5}}; // Array of 2 refsint[][] copy = (int[][]) data.clone(); // Copycopy[1] = new int[]{7,8,9}; // this does not change data[1]copy[0][0] = 99; // this changes data[0][0] too!

int[][] data = {{1,2,3},{4,5}}; // Array of 2 refsint[][] copy = new int[data.length][]; // new array to hold copied arraysfor (int i = 0; i < data.length; i++)

copy[i] = (int[]) data[i].clone();

3.5.2 Gleichheit von Objekten (und Arrays)

• Bei primitiven Werten pruft der == Operator, ob sie denselben Wert haben (beiganzzahligen Werten: gleiche Bits).Bei Referenztypen pruft ==, ob zwei Referenzen auf dasselbe Objekt verweisen,aber nicht, ob zwei Objekte denselben Inhalt haben!

• Prufung der Gleichheit von Inhalten von Objekten (nicht bei Arrays): equals()Methode ist in Object definiert (default ist ==) ↪→ Methode in eigener Klasseentsprechend uberschreiben (z.B. in String gemacht)

• Anmerkung: zur Unterscheidung “equals” fur Gleichheit von Referenzen und“equivalent” fur Gleichheit von Inhalten verschiedener Objekte. Die Benennungder Methode equals ist etwas ungunstig.

• bei Arrays: java.util.Arrays.equals() (ab Java 1.2)

// A class method for Circle replacing the instance method equals() in Objectpublic static boolean equals (Circle c, Circle d) {

return c.r == d.r;

36 Informatik B • SS 02

1 3 4 52

1 32

4 5

int[ ] data = {1,2,3,4,5}

int[ ][ ] data = {{1,2,3}, {4,5}}

data

data

Abbildung 12: Arrays sind Referenztypen

Circle c = Circle();c.r = 2.0;Circle d = Circle();d.r = 2.0;if (c == d) System.out.println("equal"); // but c and d are not equalif (Circle.equals(c,d)) System.out.println("equivalent");

// c and d are equivalent

3.6 Wrapper-Klassen

• Problem: Array ist ein Container fur primitive Typen wie beliebige Objekte.Manchmal mochte man primitive Typen vielleicht in anderen Datenstrukturenspeichern (Vector aus den Java Collection Classes in java.util ). DieseKlassen sind fur Object definiert, aber nicht fur primitive Typen.

• Losung: Einpacken von primitiven Typen in korrespondierende Klassen(Wrapper) – Boolean, Byte, Short, Integer, Long, Character, Float, Double

• Dort werden Konstanten und nutzliche (statische) Methoden definiert.

// java.lang.Integerpublic Integer(String s) throws NumberFormatException;public Integer(int value);public static int parseInt(String s) throws NumberFormatException;public int compareTo(Integer anotherInteger);

Informatik B • SS 02 37

String s = "-42";int i = Integer.parseInt(s); // class methodInteger j = new Integer(-50); // create new Integer Objectint t = j.compareTo(new Integer(i)); // instance method

// >0 if j>i, <0 if j<i, 0 if j=i

3.7 Dokumentation mit ‘javadoc’

Wenn Programm und Kommentar sich widersprechen, sind vermutlichbeide falsch.

• In Java gibt es folgende Kommentare:

/* Dies ist ein Kommentar* der uber mehrere Zeilen gehen kann.* H&auml;ufig markiert man die zum Kommentar* gehoerigen Zeilen* einleitend ebenfalls mit einem Stern*/

int i = 0; // hier ist ein Zeilenkommentar

Zwischen /* und */ eingeschlossener Text wird vom Compiler ignoriert. DerDoppel-Slash markiert alles dahinter bis zum Zeilenende als Kommentar.

• Eine dritte Moglichkeit, Kommentare zu schreiben, hat die Form/** von javadoc extrahierbarer Kommentar */ .

• Programm javadoc erzeugt API Dokumentation im HTML-Format.

javadoc [options] packages | sourcefiles | @lists

(Angegeben werden mussen entweder Pakete oder Quelldateien oder Namenvon Dateien mit Paket- oder Dateinamen.)

• Optionen, z.B:-author Information hinter @author wird in die Dokumentation eingetragen-private alle Klassen und Komponenten werden in der Dokumentationberucksichtigt. (meist nicht sinnvoll, information hiding)-classpath Pfad fur Klassen- und Sourcefiles-header Text, der oben in jeder doc-Datei erscheint

• Mit javadoc *.java wird eine Dokumentation fur alle Klassen im aktuellenVerzeichnis erstellt.

• javadoc benutzt den Java-Compiler und integriert alleDokumentationskommentare.

• Dokumentationskommentare konnen HTML-Tags enthalten, z.B.<tt>Classname</tt> . Allerdings sollten keine <A> Tags verwendet werden.(besser den speziellen {@link} Tag).

38 Informatik B • SS 02

• Weitere Schlusselworter:@author @version @seeempfehlenswert fur Methoden: @paramund @return .

• Unter anderem wird eine Datei index.html angelegt, in der eine Ubersichtuber alle Klassen gegeben wird.

• siehe zum Beispiel http://www.vorlesungen.uos.de/informatik/b02/code/shapes/doc/index.html .

/*** Simple example class for demonstrating* class (static) components and* instance components.* see Java in a Nutshell, 3rd Edition, chap. 3** @author Ute Schmid* @version Vorlesung InfoB SS 02*/

public class Circle {/** A class field for the constant PI */public static final double PI = 3.14159;

/** A class method: compute degrees from radians* @param rads the radians in double* @return rads * 180/PI*/

public static double radiansToDegrees(double rads) {return rads * 180/PI;

}

/** A class method which computes the area of a circle with* given radius. (also exists as instance method)* @param nr radius of a circle* @return PI * nr * nr*/

public static double area(double nr) {return PI * nr * nr;

}

/** An instance field representing the radius of the circle */public double r;

/** An instance method which returns the area of the circle object* @return PI * r * r*/

public double area() { // Compute the area of the circlereturn PI * r * r; // also Circle.Pi, this.r

}

Informatik B • SS 02 39

/** An instance method which returns the circumference of the circle object* @return 2 * PI * r*/

public double circumference() {return 2 * PI * r;

}

/** An instance method which returns the bigger of the current and* another Circle* @param that a Circle object* @return <code>this</code> if the current circle has a larger radius,* <code>that</code> otherwise*/public Circle bigger(Circle that) {

if (this.r > that.r) return this;else return that;

}}

3.8 Packages und Namespace

• Paket: Organisation von Klassen; Konzept, um eindeutige Klassennnamen zugarantieren; Achtung: Pakete sind nicht mit Modulen zu verwechseln(Diskussion im Kapitel ‘ADTs’)

• Namespace: Menge von einzigartien Namen.

• Die Organisation von Klassen in Pakete wird vor allem beim Erstellen grossererProgramme interessant (Strukturierung und Kapslung); ThemaSoftware-Engineering (Vorlesung Informatik C)

• Die von Java zur Verfugung gestellten Klassen sind in Paketen organisiert. Umdiese Klassen in eigenen Definitionen zu nutzen, wird ein grundlegendesVerstandnis von Paketen und Namensraumen benotigt.

• Sichtbarkeitsmodifikatoren sind mit dem Paket-Konzept von Java verknupft.Dieses Thema wird im Kapitel ‘Konstruktoren und Vererbung’ besprochen.

3.8.1 Java API

• Das API (Application Programming Interface) wird als Teil des JRE (JavaRuntime Environment) zur Verfugung gestellt und enthalt alle Pakete.

• z.B. /usr/lib/jdk1.3/jre/lib/rt.jar*.jar ist eine spezielle Art der Archivierung (vgl. *.zip und *.tar ). DerInhalt einer name.jar Datei kann mit jar tvf name.jar angezeigt werden.

• Auf alle (zugreifbaren) Komponenten von Klassen kann mit demvoll-qualifizierten Klassennamen zugegriffen werden.

40 Informatik B • SS 02

Beispiel System.out.println("Hello World!");

• Durch eine import Anweisung kann mit dem einfachen Klassennamenzugegriffen werden.

• z.B. import java.io.*; : alle Klassen des I/O-Pakets, importjava.io.InputStream; : Klasse InputStream des I/O-Pakets.

• Warnung: undifferenzierter Import mit .* birgt die Gefahr von ungewolltenKollisionen!

• java.lang (core API) wird automatisch importiert.

System.out.println("Hello World!");

• System ist eine Klasse (genauer java.lang.System ).

• out ist ein Klassen-Feld von System (vom Typ java.io.Printstream ).

• System.out verweist auf ein Objekt.

• Das Objekt hat eine Instanz-Methode println() .

• Man kann es nicht oft genug sagen:

– Eines der wichtigen Konzepte der Objekt-Orientierung ist reuse, also dieNutzung bereits vorhandener (getesteter) Klassen bei der Entwicklung vonneuen Klassen.

– Es ist empfehlenswert, sich einen Uberblick uber die vom API zurVerfugung gestellten Klassen zu verschaffen, und diese vordefiniertenKlassen auch zu verwenden!

– Beispielsweise muss man sich einen Stack nicht selber schreiben, sondernkann die entsprechende Klasse aus java.util verwenden.

– Am besten orientiert man sich uber die “Java 2 Platform API Specification”(z.B. http://www-lehre.inf.uos.de/manuals/jdk1.4/docs/api/overview-summary.html )

3.8.2 Packages und Namespaces in Java

• Jede Klasse hat einen einfachen Namen, z.B. Circle oder InputStream ,sowie einen voll-qualifizierten Namen, z.B. java.io.InputStream .

• Indem man als erstes die Anweisung package <name>; in einer Dateischreibt, bestimmt man, dass alle Klassen in dieser Datei zum Paket <name>gehoren.

• Beispielsweise gehort die Klasse InputStream zum Paket java.io .

• Eine Datei, in der eine Klasse definiert wird, kann also vor der Klassendefinitionnoch eine Paket-Definition (als aller erstes, ausser Kommentar) sowie beliebigviele Import-Anweisungen enthalten:

Informatik B • SS 02 41

0 Wed Oct 25 05:30:36 CEST 2000 java/lang/1428 Wed Oct 25 05:30:34 CEST 2000 java/lang/Object.class

11661 Wed Oct 25 05:30:34 CEST 2000 java/lang/String.class155 Wed Oct 25 05:30:34 CEST 2000 java/lang/Comparable.class

7193 Wed Oct 25 05:30:34 CEST 2000 java/lang/Class.class325 Wed Oct 25 05:30:34 CEST 2000 java/lang/CloneNotSupportedException.class291 Wed Oct 25 05:30:34 CEST 2000 java/lang/Exception.class

1559 Wed Oct 25 05:30:34 CEST 2000 java/lang/Throwable.class...

113 Wed Oct 25 05:30:36 CEST 2000 java/io/Serializable.class293 Wed Oct 25 05:30:36 CEST 2000 java/io/IOException.class

4064 Wed Oct 25 05:30:36 CEST 2000 java/io/ObjectStreamField.class1401 Wed Oct 25 05:30:36 CEST 2000 java/io/InputStream.class4463 Wed Oct 25 05:30:36 CEST 2000 java/io/PrintStream.class

880 Wed Oct 25 05:30:36 CEST 2000 java/io/FilterOutputStream.class740 Wed Oct 25 05:30:36 CEST 2000 java/io/OutputStream.class

4398 Wed Oct 25 05:30:36 CEST 2000 java/io/PrintWriter.class...

Abbildung 13: Ausschnitt aus ’rt.jar’

package mypackage;

import java.io.InputStream;import java.util.Stack;

public class MyClass {// definition

}

• Gibt man fur eine Datei keine Paket-Anweisung an, so gehoren alle dortdefinierten Klassen zu einem default (unbenannten) Paket.

• Im Allgemeinen bestehen Pakete aus mehreren Klassen.

• Die Klassen eines Pakets stehen in einem gemeinsamen Verzeichnis.

• Das Verzeichnis muss denselben Namen wie das Paket haben.

• Vorteile:

– Mehr Ubersicht und Ordnung in den Dateien.

– Einzigartige, voll-qualifizierte Klassennamen!Durch Java-Konvention: Der erste Teil des Paket-Namens ist derumgedrehte Internet-Domain-Name des Nutzers, der die Klasse erzeugt.

• Wenn ein Java-Programm lauft und eine Klasse (*.class ) geladen werden soll(dynamic loading), wird der Paket-Name in einen Verzeichnisnamen (Pfad)aufgelost.

42 Informatik B • SS 02

• Um die entsprechenden absoluten Pfade zu finden, schaut der Java-Interpreterin der Variable CLASSPATHnach:

– Diese Variable wird ublicherweise uber das Betriebssystem gesetzt.

– Es ist nutzlich, eigene Makefile s zu schreiben, in denen die konkretbenotigten Klassenpfade angegeben sind (Ubung!)

3.8.3 Namens-Kollisionen

• Was passiert, wenn zwei Pakete importiert werden, die Klassen mit demselbenNamen enthalten?

import java.util.*; // enthaelt Vectorimport mycollection.*; // enthaelt Vector

• Zunachst: nur potentielle Kollision.Der Compiler beschwert sich nicht, solange die Klasse Vektor nicht genutzt wird.Erst wenn versucht wird, ein Objekt der Klasse Vector zu erzeugen, meldet derCompiler das Problem.

• Losung: java.util.Vector v = new java.util.Vector();kennzeichnet eindeutig, welche Klasse gemeint ist.

• Anmerkung: Der Compiler ersetzt alle Klassennamen durch ihrevoll-qualifizierten Namen.

3.8.4 Verhaltensanderungen

• Achtung: Wenn via import Klassen genutzt werden, so kann das eigeneProgramm sein Verhalten verandern, wenn die Definitionen einer importiertenKlasse geandert wurden.

• Wenn die importierten Klassen nicht selbstgeschrieben sind, kann dies, wennes dumm lauft, unbeabsichtigt sein und zu Fehlern in der eigenen Klasse fuhren!

• Guter Stil ist es, dass solche Klassen und Komponenten, die offentlich zurVerfugung gestellt werden, eine klar definierte und dokumentierte Schnittstelle(Art und Anzahl der Parameter, Ruckgabewert) haben und dass dieFunktionalitat/Semantik der offentlich zur Verfugung gestellten Klassen nicht(bzw. nicht ohne alle Nutzer zu informieren) geandert wird.

• Thema: Software-Engineering

• Verfolgen, welche Klassen fur ein Programm geladen werden mitjava -verbose CircleTest (kleiner Ausschnitt in Abb. 14)

Informatik B • SS 02 43

$ java -verbose CircleTest[Opened /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.lang.Object from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.io.Serializable from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.lang.Comparable from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.lang.String from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.lang.Class from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded java.util.Dictionary from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.util.Map from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.util.Hashtable from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.util.Properties from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded java.io.ObjectStreamField from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded java.security.AccessController from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded sun.io.ByteToCharConverter from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded sun.io.Converters from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded sun.misc.Launcher from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.net.URLStreamHandlerFactory from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded sun.misc.Launcher$Factory from /usr/lib/jdk1.3.1/jre/lib/rt.jar]...[Loaded com.sun.rsajca.Provider from /usr/lib/jdk1.3.1/jre/lib/sunrsasign.jar]...[Loaded CircleTest][Loaded Circle][Loaded java.lang.FloatingDecimal from /usr/lib/jdk1.3.1/jre/lib/rt.jar][Loaded java.lang.Math from /usr/lib/jdk1.3.1/jre/lib/rt.jar]Circle c Radius: 2.0Circle d Radius: 4.0Radius of bigger of c and d: 4.0Circle c Radius: 6.0[Loaded java.lang.Shutdown$Lock from /usr/lib/jdk1.3.1/jre/lib/rt.jar]

Abbildung 14: Der Java-Interpreter ladt die core API-Klassen, weitere Klassen werden dyna-misch dazugeladen

44 Informatik B • SS 02

4 Konstruktoren und Vererbung

4.1 Konstruktoren

• Im Allgemeinen sind Konstruktoren spezielle Funktionen zur Erzeugung vonObjekten.

• In der funktionalen Programmierung und in der Typtheorie ist ein Konstruktor einSymbol, mit dem ein Objekt eines algebraischen Datentyps erzeugt wird.

– Beispiel in ML:

datatype ’a list = nil | :: of ’a * ’a list

– Ausdrucke uber Konstruktoren werden nicht reduziert (durch Ergebnis derFunktionsanwendung ersetzt); sie sind bereits in Normalform.

– Beispiele fur ML-Listen mit Typvariable ’a als Integer:nil, 1::nil, 2::(1::nil)

– Algebraische Datentypen heissen abstrakte Datentypen, wenn sie ihreKonstruktoren nicht “nach aussen” weitergeben. Objekte eines abstraktenDatentyps konnen nur mit speziellen Funktionen, die fur diesen ADT (imselben “Modul”) definiert wurden, manipuliert werden.

• In der objekt-orientieren Programmierung wurde der Begriff “Konstruktor” mitC++ eingefuhrt:

– Ein Konstruktor wird von einer Klasse zur Verfugung gestellt und dient derInitialisierung eines Objekts.

– In C++ und Java haben Konstruktoren denselben Namen wie die Klasse.

– Da ein neues Objekt fast immer uber einen Konstruktoraufruf erzeugt wird,kann die Initialisierung nicht vergessen werden.

– Als Gegenstuck konnnen Destruktoren definiert werden, die die vomObjekte gehaltenen Ressourcen freigeben.

– Java hat das Konstruktor-Konzept ubernommen. Destruktoren sind kaumnotwendig, da Java mit Garbage Collector arbeitet.

4.1.1 Definition von Konstruktoren

• Wird fur eine Klasse kein Konstruktor definiert, so wird ein Default Konstruktor(auch “no-arg constructor”) angelegt.

• Der Default Konstruktor hat denselben Namen wie die Klasse, keine Argumenteund keinen Ruckgabetyp (auch nicht void ).

• Alle Konstruktoren haben implizit eine Referenz zum neu erzeugten Objekt(this ) als Argument.

Informatik B • SS 02 45

• Im Konstruktor-Korper werden die Initialisierungen des this -Objektsvorgenommen.

Beispiel: Radius eines Circle -Objekts kann bei der Erzeugung initialisiert werden

public Circle(double r) { this.r = r; }...Circle c = new Circle(2.0);

• Die Variable c ist vom Typ Circle . Sie wird mit einem neuen Circle -Objektmit Radius 2 belegt (genauer mit dem Verweis auf dieses Objekt).

4.1.2 Definition mehrerer Konstruktoren

• Moglichkeit, Objekt auf verschiedene Art zu initialisieren.

• Beispiel: Initialisierung eines Circle -Objekts mit spezifischem Radius oder mitDefault-Wert.

public Circle() { r = 1.0; }public Circle(double r) { this.r = r; }

• Wie bei Methoden gilt overloading: gleicher Name aber unterschiedlicheSignaturen (Anzahl und Typ der Argumente). (Overloading wird im Kapitel‘Klassenabhangigkeiten’ besprochen)

• Ein Konstruktor kann andere Konstruktoren aufrufen:this() als Konstruktoraufruf; welcher Konstruktor aktiviert wird, hangt wiedervon Anzahl und Typ der Argumente ab.

• Verwendung von this() ist eine gute Strategie, wenn die Konstruktoren Teileder Initialisierung gemeinsam haben

• this() darf nur als erste Anweisung in einem Konstruktor vorkommen. Grund:automatischer Aufruf der Konstruktoren der Oberklasse (Kapitel‘Klassenabhangigkeiten’)

// This is the basic constructor: initialize the radiuspublic Circle(double r) { this.r = r; }// This constructor uses this() to invoke the constructor abovepublic Circle() { this(1.0); }

4.2 Defaults und Initialisierung fur Felder

4.2.1 Defaults

• Lokale Variablen (innerhalb von Methoden definiert) haben keine Default-Werte.Werden lokale Variablen nicht vor ihrer Verwendung initialisiert, liefert derJava-Compiler eine Fehlermeldlung (der C-Compiler nur eine Warnung).

46 Informatik B • SS 02

Tabelle 2: Default-Werte fur Felder

Typ Defaultboolean falsechar ‘ \u0000’byte , short , int , long 0float , double 0.0reference null

• (Klassen- und Instanz-) Felder sind automatisch mit Default-Werten initialisiert.

• Ubliche Deklaration mit Zuweisung eines initialen Wertes ist ebenfalls moglich.

public static final double PI = 3.14159;public double r = 1.0;

4.2.2 Initialisierung von Instanz-Feldern: Konstruktoren

• Der Java Compiler erzeugt Initialisierungscode fur Instanz-Felder und fugt sie inden Konstruktor (oder die Konstruktoren) der Klasse ein.Reihenfolge: die im Programm angegebene (Nutzung von bereits initialisiertenFeldern bei der Initialisierung weiterer Felder moglich).

• Wenn ein Konstruktor mit this() Anweisung beginnt, dann wird in diesenKonstruktor die Initialisierung nicht eingefugt, sondern in denjenigenKonstruktor, der durch this() aktiviert wird.

• ab Java 1.1: Initialisierungsblocke fur Instanz-Felder: { ... } , die anbeliebiger Stelle (an der Komponenten stehen konnen) in die Klasse eingefugtwerden konnen; ublich: direkt nach Feld; benutzt vor allem fur anonyme innereKlassen (kommt spater)

public class TestClass {public int len = 10;public int[] table = new int[len];

public TestClass(){for (int i = 0; i < len; i++) table[i] = i;

}}

Ist aquivalent zu

public class TestClass {public int len;

Informatik B • SS 02 47

public int[] table;

public TestClass() {len = 10;table = new int[len];for (int i = 0; i < len; i++) table[i] = i;

}}

4.2.3 Initialisierung von Klassen-Feldern: Initialisierungs-Blocke

• Klassen-Felder existieren auch dann, wenn kein Objekt erzeugt wird.

• Initialisierung vor Konstruktoraufruf notwendig.↪→ Java Compiler erzeugt automatisch eine Klassen-Initialisierungs-Methode furjede Klasse (interne, versteckte Methode <clinit >), in der alleKlassen-Felder initialisiert werden. Diese Methode wird genau einmalausgewertet, namlich wenn die Klasse das erstemal benutzt (geladen) wird.

• Initialisierung wieder in der im Programm angegebenen Reihenfolge.

• Explizite Initialisierung von Klassen-Feldern mit static initializer Block:static { ... } , der an jeder Stelle der Klasse stehen kann, wo

Komponenten stehen konnen.

• Es kann mehrere solche Initialisierungs-Blocke geben.

• Initialisierungs-Blocke werden vom Compiler in dieKlassen-Initialisierungs-Methode integriert.

• Statische Initialisierung ist wie eine Klassen-Methode, also keine Verwendungvon this moglich, keine Nutzung von Instanz-Komponenten moglich.

// We can draw the outline of a circle using trigonometric functions// Trigonometry is slow, though, so we precompute a bunch of valuespublic class TrigCircle {// Here are our static lookup tables and their own simple initializersprivate static final int NUMPTS = 500;private static double sines[] = new double[NUMPTS];private static double cosines[] = new double[NUMPTS];

// Here’s a static initializer that fills in the arraysstatic {

double x = 0.0;double delta_x = (Circle.PI/2)/(NUMPTS-1);for (int i = 0; i < NUMPTS; i++, x += delta_x) {

sines[i] = Math.sin(x);cosines[i] = Math.cos(x);

} } }

48 Informatik B • SS 02

4.3 Zerstoren und Finalisieren von Objekten

4.3.1 Garbage Collection

• Mit new werden neue Objekte erzeugt (und dynamisch, zur Laufzeit auf demheap abgelegt)Anmerkung: Werte primitiver Datentypen (bei lokalen Variablen) werdendagegen statisch, auf dem Stack abgelegt, dessen Grosse bereits zurCompilezeit bestimmt wird.

• Wenn ein Objekt nicht langer benutzt wird, wird der Speicherplatz automatischfreigegeben (garbage collection, alte Technik, ursprunglich in Lisp entwickelt)

• Der Java Interpreter weiss, welche Objekte und Arrays er angelegt (allocated)hat, und kann ermitteln, welche Objekte und lokale Variablen auf andereObjekte verweisen. Wenn kein Verweis auf ein Objekt existiert, kann es zerstortwerden; dito fur nicht mehr referenzierte Verweis-Zyklen.

• Der Garbage Collector lauft immer im Hintergrund als low priority thread(Multi-Threading wird spater behandelt); wird im Normalfall immer aktiv, wennnichts Wichtiges passiert (z.B. beim Warten auf Input), ausser: wenn kaum nochfreier Speicher vorhanden ist.

• Garbage Collection kann nie so effizient sein wie gute selbstgeschriebeneSpeicherverwaltung (free() , delete ); aber es verhindert Fehler (z.B. memoryleaks) und erlaubt schnellere Entwicklung von Code.

• Memory leaks konnen in Java so gut wie nicht passieren (Ausnahmen: lokaleVariablen in Methoden, die lange Ausfuhrungszeiten haben und dabei nicht aufdiese Variablen zugreifen; Objekte mit Referenzen in Hash-Tabellen werden erstzerstort, wenn die Hash-Tabelle selbst zerstort wird).

4.3.2 Anmerkung: Finalization

• Freigabe von bestimmten Resourcen, die ein Objekt benutzt, wird nicht vomGarbage Collector erledigt (z.B. temporare Dateien loschen)

• Finalizer ist Instanz-Methode, Gegenstuck zu Konstruktor (“Destruktor”); wirdvom Garbage Collector aufgerufen; keine Argumente, kein Ruckgabewert

• Es darf nur einen Finalizer pro Klasse geben.

• protected void finalize()

• Selbstgeschriebene Klassen benotigen selten explizite Finalizer (Ausnahmenative finalize fur Schnittstellen zu Code, der nicht unter Kontrolle desGarbage Collectors ist)

Informatik B • SS 02 49

Birdhas wingscan flyhas feathers

Fishhas finscan swimhas gills

Animal

has skincan move aroundeatsbreathes

Ostrichhas thin long legsis tallCanary

is yellow

can singShark

can bite

is dangerousSalmon

is pinkis edible

swims upriverto lay eggs

can’t fly

Abbildung 15: Illustration eines hierarchischen semantischen Netwerks

4.4 Unterklassen und Vererbung

4.4.1 Exkurs: Hierarchische Semantische Netze

• Der Teachable Language Comprehender (TLC) von Collins und Quillian (1969)ist ein fruhes (implementiertes) kognitives Modell zum semantischenGedachtnis. (siehe Abb. 15)

• Psychologische Experimente: Antwortzeiten bei Entscheidungsfragen“A canary eats?” dauert langer als “A canary is yellow?”

• Idee: Wissen ist in hierarchischem Netz mit Vererbung organisiert (“kognitiveOkonomie”) Antworten dauern um so langer, je weiter man “nach oben” (zuOberklassen) suchen muss, um eine Eigenschaft zu verifizieren.

• “Flache” logische Reprasentation:Klassen und Objekte werden mehrfach reprasentiert!

• Verifikation uber logische Inferenzregeln (Transitivitat)

• “naturlicher”: Jede Klasse existiert genau einmal,Ober-/Unterklassen-Beziehungen werden fur jede Klasse angegeben.

50 Informatik B • SS 02

/* Fakten */isa(canary, bird).isa(ostrich, bird).isa(bird, animal).isa(shark, fish).isa(salmon, fish).isa(fish, animal).has(skin, animal).does(eat, animal)..../* Inferenzregeln */is_a(A,B) :- isa(A,B). /* R1: direkter Fall isa */is_a(A,C) :- isa(A,B), is_a(B,C). /* R2: Transitivitaet von isa *//* analog fuer has, does, ... */

Abbildung 16: Flache Prolog-Realisierung des TLC

class Animal {boolean hasSkin = true;boolean canEat = true;

}

class Bird extends Animal {boolean hasWings = true;boolean canFly = true; // default, gilt nicht fuer alle Voegel

}

class Ostrich extends Bird {Ostrich() { canFly = false; }

}

Abbildung 17: Hierarchie und Vererbung sind naturliche Konzepte in der OO-Programmierung

Informatik B • SS 02 51

4.4.2 Erweiterung von ‘Circle’

• Spezielle Kreise: haben Radius und Position in der Ebene↪→ PlaneCircle als Unterklassevon Circle

• Funktionale Erweiterung von Klassen durch Unterklassenbildung ist zentral furobjekt-orientierte Programmierung

• class <Name> extends <SName> { ... }

• Felder und Methoden der Oberklasse werden automatisch vererbt,Konstruktoren nicht! (In anderen Sprachen werden sinnvollerweise auch dieKonstruktoren vererbt. Dafur kann es dann keine automatisch generiertenDefault-Konstruktoren geben.)

• Unterklassen-Konstruktor kann Konstruktor der Oberklasse durch super()aufrufen (analog zu this() )

public class PlaneCircle extends Circle {// We autmatically inherit the fields and methods of Circle,// so we only have to put the new stuff here.// New instance fields that store the center point of the circlepublic double cx, cy;

// A new constructor method to initialize the new fields// It uses a special syntax to invoke the Circle() constructorpublic PlaneCircle(double r, double x, double y) {

super(r); // Invoke constructor of the superclassthis.cx = x; // Initialize instance fieldsthis.cy = y; // using ‘this’ is not necessary here

}

// The area() and circumference() methods are inherited from Circle// A new instance method that checks whether a point is inside the circle// Note that it uses the inherited instance field rpublic boolean isInside(double x, double y) {

double dx = x - cx, dy = y - cy; // Distance from centerdouble distance = Math.sqrt(dx*dx + dy*dy); // Pythagorean theoremreturn (distance < r); // Returns true or false

}}

4.4.3 Erweiterung einer Klasse

• Vererbung von Feldern (z.B. r )

• Vererbung von Methoden:Methoden der Oberklasse konnen fur Objekte der Unterklasse genutzt werden.

• Zusatzliche Felder und Methoden konnen fur die Unterklasse definiert werden.

52 Informatik B • SS 02

+ isInside

PlaneCircle

cycx

Circle

PIr

+ radiansToDegrees+ area+ circumference

Abbildung 18: Ein Circle und seine Unterklasse

• Jedes Objekt der Unterklasse besitzt alle Instanz-Felder und -Methoden derOberklasse.

• Typkonversion zwischen Unter- und Oberklassen:von Unterklasse zu Oberklasse (upcasting), Objekt wird allgemeiner (verliertZugriff auf spezielle Felder und Methoden) ohne Casting;von Oberklasse zu Unterklasse (downcasting): Casting notwendig (und Prufungzur Laufzeit durch die VM)(vergleiche widening und narrowing bei primitiven Datentypen)

PlaneCircle pc = new PlaneCircle(2.0, 5.0, 5.0);double ratio = pc.circumference() / pc.area();Circle c = pc; // no access to positioningPlaneCircle pc2 = (PlaneCircle) c;boolean origininside = ((PlaneCircle) c).isInside(0.0, 0.0);

4.5 Kapslung und Zugriffskontrolle

• Klassen als Sammlung von Daten und Methoden.

• Wichtige objekt-orientierte Technik: Information-Hiding, Encapsulation(Einkapslung):Daten nur uber Methoden zuganglich machen;Daten und interne (private) Methoden sind sicher in der Klasse eingeschlossenund konnen nur von vertrauenswurdigen Nutzern (also uber ordentlich definierteoffentliche Methoden der Klasse) benutzt werden.

Informatik B • SS 02 53

• Schutz der Klasse gegen absichtliche oder unabsichtliche Eingriffe.z.B. konsistente Belegung von voneinander abhangigen Felder (Sicherung ubersorgfaltig definierte Methoden)

• Verstecken interner Implementations-Details. Andern der Implementation, ohnedass genutzter Code dieser Klasse betroffen ist. (vgl. Theorie der ModularenProgrammierung)

• Offentlich sichtbare Felder und zu viele Methoden machen API unubersichtlichund schwer zu verstehen.

4.5.1 Zugriffs-Kontrolle

(access control)

• Paket-Zugriff : Nicht Teil von Java selbst (Lesbarkeit von Dateien,Verzeichnissen)Paket: ublicherweise in einem Verzeichnis; wenn kein explizites Paketangegeben wird, wird ein unbenanntes Default-Paket generiert.

• Klassen-Zugriff: Default ist, dass top-level Klassen (etwas anderes kennen wirnoch nicht) paket-weit zugreifbar sind. public deklarierte Klassen sind uberall(wo das Paket zugreifbar ist) zugreifbar.

• Zugriff auf Komponenten einer Klasse: Komponenten sind in jedem Fall in derKlasse selbst zugreifbar; Default: paket-weiter Zugriff;Alle Klassen, die zum selben Paket gehoren, durfen zugreifen. Beiunbenanntem Paket typischerweise alle Klassen im selben Verzeichnis(implementationsabhangig).

• Zugriffsmodifikatoren: public , protected , private fur Felder undMethoden.

4.5.2 Vier Ebenen von Zugriffsrechten

Fur Klassen-Komponenten:

• public : von uberall (wo Paket zugreifbar ist) zugreifbar

• protected : paket-weit und aus allen Unterklassen (egal, in welchem Paket siedefiniert sind) zugreifbar

• default: paket-weit zugreifbar (wenn kein Modifikator angegeben)

• private : nur in der Klasse selbst zugreifbar

54 Informatik B • SS 02

Tabelle 3: Zugriffsmodifkatoren

Accessible to public protected ‘package’ privateDefining class yes yes yes yesClass in same package yes yes yes noSubclass in different package yes yes no noNon-subclass in different packageyes no no no

4.5.3 Zugriffs-Kontrolle und Vererbung

• Unterklasse erbt alle Instanz-Felder und -Methoden der Oberklasse. MancheKomponenten sind aufgrund der Einschrankung der Sichtbarkeit nichtzugreifbar.

• Wenn Ober- und Unterklasse im selben Paket: Zugriff auf alle nicht-privatenFelder und Methoden.

• Wenn Ober- und Unterklasse in verschiedenen Paketen: Zugriff auf alle publicund protected Felder und Methoden.

• private Komponenten und Konstruktoren konnen nie ausserhalb der Klassezugegriffen werden.

• In Tabelle 3 ist eine Ubersicht uber die Zugriffsmodifikatoren in Java angegeben.Die Semantik ist leicht verschiedenen zu anderen objekt-orientieren Sprachen(C++). Hinter der einfachen Struktur der Tabelle sind subtile Probleme versteckt(z.B. wie verhalt sich protected , wenn Klasse A und Unterklasse B inverschiedenen Paketen stehen und Klasse B in Klasse A genutzt wird? Wiespielen Casting und Zugriffsmodifikatoren zusammen?)

Beispiel:Circle mit protected r .PlaneCircle (ist Unterklasse) in anderem Paket.Methode in PlaneCircle :

public boolean isBigger (Circle c) {return (this.r > c.r);

}

Compiler-Fehler: Zugriff auf this.r ist erlaubt, da das Feld r von der UnterklassePlaneCircle geerbt wird.Aber: Zugriff auf c.r ist in PlaneCircle nicht erlaubt!

• Ware erlaubt, wennPlaneCircle c anstelle von Circle c , oder wennCircle und PlaneCircle im selben Paket definiert waren. (“Java-Feature”)

Informatik B • SS 02 55

• In Tabelle 3 fehlt die Information uber das Zusammenspiel der Rechte mit demTyp der Referenz. (siehe Ubung)

• In der Regel darf nur auf protected /private Komponenten nur uber eineReferenz der Klasse zugreifen, in der der Zugriff erfolgt.

4.5.4 Daumenregeln fur Sichtbarkeits-Modifikatoren

• Benutze public nur fur Methoden und Konstanten, die den offentlichen Teil desAPI der Klasse darstellen sollen.Kapsle Felder: als privat deklarieren und Zugriff uber public Methoden

• Benutze protected fur Komponenten, die bei der Erzeugung von Unterklassennotwendig sein konnten.Achtung: Anderung von protected Komponenten kann im Code der KlasseInkonsistenzen erzeugen.

• Benutze default Sichtbarkeit fur Komponenten, die interne Implementationrealisieren und von Klassen im selben Paket genutzt werden sollen.Nutzung der package Anweisung, um miteinander kooperierende Klassen inein Paket zu bundeln.

• Sonst benutze private .

Besser zunachst moglichst restriktive Rechte vergeben und erst wenn notig lockern.

4.5.5 Daten-Zugriffs-Methoden

package myshapes; // Specify a package for the class

public class Circle { // The class is still public// This is a generally useful constant, so we keep it publicpublic static final double PI = 3.14159;protected double r; // Radius is hidden, but visible to subclasses

// A method to enforce the restriction of the radius// This is an implementation detail that may be of// interest to subclassesprotected void checkRadius(double radius) {

if (radius < 0.0)throw new IllegalArgumentException("radius may not be negative.");

}

// The constructor methodpublic Circle(double r) {

checkRadius(r);this.r = r;

}

56 Informatik B • SS 02

// Public data accessor methodspublic double getRadius() { return r; }public void setRadius(double r) {

checkRadius(r);this.r = r;

}

// Methods to operate on the instance fieldpublic double area() { return PI * r * r; }public double circumference() { return 2 * PI * r; }

}

• Klasse ist einem Paket zugeordnet (Verzeichnisname gleich dem Paketnamen).

• Methoden sind um Fehlerprufung erweitert (explizite checkXX() Methoden).

• Zugriff auf Werte von Instanz-Feldern erfolgt uber Methoden (setXX() ,getXX() ).Felder, auf die mit set- und get-Methoden zugegriffen wird, werden auchProperties genannt. Man spricht von “Getter”- und “Setter”-Methoden.

Informatik B • SS 02 57

5 Klassenabhangigkeiten

5.1 Klassenhierarchie

5.1.1 Finale Klassen

• Als final deklarierte Klassen konnen nicht erweitert werden.z.B. java.lang.System↪→ Verhindern ungewunschter Erweiterungen(Compiler kann einige Optimierungen vornehmen, siehe spater)

5.1.2 Die Klasse ‘Object’

• Jede Klasse, die definiert wird, hat eine Oberklasse.

• Wenn keine Oberklasse (spezifiziert nach extends ) angegeben wird, dann wirdals Oberklasse java.lang.Object vergeben.

• Object ist eine Klasse mit speziellem Status: einzige Klasse, die keineSuperklasse hat; alle Java Klassen erben die Methoden von Object .

• Vorteil einer solchen “single rooted hierarchy”:

– Bei jedem Objekt ist garantiert, dass es vom Typ Object ist. Damit konnenKlassen/Methoden definiert werden, die auf allen Objekten arbeiten (sieheCollection Klassen) und bestimmte Methoden konnen fur alle Objekteangewendet werden (z.B. toString() ).

– Fur alle Objekte ist via Object garantiert, dass sie sinnvoll mit demLaufzeit-System interagieren (z.B. Garbage Collection)

5.1.3 Klasse ‘String’

• Spezieller Status (wie Array; mit spezieller Syntax).

• Text in doppelten Anfuhrungszeichen kann direkt an eine Variable vom TypString zugewiesen werden.

• Escape-Sequenzen konnen verwendet werden.

• Strings im Quelltext durfen nicht uber Zeilen umgebrochen werden. (Losung:Aufteilen und konkatenieren; Konkatenation konstanter Strings bei Compilation,nicht zur Laufzeit)

String name = "David";System.out.println("Hello\t" + name);String s = "This is a test of the" +

"emergency broadcast system";

58 Informatik B • SS 02

5.1.4 Hierarchische Klassenstruktur

• In Java kann eine Klasse nur genau eine andere Klasse als Oberklasse haben.

• Im Gegensatz zu C++ gibt es keine Mehrfachvererbung ↪→ Datenstruktur:Klassenbaum (nicht Klassenverband)!

• Problem bei Mehrfachvererbung: Existiert dieselbe Komponente in mehr alseiner Klasse, von der geerbt wird, muss geregelt werden, welche dieserKomponenten in die Unterklasse ubernommen wird!

• Beispiel: java.lang.Object ist die Wurzel des Baums. Number stammt vonObject ab; Integer von Number.In Abb. 19 (Quelle:http://rendezvous.com/java/hierarchy/index.html ) zeigen diedurchgezogenen Linien Klassenabhangigkeiten, die gestrichelten Linien zeigendie Implementierung von Schnittstellen (Kapitel ‘Abstrakte Klassen undInterfaces’).

– Boxen mit runden Ecken: Interfaces (Kapitel ‘Abstrakte Klassen undInterfaces’)

– weisse Boxen: Klassen

– hellgraue Boxen: Final

– dunkelgraue Boxen: abstrakte Klassen (Kapitel ‘Abstrakte Klassen undInterfaces’)

Informatik B • SS 02 59

1995-7, Charles L. Perkins http://rendezvous.com/java

Object

Boolean

Character

Class

ClassLoader

Number

Double

Float

Integer

Long

Math

Process

String

StringBuffer

System

ThreadRunnable

ThreadDeath

java.lang

Runtime

SecurityManager

Throwable

Errorjava.lang-errors

ThreadGroup

Exceptionjava.lang-exceptions

Cloneable

Compiler

Serializablejava.io-objects

Byte

FloatingDecimallocal to package

FDBigIntlocal to package

NullSecurityManagerlocal to package

Short

Void

Abbildung 19: Hierarchische Organisation von ‘java.lang’

60 Informatik B • SS 02

5.2 Erganzung: Konstruktoren

5.2.1 Unterklassen-Konstruktoren

PlaneCircle extends Circle

// A new constructor method to initialize the new fieldspublic PlaneCircle(double r, double x, double y) {

super(r); // Invoke constructor of the superclassthis.cx = x; // Initialize instance fieldsthis.cy = y;

}

• super() : Aufruf eines Oberklassen-Konstruktors(analog zu this() : Aufruf eines Klassen-Konstruktors)

• super() kann nur innerhalb einer Konstruktor-Methode benutzt werden

• Aufruf des Oberklassen-Konstruktors muss an erster Stelle in einem Konstruktorstehen (sogar vor der Deklaration lokaler Variablen)

• Argumente, die an super() ubergeben werden, mussen mit der Signatur einesOberklassen-Konstruktors ubereinstimmen. Der entsprechende Konstruktor wirddann ausgewahlt.

5.2.2 Default-Konstruktoren

• Java garantiert, dass immer, wenn eine Instanz einer Klasse erzeugt wird, die(bzw. eine) Konstruktormethode der Klasse aufgerufen wird.

• Wenn die Klasse eine Unterklasse ist, ist ebenfalls garantiert, dass derKonstruktor der Oberklasse aufgerufen wird.↪→ Java muss sicherstellen, dass jede Konstruktormethode eineKonstruktormethode der Oberklasse aufruft.

• Wenn kein expliziert Aufruf angegeben ist, wird der Aufruf des DefaultKonstruktors super() eingefugt.Achtung: Wenn die Oberklasse keinen null-stelligen Konstruktor anbietet, erfolgtein Compiler-Fehler!

• Wenn eine Klasse gar keinen Konstruktor definiert, wird ein null-stelligerDefault-Konstruktor erzeugt:public Klassen erhalten public Konstruktoren; alle anderen Klassen erhaltenden default Konstruktor ohne Sichtbarkeits-Modifikator.

• Um zu verhindern, dass ein public Konstruktor eingefugt wird, solltemindestens ein nicht-public Konstruktor definiert werden.Fur Klassen, die nicht instantiiert werden sollen, sollte ein private Konstruktordefiniert werden (kann nicht von ausserhalb der Klasse aufgerufen werden,verhindert automatische Einfuhrung eines default-Konstruktors.)(spater: abstrakte Klassen)

Informatik B • SS 02 61

5.2.3 Konstruktor-Verkettung

(constructor chaining)

• Wenn eine neue Instanz eines Objekts zur Klasse Ci erzeugt wird, wird derentsprechende Konstruktor Ci() aufgerufen. Dieser ruft explizit oder implizt denKonstruktor der unmittelbaren Oberklasse Ci−1 auf usw., solange bis derKonstruktor der Klasse Object aufgerufen wird.Die Ausfuhrung ist in umgekehrter Reihenfolge zum Aufruf, also zuerst wirdObject() ausgefuhrt.↪→Wann immer der Korper eines Konstruktors ausgefuhrt wird, istsichergestellt, dass alle Felder der Oberklasse bereits initialisiert sind!

• Anmerkung finalizer chaining: finalize() Methoden werden nichtautomatisch verkettet. ↪→ super.finalize()

5.3 Vererbung: Shadowing und Overriding

5.3.1 Verdecken von Feldern der Oberklasse

(Shadowing)

• Ein etwas konstruiertes Beispiel:Weiteres Instanz-Feld in Klasse PlaneCircle , das die Distanz zwischen demKreismittelpunkt und dem Ursprung (0, 0) angibt, das r genannt wird, alsodieselbe Bezeichnung hat, wie das Feld r (fur Radius) in der OberklasseCircle .

class PlaneCircle extends Circle {public double r;...PlaneCircle(...) { // Pythagorean Theorem

this.r = Math.sqrt(cx * cx + cy * cy);} }

• Zugriff auf Felder der aktuellen Klasse und der Oberklasse:

r // Feld der aktuellen Klassethis.r // ditosuper.r // Feld der Oberklasse

• Alternativ: Cast des Objekts zur entsprechenden Oberklasse.

((Circle) this).r

Klammerung beachten: erst Cast, dann Zugriff auf Feld!

62 Informatik B • SS 02

• Casting ist vor allem hilfreich, wenn auf ein Feld referenziert werden soll, dasnicht in der direkten Oberklasse definiert ist.

• Beispiel: class C extends B , class B extends A und alle drei Klassenhaben ein Feld x ; Innerhalb von C:

x // Field x in class Cthis.x // ditosuper.x // Field x in class B((B)this).x // dito((A)this).x // Field x in class Asuper.super.x // Illegal Syntax

• Zugriff auf x einer Instanz von C

C c = new C();c.x // Field x of class C((B)c).x // Field x of class B((A)c).x // Field x of class A

(Haufig sinnvoller: andere Variablennamen verwenden.)

5.3.2 Shadowing von Klassen-Feldern

• Klassen-Felder konnen ebenfalls uberdeckt werden

• Beispiel: exakteres PI in PlaneCircle

public static final double PI = 3.14159265358979323846;

Innerhalb von PlaneCircle :

PI // Field PI in class PlaneCirclePlaneCircle.PI // ditosuper.PI // Field PI in class CircleCircle.PI // dito

Achtung: Innerhalb der Methoden area() und circumference() , die inCircle definiert sind, wird immer auf Circle.PI referenziert, auch wenndiese Methoden innerhalb von PlaneCircle oder von einemPlaneCircle -Objekt benutzt werden!

Informatik B • SS 02 63

5.3.3 Uberschreiben von Instanz-Methoden der Oberklasse

(Overriding)

• Wenn in einer Klasse eine Instanz-Methode definiert wird, die dieselbe Signatur(Name, Parameter) hat wie eine Methode der Oberklasse, wird die Methode derOberklasse uberschrieben:Wenn die Methode bei einem Objekt der Klasse aufgerufen wird, dann wird dieneue Methodendefinition aktiviert.

• Uberschreiben von Methoden ist eine wichtige Technik der objekt-orientiertenProgrammierung.

• Klassen-Methoden werden nicht uberschrieben sondern nur uberdeckt.<Klasse >. <methode >() , <OberKlasse >. <methode >() haben in jedemFall verschiedene Namen

• Etwas konstruierte Erweiterung des Circle -Beispiels: Ellipse als Unterklassevon Circle mit neuer Definition von area() und circumference() .Es ist wichtig, dass fur ein Objekt der Klasse Ellipse immer die neuenMethoden zur Berechnung verwendet werden!

5.3.4 Uberschreiben vs. Verdecken

class A { // Define a class named Aint i = 1; // An instance fieldint f() { return i; } // An instance methodstatic char g() { return ’A’; } // A class method

}class B extends A { // Define a subclass of A

int i = 2; // Shadows field i in class Aint f() { return -i; } // Overrides instance method f in Astatic char g() {return ’B’; } // Shadows class method g in A

}

public class OverrideTest {public static void main (String[] args) {

B b = new B(); // Creates new object of type BSystem.out.println(b.i); // Refers to B.i; prints 2System.out.println(b.f()); // Refers to B.f(); prints -2System.out.println(b.g()); // Refers to B.g(); prints BSystem.out.println(B.g()); // This is a better way to invoke B.g()

A a = (A)b; // Casts b to a reference to class ASystem.out.println(a.i); // Now refers to A.i; prints 1System.out.println(a.f()); // Still refers to B.f(); prints -2System.out.println(a.g()); // Refers to A.g(); prints ASystem.out.println(A.g()); // This is a better way to invoke A.g()

} }

64 Informatik B • SS 02

• Unterschied zwischen Uberschreiben von Instanz-Methoden und Uberlagernvon Feldern (und Klassen-Methoden) macht Sinn:Fur ein Objekt sollen auf jeden Fall seine spezifischen Methoden angewendetwerden.(Beispiel: Array von Circle -Objekten, von denen manche Circle - undmanche Ellipse -Objekte sind. Methoden zur Berechnung von Flacheninhaltund Umfang sollen auf jeden Fall die der spezifischen Klasse sein!)

5.3.5 Dynamisches ‘Method Lookup’

• Woher weiss der Compiler, ob er die Methode zur Oberklasse A oder zurUnterklasse B aufrufen soll, wenn beispielsweise ein Array von A Objektendefiniert wurde, in dem manche Objekte zur Klasse B gehoren konnen?

• Kann er nicht wissen: Code, der dynamisches Method Lookup zur Laufzeitbenutzt: Interpreter pruft Typ eines Objektes und ruft die entsprechendeMethode auf.

• auch als Virtual Method Invocation bezeichnet (in C++)

5.3.6 ‘Final’ Methoden und Statisches ‘Method Lookup’

• Schneller, wenn kein dynamic method lookup zur Laufzeit benotigt wird.

• Wenn eine Methode mit dem final Modifikator deklariert ist, heisst das, dassdie Methode nicht von einer Unterklassen-Methode uberschrieben werden darf.↪→ Der Compiler weiss bereits, welche Version der Methode gemeint ist, unddynamisches Lookup ist damit unnotig.

• Fur bestimmte Methoden kann das Java-Laufzeitsystem dynamic methodlookup vermeiden:

– Alle Methoden einer final deklarierten Klasse sind final : also istbekannt, fur welche Klasse der Aufruf erfolgt.

– Alle private Methoden konnen generell nur in der Klasse selbstaufgerufen werden: damit ist ebenfalls bekannnt, fur welche Klasse derAufruf erfolgt. private Methoden sind implizit final und konnen nichtuberschrieben werden.

– static (Klassen)-Methoden werden generell nicht uberschrieben(sondern uberdeckt).

5.3.7 Aufruf einer uberschriebenen Methode

• Aufruf uberschriebener Methoden ist syntaktisch ahnlich zu Zugriff aufuberdeckte Felder: super. <methode >()

• Aufruf einer uberschriebenen Methode kann nicht mit Casting(((A)this).f() ) realisiert werden!

Informatik B • SS 02 65

• Modifizierte Form von dynamischem Method Lookup bei super : Gehe zurdirekten Oberklasse derjenigen Klasse, innerhalb derer super aufgerufen wird.Wenn die Methode dort definiert ist, verwende sie, ansonsten gehe zur direktenOberklasse dieser Klasse etc.

• super spricht die Methode an, die unmittelbar uberschrieben wurde.

• super bezieht sich immer auf die unmittelbare Oberklasse der Klasse, in derder Aufruf steht.Beispiel: super.f() in OverrideTest bezieht sich auf die Klasse Object !

• Uberdeckte Klassen-Methoden konnen ebenfalls durch super angesprochenwerden. (Hier erfolgt generell kein dynamic lookup.)

class A { // Define a class named Aint i = 1; // An instance fieldint f() { return i; } // An instance methodstatic char g() { return ’A’; } // A class method

}class B extends A { // Define a subclass of A

int i; // Shadows field i in class Aint f() { // Overrides instance method f in A

i = super.i + 1; // It can retrieve A.i like thisreturn super.f() + i; // It can invoke A.f() like this

}}

5.4 Overloading und Polymorphismus

5.4.1 Operator-Overloading

• Nicht zu verwechseln: Uberschreiben und Uberladen!

• Uberladen (operator overloading): Verwendung desselben Symbols, umOperatoren mit verschiedenen Signaturen zu bezeichnen.Beispiel: monadisches und diadisches - ; + fur Integers, Floats, Strings

• Overloading wird auch als “ad hoc Polymorphismus” bezeichnet.

• Java erlaubt dem Benutzer kein Uberladen von primitiven Operatoren, aberUberladen von Methoden (und Konstruktoren).

• Vorteil von Overloading: Bedeutung eines Symbols im Kontext spart dieEinfuhrung zusatzlicher Symbole. Beispiel: Definition von + fur komplexeZahlen.Vergleiche naturliche Sprache (das vermisste Buch finden, sein Gluck finden).

• Nachteil von Overloading: Es ist nicht mehr ohneweiteres nachvollziehbar, wasein Operator wirklich tut (unklare Semantik), wenn primitive Operatoren vomBenutzer uberladen werden durfen (Kritik an C++).

• Beispiel: a + b

66 Informatik B • SS 02

– Intuitiv, wenn a und b vom gleichen primitiven numerischen Typ sind:int + int → int , float + float → float .

– Verschiedene Optionen fur char + char : liefert den String aus denbeiden Zeichen, liefert die Summe der Ordnungszahl der Zeichen, ...

– Haufig sinnvoll: wenn verschiedene numerische Typen beteiligt sind, wirdzunachst auf den “großeren” Typ ge-castet: int + float → float .

– Was tun bei char + short ? (in Java haben beide 16 Bit)?

– Eventuell Verlust der Kommutativitat: Vorrang des ersten Arguments, alsokonnte char + short einen anderen Ergebnistyp liefern als short +char .

– Was ist die Intuition fur HashMap + HashMap oder Stack + Vector ?

↪→ Zulassigkeit, Einschrankungen und Techniken fur Overloading sind eine wichtigeFrage fur das Design einer Programmiersprache!

5.4.2 Operator-Overloading in Java

• Arithmetische Operatoren (+, −, ∗, /, %) und Vergleichsoperatoren in Java sinduberladen.

• Arithmetische Operatoren und Vergleichsoperatoren sind fur numerische Typendefiniert (alle primitiven Typen ausser boolean , siehe auch die entsprechendenWrapper-Klassen in Tabelle 19)

• Es ist zulassig, dass ein Operator Argumente verschiedenen Typs miteinanderverknupft. Dabei erfolgt ein implizites Casting zu dem großeren Typ, mindestenszu int (widening, siehe Tab. 4).

• Ruckgabetyp bei arithmetischen Operatoren:double wenn mindestens ein Argument double ,float wenn mindestens ein Argument float ,long wenn mindestens ein Argument long ,int sonst (auch, wenn beide Argumente byte , short oder char sind).

• Dabei werden zuerst die impliziten Casts auf den Operanden durchgefuhrt unddann der Operator angewendet.

• Der Operator + (und +=) ist zusatzlich fur String -Objekte definiert.

• Wenn mindestens eines der Argumente String ist, wird das andere Argumentzu String konvertiert.

• Klammern sind haufig notwendig:System.out.println("Total: " + 3 + 4); // Total: 34 nicht 7

(Klammern (3 + 4) : erst Addition auf Zahlen)

Informatik B • SS 02 67

Tabelle 4: Typumwandlung in JavaVon Nach

boolean byte short char int long float doubleboolean - N N N N N N Nbyte N - Y C Y Y Y Yshort N C - C Y Y Y Ychar N C C - Y Y Y Yint N C C C - Y Y* Ylong N C C C C - Y* Y*float N C C C C C - Ydouble N C C C C C C -

N(o), Y(es), explicit C(asting), Y*(yes, automatic widening, moglicher Verlust)

• Fur String + Object wird Object in String umgewandelt, indem dietoString() -Methode des Objekts angewendet wird.Achtung: Die fur Object definierte toString() Methode liefert dieReferenz-Adresse des Objekts als String. Falls andere Information gewunschtwird, muss diese Methode uberschrieben werden.

5.4.3 Method-Overloading in Java

• In Java musste Method-Overloading zugelassen werden, daKonstruktoren-Namen durch den Klassennamen bestimmt werden(automatische Erzeugung von default-Konstruktoren), und da es moglich seinsollte, mehr als einen Konstruktor fur eine Klasse zu definieren.

• Uberladene Methoden mussen sich eindeutig durch ihre Signaturunterscheiden: Anzahl, Reihenfolge und Typ der Argumente.

• Eine blosse Unterscheidung durch verschiedene Ruckgabe-Typen istunzulassig:

void f() {}int f() {}

Konnte nur klappen, wenn der Compiler eindeutig aus dem Kontext bestimmenkann, welche Methode gemeint ist, z.B. int x = f();

• Auch bei Methoden mit unterschiedlichen Signaturen kann es Probleme geben,die “gemeinte” Methode eindeutig zu identifizieren. In diesem Fall liefert derCompiler eine Fehlermeldung. (siehe Abb. 20)

5.4.4 Polymorphismus

• Polymorphismus wurde ursprunglich von Christopher Strachey (1967) alsKonzept benannt und dann im Rahmen der funktionalen Programmierungweiterentwickelt.

68 Informatik B • SS 02

public class Overloading {public static String f(String s, Object o) {

return s + o;}public static Object f(Object o, String s) {

return (Object) (o + s);}public static void main(String[] args) {

System.out.println(f("Die Zahl ist ", (Object)"17"));System.out.println(f((Object)"17", " ist eine Zahl"));// System.out.println(f("Hello", "World")); // ambiguous!!!

}}

Abbildung 20: Method-Overloading und Eindeutigkeit

• Polymorphismus bei Funktionen (parametrischer P.) meint, dass Funktionenuber Parameter mit Typvariablen definiert werden konnen:length : ’a list -> intist eine generischeFunktion, die die Lange von Listen mit Elementen beliebigen(aber einheitlichen) Typs liefert.

• ML war 1976 die erste Programmiersprache, die polymorphe Typisierung(zusammen mit starker Typisierung) eingefuhrt hat.

• ↪→ Parametrischer Polymorphismus erlaubt denselben Code, um Argumenteverschiedenen Typs zu behandeln; Overloading meint dagegen dieWiederverwendung desselben syntaktischen Symbols und verlangtverschiedenen Code, um verschiedene Typen zu behandeln!

• In der objekt-orientierten Programmierung meint Polymorphismus, dassVariablen deklariert werden konnen, die zur Laufzeit auf Objekte verschiedenerKlassen verweisen konnen.

5.4.5 Casting und Polymorphismus

• Upcasting in der Klassenhierarchie ist immer zulassig.

• Wird ein Circle -Objekt zu einem Shape -Objekt gecasted, stehen fur denZugriff nur noch die Methoden und Felder der Klasse Shape zur Verfugung.

• Downcasting ist nur in speziellen Fallen moglich: Jeder Circle ist ein Shape ,aber nicht jeder Shape ist ein Circle .

• Unerlaubtes Downcasting fuhrt zu einem Laufzeit-Fehler(RuntimeException ), genauer zu einer ClassCastException (sieheKapitel ‘Exceptions’).

Informatik B • SS 02 69

Shape s;s.setColor();

Circle

+ area+ circumference+ diameter

Shape

+ setColor

TriangleRectangle

+ area+ circumference+ isSquare

+ circumference+ area

+ ...

Up

cast

ing

Abbildung 21: Polymorphismus

• Mit dem booleschen Operator <objectname> instanceof <Classname> kannvor dem Casting explizit gepruft werden, ob das Objekt zur gewunschten Klassegehort oder die Klasse des Objekts von der gewunschten Klasse abgeleitet ist!(gilt auch fur Interfaces)

void checkPos(Circle c, double x, double y) {if (c instanceof PlaneCircle)

((PlaneCircle)c).isInside(x,y);

• Vorteil von Polymorphismus: Eine Methode setColor() kann fur beliebigeShape -Objekte definiert werden. Egal, ob die Methode zur Laufzeit zu einemCircle - oder einem Rectangle -Objekt gehort, sie kann auf jeden Fallangewendet werden.

• Dadurch wird Duplizierung von Code vermieden!

• Zudem ist keine Kenntnis notig, welche Unterklassen von Shape konkretexistieren.

• Wird eine Methode f() in der Oberklasse definiert, so kann sie in derUnterklasse uberschrieben werden. Fur ein Shape -Objekt, das ein Circle ist,wird dann seine spezifische Methode verwendet.

• Polymorphismus kann nur zusammen mit dynamic binding (auch late binding)realisiert werden. Viele imperative Sprachen verwenden early binding, d.h.,Methodenaufrufe werden schon zur Compilezeit mit dem Methodenkorperverbunden.

5.4.6 Casting vs. Parameterisierte Klassen

• Unzulassiges Downcasting kann erst zur Laufzeit erkannt werden.

• Downcasting wird in Java immer dann verwendet, wennMethoden/Datenstrukturen benutzt werden, die fur recht allgemeine Klassen

70 Informatik B • SS 02

definiert werden. Werden Objekte zuruckgeliefert, mussen sie haufig wieder aufihren speziellen Typ gecasted werden. Beispiel: Collection-Klassen verwaltenObjekte vom Typ Object .

• Alternative Idee: generische Klassen, Templates (C++).Templates sind parametrisierte Klassen, die fur spezielle Typen konkretisiertwerden konnen. Dies entspricht parametrisierten, polymorphen Typen, wie sie inder funktionalen Programmierung verwendet werden.

• Beispiel: Statt einer Stack -Klasse, die Objekte vom Typ Object verwaltet,kann eine Stack(T) -Klasse definiert werden. Parameter T kann dannverschieden belegt werden (zu Integer , Shape , etc.).

• Arrays in Java sind eine Art generische Klasse: Ausgehend von einem“allgemeinen Array-Typ” werden nach Bedarf Objekte zu spezifischenElement-Typen erzeugt.vgl. int[] vs. [](int) oder Circle[] vs. [](Circle)

Informatik B • SS 02 71

6 Exceptions

6.1 Fehler und Ausnahmen

• Exception = exceptional event (aussergewohnliches Ereignis).

• Eine Exception ist ein Ereignis, das wahrend der Ausfuhrung eines Programmsauftritt und den normalen Ablauf unterbricht.

• In Java werden “Fehlerereignisse” als Objekte (vom Typ Exception )reprasentiert.

• Exception und Error erweitern Throwable .

• Error -Unterklassen betreffen schwerwiegende Fehler (z.B.VirtualMachineError ) und sollten nicht vom Programmierer behandeltwerden.

• Exceptions sollten dagegen behandelt werden.

• Exceptions treten typischerweise innerhalb von Methoden auf.

• Erkennt eine Methode eine Fehlerbedingung, wird ein entsprechendesException-Objekt erzeugt und “geworfen”.

• Wenn eine Exception auftritt (z. B. FileNotFoundException wenn eineDatei, die geoffnet werden soll, nicht gefunden wird), wird ein ExceptionObjekt erzeugt und an das Laufzeitsystem gegeben. ↪→ throwing an exception

• Dieses Objekt enthalt Information uber die Art der Exception und uber denZustand des Programms (Aufrufstack) zum Zeitpunkt zu dem die Exceptionauftrat.

• Das Laufzeitsystem ist verantwortlich, Code zu finden, der den Fehler behandelt.Die Behandlung kann in der Methode, in der der Fehler aufgetreten ist, selbstoder in einer der diese Methode aufrufenden Methoden (Aufrufstack) erfolgen.Beispiel:

h() -----------------> Exception tritt aufg() (ruft h() auf)f() (ruft g() auf) Behandlung der Exception

• Exception Handler (catch -Block): Fur eine aufgetretene Exception ist derjenigeHandler angemessen, der den entsprechenden Exception-Typ (Klasse oderOberklasse des geworfenen Exceptionen-Objects) behandelt.

• Wird eine aufgetretene Exception nicht behandelt, terminiert das Laufzeitsystemund damit das Programm.

72 Informatik B • SS 02

6.2 Vorteile von Exceptions

• Separierung von regularem Code und Fehlerbehandlung: Transparenz,Strukturiertheit

• Propagierung von Fehlern moglich

• Gruppierung von Fehler-Typen, Fehlerdifferenzierung

readFile { // was ist, wennopen the file; // file nicht geoeffnet werden kann?determine its size; // Laenge nicht bestimmt werden kann?allocate that much memory; // nicht genug Speicher belegt werden kann?read the file into memory; // beim Lesen ein Fehler auftritt?close the file; // file nicht geschlossen werden kann?

}

6.2.1 Separierung von Code und Fehlerbehandlung

Abfangen mit expliziten bedingten Anweisungen im Code:

errorCodeType readFile {initialize errorCode = 0;open the file;if (theFileIsOpen) {

determine the length of the file;if (gotTheFileLength) {

allocate that much memory;if (gotEnoughMemory) {

read the file into memory;if (readFailed) {

errorCode = -1;}

} else {errorCode = -2;

}} else {

errorCode = -3;}

close the file;if (theFileDidntClose && errorCode == 0) {

errorCode = -4;} else {

errorCode = errorCode and -4;}

} else {errorCode = -5;

}return errorCode;

}

Informatik B • SS 02 73

Trennung von “normalem” Code und Fehlerbehandlung:

readFile {{ // Block mit Anweisungen, bei denen Exceptions auftreten koennten

open the file;determine its size;allocate that much memory;read the file into memory;close the file;

} handle fileOpenFailed {doSomething;

} handle sizeDeterminationFailed {doSomething;

} handle memoryAllocationFailed {doSomething;

} handle readFailed {doSomething;

} handle fileCloseFailed {doSomething;

}}

6.2.2 Propagierung von Exceptions

method1 {call method2;

}method2 {

call method3;}method3 {

call readFile;}

Nur method1 sei an Fehlern, die in readFile() auftreten konnen interessiert.Fehler-Propagierung “zu Fuss”:

method1 {errorCodeType error;error = call method2;if (error)

doErrorProcessing;else proceed;

}errorCodeType method2 {

errorCodeType error;error = call method3;if (error)

74 Informatik B • SS 02

return error;else proceed;

}errorCodeType method3 {

errorCodeType error;error = call readFile;if (error)

return error;else proceed;

}

In Java ist es zulassig, dass eine Methode den Fehler nicht selbst fangt (“duck” athrown exception), sondern weitere nach oben durchreicht.

method1 {try {

call method2;} catch (exception) {

doErrorProcessing;}

}method2 throws exception {

call method3;}method3 throws exception {

call readFile;}

Achtung: Wenn in einer Methode (oder einem Konstruktur) Exceptions auftretenkonnen, mussen diese entweder spezifiziert (throws ) oder behandelt werden!

InputFile.java:11: Exception java.io.FileNotFoundExceptionmust be caught, or it must be declared in the throws clauseof this method.

in = new FileReader(filename);ˆ

6.3 Exception Handling – ‘try’, ‘catch’, ‘finally’

// Note: This class won’t compile by design!// See ListOfNumbersDeclared.java or ListOfNumbers.java// for a version of this class that will compile.import java.io.PrintWriter;import java.io.FileWriter;import java.util.Vector;

public class ListOfNumbers {

Informatik B • SS 02 75

private Vector vec;private static final int SIZE = 10;

public ListOfNumbers () {vec = new Vector(SIZE);for (int i = 0; i < SIZE; i++)

vec.addElement(new Integer(i));}public void writeList() {

PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));

for (int i = 0; i < SIZE; i++)out.println("Value at: " + i + " = " + vec.elementAt(i));

out.close();}

}

• Mogliche IOException: Konstruktor FileWriter() kann angegebene Dateinicht offnen.

• Mogliche RunTimeException : ArrayIndexOutOfBoundsException beivec.elementAt(i) .

• Es macht Sinn, dass verlangt wird, dass alle Fehler ausser RunTimeExceptionsvom Programmierer behandelt werden.

• Der Compiler/das Laufzeitsystem konnen nicht hellsehen, auf welche Art eineException behandelt werden soll.

• Beispiel FileNotFoundException : Programm beenden, andere Dateieinlesen, File dieses Namens erzeugen.

• Beispiele fur RunTimeExceptions: arithmetic exceptions (division by zeroo),pointer exceptions (access object by null reference), indexing exceptions.

• Checked Exceptions: Exception ausser RunTimeExceptions, die vom Compilergepruft werden (ob sie behandelt oder spezifiziert werden).

import java.io.PrintWriter;import java.io.FileWriter;import java.io.IOException;import java.util.Vector;

public class ListOfNumbers {private Vector vec;private static final int SIZE = 10;

public ListOfNumbers () {vec = new Vector(SIZE);for (int i = 0; i < SIZE; i++)

76 Informatik B • SS 02

vec.addElement(new Integer(i));}public void writeList() {

PrintWriter out = null;

try {System.out.println("Entering try statement");out = new PrintWriter(new FileWriter("OutFile.txt"));

for (int i = 0; i < SIZE; i++)out.println("Value at: " + i + " = " + vec.elementAt(i));

} catch (ArrayIndexOutOfBoundsException e) {System.err.println("Caught ArrayIndexOutOfBoundsException: " +

e.getMessage());} catch (IOException e) {

System.err.println("Caught IOException: " + e.getMessage());} finally {

if (out != null) {System.out.println("Closing PrintWriter");out.close();

} else {System.out.println("PrintWriter not open");

}}

} }

Erlauterungen:

• Es konnte alternativ zu System.err.println() auchSystem.out.println() verwendet werden, um Meldungen auszugeben.Ublicherweise geht der Fehler-Strom aber auf das Terminal, wahrend derAusgabestrom beispielsweise in eine Datei gehen kann (in der man nicht dieFehlermeldungen haben will).

• try-catch-finally ist eine Kontrollstruktur. Der try -Block kann ohnefolgende catch-Bl ocke oder ohne folgenden finally -Block stehen. (tryalleine wird vom Compiler angemeckert.)

• Der try -Block ohne catch -Blocke bewirkt, dass hier keine Fehlerbehandlungerfolg.

• Der try -Block wird verlassen, sobald eine Exception darin auftrat. Wennbestimmte Dinge auf jeden Fall erledigt werden sollen (z.B. Schliessen einerDatei), so kann dies in einem finally -Block spezifiziert werden.

• Es kann maximal einen finally -Block geben, in dem abgesichert werdenkann, dass bestimmte Dinge auf jeden Fall ausgefuhrt werden (wenn vorher keinSystem.exit() erfolgt), auch wenn etwas schief geht.

• Exception-Objekte haben die Methode getMessage() , die den Fehlertext derException liefert.

Informatik B • SS 02 77

• Falls die Datei OutFile.txt nicht zum Schreiben geoffnet werden kann,reagiert der FileWriter -Konstruktor und erzeugt und wirft das entsprechendeException -Objekt.

• Die ArrayIndexOutOfBoundsException musste nicht abgefangen werden.

• Falls ArrayIndexOutOfBoundsException und IOException in einemeinzigen catch-Block behandelt werden sollen, muss die gemeinsameOberklasse dieser Exceptions gefangen werden. Die ist nur Exception , wasublicherweise zu allgemein ware!

• finally kann Code-Duplizierung vermeiden:

try { . . .out.close(); // don’t do this; it duplicates code

} catch (ArrayIndexOutOfBoundsException e) {out.close(); // don’t do this; it duplicates codeSystem.err.println("Caught ArrayIndexOutOfBoundsException: "

+ e.getMessage());} catch (IOException e) {

System.err.println("Caught IOException: " + e.getMessage());}

• Was passiert, wenn sowohl catch als auch finally eine return -Anweisungenthalten? (Ubung!)

Drei Moglichkeiten des Programmablaufs:

• new FileWriter() geht schief, IOException :

Entering try statementCaught IOException: OutFile.txtPrintWriter not open

• ArrayIndexOutOfBoundsException :

Entering try statementCaught ArrayIndexOutOfBoundsException: 10 >= 10Closing PrintWriter

• try -Block wird ohne Exception verlassen

Entering try statementClosing PrintWriter

78 Informatik B • SS 02

6.4 Spezifikation von Exceptions – ‘throws’

import java.io.PrintWriter;import java.io.FileWriter;import java.io.IOException;import java.util.Vector;

public class ListOfNumbersDeclared {private Vector vec;private static final int SIZE = 10;

public ListOfNumbersDeclared () {vec = new Vector(SIZE);for (int i = 0; i < SIZE; i++)

vec.addElement(new Integer(i));}public void writeList() throws

IOException, ArrayIndexOutOfBoundsException {PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));

for (int i = 0; i < SIZE; i++)out.println("Value at: " + i + " = " + vec.elementAt(i));

out.close();}

}

• throws spezifiziert mogliche Fehler und verschiebt deren Behandlung zuaufrufenden Methoden.

• Dies macht Sinn, wenn es ubergeordnete Strukturen gibt, bei denen erst klar ist,welche Fehler wie abgefangen werden sollen.

• Es macht wenig Sinn, dass die main -Methode (letzte Methode im Aufrufstack)Fehler spezifiziert und nicht behandelt. Programmbenutzer wird dann mit denjava-Fehlermeldungen konfrontiert.

• throws kann nur fur Methoden (und Konstruktoren) deklariert werden.

6.5 Vererbung und ‘throws’

• Es ist nicht erlaubt, einer Methode beim Uberschreiben weiterethrows -Klauseln hinzuzufugen!Ansonsten ware keine Zuweisungskompatibilitat mehr gegeben: In allenMethoden, die diese Methode verwenden, musste eine Spezifikation bzw.Behandlung der neu hinzugekommenen Exceptions erfolgen.

• Weglassen eines Teils oder einer kompletten throws -Klausel ist erlaubt.

Informatik B • SS 02 79

1995-7, Charles L. Perkins http://rendezvous.com/java

Exception

ArithmeticException

RuntimeException ArrayIndexOutOfBoundsException

IndexOutOfBoundsException

ArrayStoreException

ClassCastException

ClassNotFoundException

IllegalAccessException

IllegalArgumentException

IllegalThreadStateException

InstantiationException

InterruptedException

NegativeArraySizeException

NoSuchMethodException

NullPointerException

NumberFormatException

SecurityException

StringIndexOutOfBoundsException

Objectjava.lang

Throwablejava.lang

java.lang-exceptions

CloneNotSupportedException

IllegalMonitorStateException

IllegalStateException

NoSuchFieldException

Serializablejava.io-objects

Abbildung 22: Java Language Exception Klassen

6.5.1 Gruppierung von Fehler-Typen

• Exception-Objekte sind – wie andere Java Objekte – in einer Klassenhierarchieorganisiert.

• Ganze Gruppen von Exceptions konnen mit einem einzigen catch behandeltwerden, wenn eine entsprechende Oberklasse verwendet wird.

• Wenn mehrere catch -Blocke den Typ der Exception behandeln, so wird nur dererste (Reihenfolge im Code) passende ausgefuhrt.↪→ Falls mehrere Exceptions, die in einer Unterklassenbeziehung zu einanderstehen, abgefangen werden sollen, so mussen diese sequentiell von derspeziellsten zur allgemeinsten behandelt werden!

• Achtung: Exception-Handler, die zu allgemein sind, konnen Code wiederfehleranfallig machen! Es konnen dadurch Exceptions gefangen werden, dienicht vorhergesehen wurden und entsprechend nicht korrekt behandelt werden.

80 Informatik B • SS 02

6.6 Definition eigener Exception-Klassen und Auslosen von Exceptions

public class IllegalRadiusException extends Exception {private double invalidRad;public IllegalRadiusException (String msg, double rad) {

super(msg);invalidRad = rad;

}public String getMessage() {

return super.getMessage() + ": " + invalidRad;} }

public class CheckedCircle {public static final double PI = 3.14159;protected double r;protected void checkRadius(double radius) throws IllegalRadiusException {

if (radius < 0.0) throw new IllegalRadiusException("radius may not be negative", radius);

}public CheckedCircle(double r) throws IllegalRadiusException {

checkRadius(r);this.r = r;

}public double getRadius() { return r; }public void setRadius(double r) throws IllegalRadiusException {

checkRadius(r);this.r = r;

}

public static void main (String[] args) {try { CheckedCircle c = new CheckedCircle(1.0);

c.setRadius(-1.0);} catch (IllegalRadiusException e) {

System.out.println( e.getMessage() );}

} }

• Nicht verwechseln: throws – Spezifizieren einer Exception, und throw –Auslosen einer Exception.

• In den API’s sind Exceptions auf dieselbe Art realisiert wie hier gezeigt.

• Alle checked exceptions werden von Methoden ausgelost. Laufzeitfehler werdendagegen aus dem Laufzeitsystem heraus erzeugt.

• Im Programmbeispiel CheckedCircle muss nun in alle Methoden, in denendie IllegalRadiusException auftreten konnte, entweder die Exceptionspezifiziert (geworfen) oder behandelt werden.

• Alternativ hatte IllegalRadiusException von RunTimeExceptionabgeleitet werden konnen. Dann ware die Fehlerbehandlung nicht verpflichtend.

Informatik B • SS 02 81

6.7 Exkurs: UML

• Im Skript werden Klassen manchmal graphisch als Kasten und Beziehungenzwischen Klassen mit Pfeilen veranschaulicht. (z.B. Abb. 18)

• Eine standardisierte Notation zur Reprasentation von Klassen und ihrenBeziehungen sind UML-Diagramme.

• UML (“Unified Modeling Language”) ist eine auf Diagrammen basierendeBeschreibungssprache fur den objekt-orientierten Entwurf und dieobjekt-ortientierte Analyse.

• Standardisierung durch: Booch, Jacobson, Rumbaugh (“Die drei Amigos”).

• Ein Meta-Modell legt fest, wie diese Sprache benutzt werden soll. In vielenDokumentationen wird auf diesen Aspekt kaum eingegangen.Vergleiche: BNF als Meta-Sprache zur Reprasentation von Grammatiken furProgrammiersprachen; Meta-Modell als Sprache zur Reprasentation vonGrammatiken fur UML-Diagramme.aktuelle Forschung: Beschreibung von UML-Diagrammen mitGraph-Grammatiken (Parsierung, syntaktische Korrektheit, ...)

• Objekt-orientierter Entwurf meint die Konzeption von Klassenstrukturen undAbhangigkeiten bei der Systementwicklung.

• Vorteile einer standardisierten Sprache:↪→ CASE-Tools (Computer Assisted Software Engineering) zur Erzeugung vonCode↪→ Austausch von Entwurfen

• UML wird in der Vorlesung Informatik C behandelt. Im folgenden werden diewesentlichen Komponenten kurz illustriert.

6.7.1 Klassendiagramme in UML

• Abbildung 23 zeigt den wesentlichen Aufbau von Klassendiagrammen.

• UML-Diagramme sollen ubersichtlich sein!

• Immer soviel Information fur die Klassen angeben, wie notwendig ist.

• Optionale Angabe von Typ-Information bei Feldern und Methoden

• Angabe ausgewahlter Komponenten (beispielsweise: nur Methoden)

public abstract class Person {protected String personName;private int age;

public Person (String name) {personName = name;

}

82 Informatik B • SS 02

−age#personName

+Person+getAgegetJob+makeJob−splitNames

Person• Kasten aus drei Teilen:

Klassen-Namen (fett),Felder, Methoden

• Sichtbarkeits-Modifikatoren:+ public ,− private , # protected

• Kursiv: Abstrakte Klassen/Methoden

• Unterstrichen: Klassen-Methoden, -Felder

Abbildung 23: Darstellung der Klasse ‘Person’ in UML

#personName: String

getJob(): String+makeJob(): String−splitNames()

Person

+Person(String)+getAge(): Integer

−age: Integer

+getAgegetJob+makeJob−splitNames

Person

Abbildung 24: Darstellungsvarianten fur Klassen in UML

static public String makeJob () {return "hired";}public int getAge () {return age;}private void splitNames () {}abstract String getJob ();

}

6.7.2 Klassen-/ Unterklassenbeziehungen in UML

• Der Klasse/Oberklasse-Pfeil reprasentiert eine Generalisierung (Employee istUnterklasse von Person ).

• Pfeil mit durchgezogener Linie und hohler Pfeilspitze von der Unterklasse zurOberklasse

• bei Interfaces: gestrichelte Linie, uber dem Interface-Namen steht<<interface>>

Informatik B • SS 02 83

public class Employee extends Person {public Employee (String name) {

super(name);}

public String getJob() {return "Research Staff";

}}

+getAgegetJob+makeJob−splitNames

Employee

+Employee+getJob

Person

Abbildung 25: Vererbung in UML

6.7.3 Assoziationen

• Beziehungen zwischen Klassen/Objekten werden als Assoziationenbezeichnet.

• Generalisierung ist eine spezielle Assoziation.

• Eine Assoziation bezeichnet eine “Rolle”, die eine Klasse bezuglich der andereneinnimmt.vergleiche: Casus-Strukturen, Fillmore, 1968, zur Reprasentation derTiefenstruktur naturlichsprachiger Satze.

• Bei Generalisierung: “Ein Employee ist einePerson .”

• Ein Employee arbeitet fur eine Company.

• Assoziationen werden allgemein durch Linien zwischen Klassen (ohne Pfeil)dargestellt. Zusatzlich konnen Zahlenbereiche angegeben werden, dieanzeigen, wieviele Instanzen von Objekten einer Klasse mit einer anderenKlasse in Beziehung stehen konnen.

– ∗ gibt an, dass null bis beliebig viele Instanzen einer Klasse mit eineranderen assoziiert sein konnen.

– 1 gibt an, dass genau eine Instanz mit einer Klasse/Objekt assoziiert ist(entspricht 1..1).

• Assoziationen einer Klasse mit sich selbst heissen rekursiv.

• Eine spezielle Art von Assoziation ist die Teil-Ganzes-Beziehung: Aggregation.(“Ein Auto hat Rader.”)

84 Informatik B • SS 02

public class Company { public class Company1 {Employee empt1; Employee[] emp1;Person per1; public Company1() {}public Company() {} }

}

0..1per1

emp1

0..1

*emp1

Company1

Person

Employee

Employee

Company

Abbildung 26: Assoziationen in UML

• Komposition ist wiederum eine spezielle Aggregation, bei der die Teile ohne dasGanze nicht existieren konnen.

• Aggregationen werden durch eine Linie mit einer Raute im Ursprung dargestellt.Bei Komposition ist die Raute gefullt.

• Die Klasse NeighborQueen (siehe Kapitel 2) definiert, dass eineNeighborQueen eine Queen als linke Nachbarin hat. Diese Assoziation isteher keine Aggregation: Wir formulieren “Eine NeighborQueen hat eineQueenals Nachbarin”, aber nicht “Eine NeighborQueen hat als Teil/besteht auseinerQueen.”

6.7.4 Kommentare und Annotierung in UML

• Kommentare als eigene Boxen mit umgeklappter Ecke

• Pfeile mit durchgezogenen Linien und vollen Kopfen, um anzuzeigen, welcheKlasse eine Methode welcher anderen Klasse aufruft.

6.7.5 UML-Tools

• Zur Kommunikation, zum Entwurf: Papier und Bleistift, beliebigesGraphik-Programm

Informatik B • SS 02 85

• Spezielle Tools: Erzeugung von UML aus Graphik-Bausteinen, Erzeugung vonUML aus Code, Erzeugung von Code aus UML (spezielle syntaktischeKonventionen einzuhalten!)Beispiele: Rational Rose, Together, argouml

6.8 Exkurs: Design Patterns – Factory Pattern

• Design Patterns:(abstrakter) Code, der wiederverwendet werden kann(bewahrte Standardlosungen von Experten)Beispiele: Factory Pattern, Adapter Pattern, Proxy Pattern, Patterns fur GUI

• Cognitive Science: Abstraktion als Ergebnis des Lernens beim AnalogenProblemlosen!

• Ein Simple Factory Pattern liefert eine Instanz fur eine oder mehrere Klassen inAbhangigkeit von den gelieferten Daten.

• Ublicherweise haben alle Klassen, fur die die Factory Objekte erzeugen kann,eine gemeinsame Oberklasse und gemeinsame Methoden. Die Klassenunterscheiden sich dadurch, dass sie fur verschiedene Arten von Datenoptimiert sind.

• Beispiele: Temperatur kann als Celsius oder Fahrenheit aufgefasst werden, einNutzerdialog kann in verschiedenen Sprachen erfolgen (Internationalisierung),eine Zeichenkette kann als numerischer Wert verschiedenen Typs aufgefasstwerden, ...

86 Informatik B • SS 02

XFactory

+XFactory()

...

X

XY XZ

+do_X() +do_X()

+newObj() : X

+do_X()

Abbildung 27: Das Factory-Pattern

• X als Basis-Klasse, von der XY und XZ abgeleitet sind.

• Klasse XFactory entscheidet, Instanzen welcher Unterklasse zuruckgeliefertwerden, in Abhangigkeit davon, welche Argumente ubergeben werden. DienewObj() -Methode erhalt einen Wert und liefert Instanz der “entsprechenden”Klasse.

• Welche Klasse zuruckgeliefert wird, ist dem Programmierer egal, da alledieselben Methoden (aber in unterschiedlichen Implementationen) haben.

• Beispiel: Eine Zahl wird der Factory als String ubergeben. Je nach “Form” wirddas Objekt einer passenden Wrapper-Klasse zuruckgeliefert.

package number;

public class NumberFactory{

public Number newNumber (String value) throws NumberFormatException{

try{

return new Byte(value); // first try Byte}catch (NumberFormatException e1){

Informatik B • SS 02 87

NumberFactory

newNumber(String) : Number

java.lang

Number

Integer Double...

intValue()

intValue() intValue()

Abbildung 28: Eine Number-Factory

try{

return new Short(value); // ... then Short}catch (NumberFormatException e2){

try{

return new Integer(value); // .. then Integer}catch (NumberFormatException e3){

try{

return new Long(value); // ... then Long}catch (NumberFormatException e4){

// ‘new Float(value)’ will return an infinite value// if the number cannot be represented as a float// (not a NumberFormatException), so check for thisreturn new Float(value).isInfinite() ?

(Number) new Double(value) :(Number) new Float(value);

}}

88 Informatik B • SS 02

}}

}}

import number.NumberFactory;

public class NumberFactoryTest{

// print object’s class name and valuepublic static void printNumber (Number number){

System.out.println(number.getClass().getName() + ": " + number);}

public static void main (String args[]){

NumberFactory factory = new NumberFactory(); // the factory

try{

printNumber(factory.newNumber("123")); // ByteprintNumber(factory.newNumber("1234")); // ShortprintNumber(factory.newNumber("123456")); // IntegerprintNumber(factory.newNumber("1234567890123")); // LongprintNumber(factory.newNumber("3.14159")); // FloatprintNumber(factory.newNumber("1e100")); // DoubleprintNumber(factory.newNumber("abcd")); // Exception

}catch (NumberFormatException e){

System.err.println(e); // print error message}

}}

Informatik B • SS 02 89

open a stream open a streamwhile more information while more information

read information write informationclose the stream close the stream

Abbildung 29: Input und Output Stream

7 Input/Output

7.1 Ein-/Ausgabe-Strome

• Anwendung: Einlesen von Information aus einer externen Quelle (source) oderAusgabe zu einer externen Destination (sink).

• Information kann von verschiedenen Quellen stammen: Tastatur, Datei,Speicher, Internet, anderes Programm, ...

• Information kann verschiedener Art sein: Zeichen, Objekte, Bilder, ...

• Information kann zu verschiedenen Ausgaben gehen: Bildschirm, Datei,Drucker, Speicher, Internet, anderes Programm, ...

• Klassen in java.io : sehr viele Klassen, im folgenden werden nur ausgewahlteAspekte dargestellt

• Information wird generell sequentiell gelesen/geschrieben.

7.1.1 Klassenstruktur in ‘java.io’

• Die wichtigsten Klassen zum Lesen und Schreiben von Daten sindReader /Writer fur Zeichen-Strome (ab Java 1.1) sowie

90 Informatik B • SS 02

InputStream /OutputStream fur Byte-Strome (ab Java 1.0) und derenUnterklassen (nachster Abschnitt).

• Die Klasse RandomAccessFile erlaubt Lesen und Schreiben von Bytes, Textund primitiven Datentypen von oder in spezifische(n) Positionen einer Datei.

• Die Klasse StreamTokenizer liefert eine einfache lexikalische Analyse fureinen Eingabestrom und zerlegt ihn in “Tokens” (wichtig fur Parser-Konstruktion).

• Die Klasse File unterstutzt plattform-unabhangige Definition von Datei- undVerzeichnisnamen. Sie liefert Methoden zum Auflisten von Verzeichnissen,Prufen der Schreib-Lese-Rechte und weitere typische Operationen auf Dateienund Verzeichnissen.Ein File -Objekt bezeichnet einen Datei-Strom aus dem gelesen/in dengeschrieben werden kann.

• Da Daten zum Lesen und Schreiben seriell verarbeitet werden, mussen Klassendas Serializable -Interface implementieren, damit entsprechende Objekteverarbeitet werden konnen. Serializable ist ein sogenanntes“Marker”-Interface, das keine Methoden oder Konstanten definiert.

7.1.2 Character und Byte Strome

• Lesen/Schreiben von 16-Bit (unicode) Zeichen: Abstrakte Reader /WriterKlasse und entsprechende Unterklassen (ab Java 1.1).

• Lesen/Schreiben von 8-Bit Bytes: Abstrakte InputStream /OutputStreamKlasse und entsprechende Unterklassen (ab Java 1.0).

• Ahnliche APIs (Methoden mit gleichem Namen und aquivalenter Signatur) furverschiedene Character- und Byte-Strome.

• Fur Byte-Strome werden Byte-Arrays, fur Character-Strome Character-Arraysverarbeitet:

int read()int read(char cbuf[])int read(char cbuf[], int offset, int length)

int write(int c)int write(char cbuf[])int write(char cbuf[], int offset, int length)

• read() und write() konnen IOException s werfen.

• read() liefert int zuruck: 0 . . . 255 fur Bytes oder 0 . . . 65535(0x00-0xffff) fur Characters und -1 fur Ende des Stroms.

Informatik B • SS 02 91

Object

RandomAccessFile

StreamTokenizer

File

Serializable Externizable

Abstrakte Klassen zum Lesen und Schreiben

Abstrakte Klassen zum Lesen und Schreiben

Lesen und Schreiben an beliebigen Stellenin einer Datei

Zerlegung von Input in Tokens

Verzeichnisnamen

Reader

Writer

InputStream

OutputStream

<<interface>> <<interface>>

Plattform−unabhängige Definition von Datei− und

von Byte−Strömen

von Character−Strömen

Abbildung 30: Auswahl von Klassen injava.io

92 Informatik B • SS 02

FileInputStream

FileOutputStream

FilterInputStream

BufferedInputStream

BufferedOutputStream

FilterOutputStream

InputStreamReader FileReader

BufferedReader

OutputStreamReader FileWriter

BufferedWriter

Reader

Writer

InputStream

OutputStream

FilterReader

FilterWriter

Abbildung 31: Unterklassen vonReader /Writer sowie InputStream undOutputStream

• Uberladene Methoden:

– Lesen/Schreiben eines Zeichens/Bytes.

– Lesen/Schreiben in/aus Array von Zeichen/Bytes.

– Lesen/Schreiben von length Zeichen/Bytes in/aus Array ab Indexoffset .

• Bei den Methoden, die Arrays verarbeiten, wird die Anzahl der verarbeitetenZeichen/Bytes zuruckgeliefert bzw. -1 fur Ede des Stroms.

7.1.3 Wichtige Reader- und Writer-Klassen

• Um komplexe Funktionalitat zu erhalten, werden gerade im I/O-Bereich haufigObjekte komponiert/ineinander verschachtelt.

• Viele Konstruktoren und Methoden in java.io werfen Exceptions!

• Die Klasse InputStreamReader bietet eine Reader -Schnittstelle zuu einemInputStream (analog fur OutputStreamWriter ): ein InputStream -Objektwird in ein InputStreamReader -Objekt eingebettet.

public class InputStreamReader extends Reader {// public constructorpublic InputStreamReader(java.io.InputStream in);// ...

}

• Schreiben in eine Datei und Lesen aus einer Datei kann mit FileWriter undFileReader erledigt werden.

Informatik B • SS 02 93

• Die Angabe von Dateien kann uber File -Objekte oder (plattform-spezifische)Dateinamen als Strings erfolgen. Konstruktoren:

public class FileReader extends InputStreamReader {// public constructorpublic FileReader(File file) throws FileNotFoundException;public FileReader(String fileName) throws FileNotFoundException;// ...

}

oder

• Puffern von Daten bringt Effizienz: Daten werden (in Array) gesammelt unddann weiterverarbeitet. Die Klasse BufferedReader hat einereadLine() -Methode.

• Die abstrakten Filter-Klassen FilterReader und FilterWriter erlaubenZusatzfunktionen wahrend des Lesens/Schreibens: z.B. Zahlen von Zeichen,Umwandlung von Zeichen etc.

7.2 Datei-Strome

import java.io.*;

public class Copy {public static void main(String[] args) throws IOException {

File inputFile = new File(".", "farrago.txt");File outputFile = new File("outagain.txt");

// File Reader/Writer fuer Character-weises Lesen/SchreibenFileReader in = new FileReader(inputFile);FileWriter out = new FileWriter(outputFile);

// Alternativ fuer Bytes// FileInputStream in = new FileInputStream(inputFile);// FileOutputStream out = new FileOutputStream(outputFile);

int c;

while ((c = in.read()) != -1)out.write(c);

in.close();out.close();

}}

• Klasse File : Konstruktor erzeugt File-Objekt aus String.Achtung bei Pfadnamen: Pfadseparatoren sind vom Betriebssystem abhangig

94 Informatik B • SS 02

• Alternativ zum obigen Code konnte der Dateiname direkt als String anFileReader ubergeben werden, z. B. FileReader(farrago.txt");

• FileReader ist ein Datei-Strom.

• FileReader ist Unterklasse von InputStreamReader : Eine Datei isteigentlich als Folge von Bytes und nicht von Unicode-Zeichen reprasentiert. DieKlasse FileReader realisiert die Anwendung eines InputStreamReader aufein InputStream -Objekt!

• mit new FileReader(...) etc. wird die Datei automatisch geoffnet.

• Dateien konnen (sollten) explizit geschlossen werden, damit keine Ausgabe imI/O-Puffer verbleibt (flush). Im Prinzip werden Dateien auch vom GarbageCollector geschlossen, wenn nicht mehr auf sie zugegriffen wird.

• In dem Programm konnte noch eine Abfrage eingebaut werden, ob der Nameder Zieldatei verschieden vom Namen der Quelldatei ist (equals() Methodeder Klasse File ).

7.3 Puffern von Daten

• Beliebige Reader -Objekte konnen in einen BufferedReader gesteckt werden,also z.B. FileReader -Objekte. (analog fur Writer , analog fur Byte-Strome)

• Im zweiten Teil von BufferDemo wird gezeigt, wie Daten aus demStandard-Eingabestrom (z.B. der Tastatur) gepuffert verarbeitet werden konnen.System.in ist ein InputStream -Objekt!

• Analog zu

BufferedReader in =new BufferedReader(new FileReader(inputFile));

kann naturlich geschrieben werden:

FileReader fr = new FileReader(inputFile);BufferedReader in = new BufferedReader(fr);

public class BufferDemo {public static void main(String[] args) throws IOException {

File inputFile = new File("farrago.txt");File outputFile = new File("outagain.txt");BufferedReader in = new BufferedReader(new FileReader(inputFile));BufferedWriter out = new BufferedWriter(new FileWriter(outputFile));

String s;while ((s = in.readLine()) != null) {

out.write(s);out.write(’\n’);

Informatik B • SS 02 95

}

in.close();out.close(); // probieren Sie, was passiert, wenn Sie out nicht

// schliessen

// analog von der Standard-Eingabe (System.in)BufferedReader console = new BufferedReader

(new InputStreamReader(System.in));System.out.print("What is your name: ");try {

String name = console.readLine();System.out.println("Hello " + name);

}catch (IOException e) { System.err.println(e); }

}}

• Achtung: bei allen gepufferten Ausgabe-Stromen muss die flush -Methodeangewendet werden, damit der Puffer “geleert”, also damit wirklich geschriebenwird.

• close() fuhrt automatisch ein flushing aus.

7.4 Filter-Strome

• Die abstrakten Filter-Klassen von java.io erlauben es, beim Lesen undSchreiben zusatzliche Operationen durchzufuhren.

• Die default-Implementation der Filter-Klassen leiten die Methodenaufrufe an dasbei Konstruktion ubergebene Objekt weiter, z.B. ubliches read() : Null-Filter.

• Wird eine Unterklasse einer Filter-Klasse wie FilterInputStream definiert,so konnen genau die Methoden uberschrieben werden, von denen manzusatzliche Funktionalitat haben mochte.

• Die Filter-Klassen entsprechen dem Decorator-Pattern. Der Name kommtursprunglich aus der GUI-Programmierung (z.B. Fenster mit verschiedenerDekoration), ist aber analog fur nicht-visuelle Bereiche definiert.

import java.io.*;

public class CaseFilter extends FilterReader {

public CaseFilter(Reader f) {super(f);

}

public int read() throws IOException {

96 Informatik B • SS 02

int ch = super.read();

if (Character.isLowerCase((char) ch))return Character.toUpperCase((char) ch);

else return ch;}

}

• Die CaseFilter -Klasse implementiert eine erweiterte Funktionalitat furread() : Beim Einlesen werden Kleinbuchstaben in Grossbuchstabenumgewandelt.

• In der Klasse DecoStream wird nun das read() eines CaseFilter -Objektsverwendet. Direkt beim Einlesen wird der Text nun umformatiert!

public class DecoStream {

public DecoStream() {String s = readNormal("note.txt");System.out.println(s);s = readFilter("note.txt");System.out.println(s);

}

private String readNormal(String fl) {StringBuffer s = new StringBuffer();try {

FileReader fread = new FileReader(fl);int c;while ((c = fread.read()) != -1)

s.append((char) c);fread.close ();

}catch(IOException e) { System.err.println(e); }return s.toString();

}

private String readFilter(String fl) {StringBuffer s = new StringBuffer();try {

FileReader fread = new FileReader(fl);CaseFilter ff = new CaseFilter(fread); // CaseFilter class// provides read() with Uppercaseint c;while ((c = ff.read()) != -1)

s.append((char) c);ff.close ();

}catch(IOException e) { System.err.println(e); }

Informatik B • SS 02 97

return s.toString();}

static public void main(String[] argv) {new DecoStream();

}}

Anmerkung:

• Die Verwendung von StringBuffer statt String ist hier effizienter: Bei s =s + (char) c; muss jeweils eine Kopie des Strings angelegt werden.StringBuffer besitzt die Methode append() , mit der das neue Zeichendirekt angefugt werden kann.

7.5 Standard-Ein- und Ausgabe

• Auf Betriebssystem-Ebene existieren fur jedes laufende Programm drei Strome(siehe Ubung): Standard Input, Standard Output und Standard Error.

• In Java existieren entsprechende Objekte in der System -Klasse:

– System.in : ist ein InputStream

– System.out und Systen.err sind bereits in einen PrintStreamgepackt (statt OutputStream ).

• Defaultmassig ist Standard Input die Tastatur, Standard Output und Error derMonitor.

• Die Defaults konnen uber das Betriebssystem, aber auch innerhalb einesProgramms (z.B. Java) umdefininert werden.

• Statische Methoden in der System -Klasse und die Default-Belegung:

– setIn(InputStream in)

– setOut(PrintStream out)

– setErr(PrintStream err)

• Im Programmbeispiel BufferDemo wurde gezeigt, wie ein System.in -Objektin ein Reader -Objekt und dann in ein BufferedReader -Objekt gepacktwerden kann.

• Bereits bekannt ist die Verwendung der Methoden System.out.print() undSystem.out.println() .

• Beispiel fur die Umleitung des Ausgabe-Stroms:

98 Informatik B • SS 02

IOExceptionException

java.io

CharConversionException

EOFException

FileNotFoundException

InterruptedIOException

ObjectStreamException

SyncFailedException

UnsupportedEncodingException

UTFDataFormatException

InvalidClassException

InvalidObjectException

NotActiveException

NotSerializableException

OptionalDataException

StreamCorruptedException

java.lang

WriteAbortedException

Abbildung 32: IO-Exceptions

import java.io.*;public class Redirecting {

public static void main (String[] args) throws IOException {BufferedInputStream in = new BufferedInputStream(

new FileInputStream( "Redirecting.java"));PrintStream out = new PrintStream (

new BufferedOutputStream( new FileOutputStream("test.out")));System.setIn(in);System.setOut(out);System.setErr(out); // wenn auskommentiert:

// Fehlermeldungen auf MonitorBufferedReader br = new BufferedReader(

new InputStreamReader(System.in));String s;while ((s = br.readLine()) != null)

System.out.println(s);out.close(); // nicht vergessen! sonst wird nicht geflushed

}}

7.6 IO-Exceptions

• Bei der Ein- und Ausgabe konnen zahlreiche Exceptions auftreten: Dateienkonnen nicht vorhanden oder nicht zugreifbar sein, Eingaben konnen vomfalschen Typ sein, etc.

Informatik B • SS 02 99

7.7 RandomAccess

• Die Klasse RandomAccessFile ist fast vollig isoliert vom Rest der Klassen injava.io .

• RandomAccessFile stammt direkt von Object ab und implementiert dieInterfaces DataInput und DataOutput .

• Die Klasse ermoglicht Lesen und Schreiben sowie das Vorwarts- undRuckwartsgehen in einer Datei.

• Sie kann nicht in einen BufferedInputStream o.A. gepackt werden.

• Im Prinzip arbeitet die Klasse wie ein kombinierter DataInputStream undDataOutputStream .

• Typische Anwendung: Effizientes Lesen aus ZIP-Archiv

– Sequentieller Zugriff:

∗ Offnen des ZIP-Archivs∗ Sequentielle Suche bis das gewunschte File gefunden ist∗ Extraktion des Files∗ Schliessen des ZIP-Archivs

– Aufwand: im Mittel halbe Lange des ZIP-Files

– mit Random Access:

∗ Offnen des ZIP-Archivs∗ Suche des dir-entry und lokalisiere den Eintrag fur das gewunschte

File∗ Suche ruckwarts zur Position des Files∗ Extraktion des Files∗ Schliessen des ZIP-Archivs

7.8 Weitere Aspekte von I/O

7.8.1 Tokenizer

• Manchmal kann es nutzlich sein, eine Eingabe in einzelne Tokens (Worte) zuzerlegen.

• StreamTokenizer fuhrt eine lexikalische Analysedes Eingabestroms durch.(Anwendung: Parser-Konstruktion).

• whitespaceChars() spezifiziert die Worttrenner (z.B. Leerzeichen),ordinaryChars() spezifiziert die in Worten erlaubten Zeichen.

• Verwandt zum StreamTokenizer ist die Klasse StringTokenizer ausjava.util .

• Verwendung in spateren Kapiteln.

100 Informatik B • SS 02

Object

RandomAccessFile

+ read()+ seek()+ write()

DataInput<<interface>>

DataOutput

<<interface>>

Abbildung 33: Die KlasseRandomAccessFile

7.8.2 Serializable, Externalizable

• Uber Streams werden Daten sequentiell ubertragen.Objekte sind keine linearen Gebilde↪→ Serialisierung (Implementation des Marker-Interface Serializable ).

• Um Objekte (z.B. fur verteilte Anwendungen ubers Netz) zu verschicken, kanndie Serialisierung explizit kontrolliert werden: interface Externalizableextends Serializable .Hierfur mussen dann Methoden readExternal() und writeExternal()implementiert werden.

• Daten, die nicht serialisiert werden sollen/konnen, konnen als transientmarkiert werden. Solche Felder werden nicht serialisiert/deserialisiert.

• Genaueres im Zusammenhang mit Netzwerkprogrammierung/VerteiltenAnwendungen (Vorlesung Informatik C).

7.8.3 Pipe-Strome

• Zur Kommunikation zwischen Threads (siehe Kapitel ‘Multi-Threading’) werdenPipe-Strome verwendet. Wieder gibt es Klassen fur Byte- undUnicode-Verarbeitung.

Informatik B • SS 02 101

8 Vererbung und Typsicherheit

8.1 Formale Modelle fur Programmiersprachen

• Ein formales Modell dient dazu, einen Gegenstandsbereich (etwa eineProgrammiersprache) prazise zu beschreiben.

• Durch das Auflisten und Beweisen von Eigenschaften werden haufig Aspekteoffengelegt, die beim Entwurf ubersehen wurden (Lucken, Widerspruche).

• Kompromiss zwischen Vollstandigkeit und Kompaktheit: Beispielsweise ist eskaum moglich, eine komplexe Sprache wie Java voll zu formalisieren.Stattdessen sollten ausgewahlte Aspekte formalisiert werden.

• Im folgenden: Operationale Semantik fur einen Java-Kern – “FeatherweightJava” (FJ), Arbeit von Igarashi et al., 1999.

• Grundidee: Es soll gezeigt werden, dass Java (im Kern) typsicher ist.

– Die Syntax von Java wird auf FJ reduziert.

– Es werden formale Regeln fur die Typisierung angegeben.

– Es werden Reduktionsregeln fur Ausdrucke angegeben.

↪→ Mittels der Reduktionsregeln wird bewiesen, dass FJ typsicher ist.

Motivation:

• Eine Operationale Semantik beschreibt in Form von Reduktionsregeln, wie einAusdruck (expression) einer Programmiersprache zu einem einfacherenAusdruck ausgewertet wird:

4 + 5addregel−→ 9

• Solche Regeln konnen auch auf Teile eines Ausdrucks angewendet werden:

6 · (4 + 5)addregel−→ 6 · (9)

• Es werden (in beliebiger Reihenfolge) solange Regeln angewendet, bis keineRegel mehr anwendbar ist. Der Ausdruck ist dann entweder in Normalform(reprasentiert eine “konstanten Wert”) oder die Auswertung ist nicht vollstandigmoglich (Fehler).

• Reduktionsregeln entsprechen Termersetzungsregeln (rewrite rules). Eineinfaches Beispiel (Kaffeedosen-Problem) ist in Abb. 34 angegeben. Eine Reiheschwarzer und weisser Bohnen kann verkurzt werden, indem nach festenRegeln der Form 〈Bedingung〉 → 〈Aktion〉 Paare benachbarter Bohnen durcheine einzelne Bohne ersetzt werden.

102 Informatik B • SS 02

Gegeben ist eine Kaffeedose, in der schwarze (S)und weiße (W) Bohnen in einer festen Reihenfolgeangeordnet sind, beispielsweise: W W S S W W S S.Gegeben sind folgende Regeln:

S W→ S

W S→ S

S S→W

Das Ziel ist, am Ende moglichst wenige Bohnen zuhaben. Die Konfliktlosungs-Strategie sei, immer dieoberste anwendbare Regel auszuwahlen.

W W S S WW S SW W S S WS S

W W S S S SW S S S SW S S S S

W S SS SW

Abbildung 34: Losung des “Kaffeedose” Problems mit einer Menge von Ersetzungsregeln

• Haufig haben Reduktionsregeln Anwendungsbedingungen: Es muss nicht nurein bestimmter Unter-Ausdruck in einem Ausdruck existieren, damit eine Regelangewendet werden darf, sondern es mussen noch weitere Bedingungen erfulltsein.

• Solche Regeln werden haufig so geschrieben, dass dieAnwendungsbedingungen uber einer Linie stehen und die eigentliche Regelunter einer Linie:

fields(N) = T f

(new N(e)).fi → ei

Lies: Wenn eine Klasse N Felder f1 . . . fn mit Typen T1 . . . Tn besitzt, dann kannder Ausdruck (new N(e)).fi zu ei ausgewertet werden. (Zugriff auf das Feld fiergibt den Wert des entsprechenden Feldes – unter der Randbedingung, dassder Konstruktor alle Felder mit den ubergebenen Werten fullt.)

8.2 Featherweight Java

• Reduktion von Java auf einen minimalen Kern: Funktionaler Kern + Vererbungund Casting.

• Funktionaler Kern (Seiteneffekt-Freiheit, vgl. Lambda-Kalkul):

– Alle Felder und Parameter sind implizit final .

– Felder werden im Konstruktor initialisiert und danach nicht mehr verandert.

– Jede Methode besteht aus einer einzigen return -Anweisung.

• Abgedeckt werden alle Aspekte, die fur Polymorphismus relevant sind:

– Objekt-Erzeugung

– Wechselseitig rekursive Klassen-Definitionen

– Zugriff auf Felder und Aufruf von Methoden

Informatik B • SS 02 103

– Uberschreiben von Methoden

– Unterklassen (subtyping)

– Casting

• Um Regularitat in den Klassendefinitionen zu haben, wird zu jeder Klasse ihrObertyp explizit angegeben (auch wenn es Object ist), wird immer einKonstruktor explizit definiert, wird immer der Empfanger bei Feld-Zugriffen oderMethoden-Aufrufen angegeben (auch wenn es this ist).

8.2.1 Programmbeispiel

class A extends Object { A() { super(); } }class B extends Object { B() { super(); } }class Pair extends Object {

Object fst; // first element of a pairObject snd; // second element of a pairPair(Object fst, Object snd) {

super(); this.fst = fst; this.snd = snd;}Pair setfst(Object newfst) {

return new Pair(newfst, this.snd);}

}

• Funf Arten von Ausdrucken: (ei sind Platzhalter fur Ausdrucke)

1. Object constructors: new A() , new B() , new Pair(e1, e2)

2. Method invocation: e3.setfst(e4)

3. Field access: this.snd

4. Variable: newfst , this (this wird in FJ als Variable aufgefasst)

5. Cast: (Pair) e5

• Da (ausser in Konstruktoren) keine Zuweisung erlaubt ist, wird auf dasSchlusselwort final verzichtet: Felder werden nur einmal belegt,Methoden-Parameter werden im Korper nicht manipuliert.

Im Kontext der Klassen-Definitionen A, B und Pair konnen Ausdrucke ausgewertetwerden:

• new Pair(new A(), new B()).setfst(new B())evaluiert zu new Pair(new B(), new B())

• ((Pair) new Pair(new Pair(new A(), new B()),new A()).fst).snd

evaluiert zu new B()

Dabei bezeichnet new X() ein Objekt vom Typ X.Die Auswertung (Reduktion) wird im folgenden formal gefaßt.

104 Informatik B • SS 02

L ::= class C extends D {C f ; K M} // class declarationsK ::= C( D g, C f ) {super( g); this. f=f ; } // constructor declarationM ::= C m( C x) { return e; } // method declaratione ::= x | e. f | e. m( e) | new C( e) | ( C) e // expression declaration

• Platzhalter fur Klassennamen: A, B, C, D, E

• Platzhalter fur Felder: f, g

• Platzhalter fur Methodennamen: m

• Platzhalter fur Variablen: x

• Platzhalter fur Ausdrucke: d, e

• Sequenzen:f fur f1, . . . , fn etc. (beiM ohne Kommata),Cf furC1 f1; . . . Cn fn;• Leere Sequenz:•, Lange von Sequenzen#(x)

Abbildung 35: Syntax fur FJ

8.2.2 Syntax fur FJ

• Die Syntax von FJ kann abstrakt angegeben werden (siehe Abb. 35): hier eineArt EBNF mit Zusatzsyntax.

• Klassendeklaration: Neue Klasse C mit Oberklasse D, Felder C1f1; . . . ;Cnfn(keine primitiven Typen, Instanzvariablen erweitern die Menge der in denOberklassen deklarierten Variablen – Namen mussen echt verschieden sein,kein shadowing), ein Konstruktor K und Methodendeklarationen M1 . . .Mm.

• Konstruktordeklaration: Es mussen alle Felder der Klasse explizit initialisiertwerden, der Konstruktor muss genauso viele Parameter erhalten, wie es Feldergibt. Der Oberklassenkonstruktor muss aufgerufen werden.

• Methodendeklaration: immer mit Ruckgabetyp, Variablen x und this sind imAusdruck e gebunden.

8.2.3 Subtyping

• Definition einer Klassentabelle CT: Abbildung von Klassennamen C aufKlassendeklarationen L.

• Tabelle CT hat als Domain (dom) eine Menge von Klassennamen C.

• Zur Vereinfachung wird jeweils eine feste Tabelle angenommen.

• Ein Programm ist ein Paar (CT, e) einer Klassentabelle und eines Ausdrucks.(siehe Programmbeispiel weiter oben)

• Klasse Object wird speziell behandelt: erscheint nicht in CT, hat keine Felderund Methoden (Vereinfachung gegenuber Java)

• Untertyp-Relationen konnen uber CT ermittelt werden.

• Untertyp-Regeln sind in Abb. 36 angegeben.

Informatik B • SS 02 105

class C extends D { ... }C <: D // Untertyp

C <: C // ReflexivitatC <: D D <: E

C <: E // Transitivitat

Abbildung 36: Subtyping Regeln fur FJ

• Jede Klassendefinition legt eine direkte Unterklassenbeziehung fest. Die beidenweiteren Regeln ermoglichen es, die reflexive und transitive Hulle derUnterklassenbeziehungen zu ermitteln.

• CT muss einige Korrektheitsbedingungen (sanity conditions) erfullen:

– CT(C) = class C ... fur jedes C ∈ dom(CT ).

– Object /∈ dom(CT ).

– Fur alle Klassennamen C (ausser Object ) in CT, gilt C ∈ dom(CT )

– Es existieren keine Zyklen in der Subtyp-Relation, die durch CT induziertist, d.h. die Relation <: ist antisymmetrisch.

• Typen durfen rekursiv (und wechselseitig rekursiv) sein:Die Definition einer Klasse A darf Methoden und Instanzvariablen, in denen Avorkommt, besitzen.

8.2.4 Hilfsfunktionen

• Zur Definition der Typisierungs- und Reduktionsregeln werden einigeHilfsfunktionen benotigt, die in Abb. 37 angegeben sind.

• m /∈ M : Definition von Methode m kommt in den Methodendeklarationen Mnicht vor.

• fields(C) ist eine Sequenz von Paaren Cf : Typen und Namen aller Felder derKlasse C und ihrer Oberklassen.

• mtype(m, C) liefert die Signatur einer Methode als B → B (Argumenttypen undResultattyp).

• mbody(m, C) liefert einen Ausdruck und die darin gebundenen Variablen x.eBeispiel:Der Ausdruck e = new Pair(newfst, this.snd) enthalt die Variablen x =newfst, this .

• mtype() und mbody() sind partielle Funktionen (undefiniert fur Object ).

106 Informatik B • SS 02

Abbildung 37: Hilfsfunktionen fur FJ

Informatik B • SS 02 107

8.3 Typisierung und Reduktion in FJ

8.3.1 Typisierungsregeln

• Die Typisierungsregeln sind in Abb. 38 angegeben.

• Sie definieren, unter welchen Bedingungen (uber dem Strich angegeben) einAusdruck zu einem bestimmten Typ auswertet bzw. ob Klassen und Methodenkorrekt definiert wurden.

• Es gibt Typisierungsregeln fur Klassen, Methoden und Ausdrucke.

• Typisierung erfolgt bzgl. eines Environments Γ, das eine endliche Abbildung vonVariablen auf Typen x : C festlegt.

• Typisierungs-Aussagen fur Ausdrucke haben die Form: Γ ` e : C, lies “inEnvironment Γ hat Ausdruck e den Typ C”.

• Es gibt fur jede der funf syntaktischen Arten von Ausdrucken eineTypisierungsregel – nur fur Casts gibt es drei Regeln.

• Fur Casts werden Upcast, Downcast und “stupid cast” betrachtet. Der “stupidcast” behandelt Falle, in denen die Zielklasse bzgl. der Klassenhierarchieunverbunden mit der Klasse des aktuellen Objekts ist.

• “stupid casts” werden im Formalismus benotigt, weil wahrend der Anwendungvon Reduktionsregeln aus zulassigen Casts “stupid casts” entstehen konnen:(Beispielprogramm von oben)(A) (Object)new B() → (A)new B()(Object) new B() wird zunachst zu new (B) reduziert: Der Upcast istzulassig, aber es handelt sich um ein Objekt vom Typ B. Der Cast zurunverbundenen Klasse A ist unzulassig.

• Die Typisierungsregeln (bis auf “stupid cast”) entsprechen der Semantik derTypisierung in Java.

• Typisierungs-Aussagen fur Methoden-Deklarationen haben die Form M OK INC – “Methoden-Deklaration M ist ok, wenn sie in Klasse C auftaucht”.Fur Overriding gilt: Die Methode der Unterklasse muss denselben Typ habenwie die der Oberklasse.

• Typisierungs-Aussagen fur Klassen-Deklarationen: Es muss gelten, dass derKonstruktoraufruf korrekt ist (Aufruf von super() mit den Feldern derOberklasse und Initialisierung der Klassenfelder) und dass jedeMethodendeklaration ok ist.

• Uber die Hilfsfunktionen kann jede Methode unabhangig von den anderenMethoden gepruft werden.

8.3.2 Reduktionsregeln

• Die Reduktionsregeln sind (zusammen mit Kongruenzregeln) in Abb. 39angegeben.

108 Informatik B • SS 02

Abbildung 38: Typisierungsregeln fur FJ

Informatik B • SS 02 109

• Reduktionsregeln beschreiben, wie ein Ausdruck ausgewertet wird(computation).

• Anwendung einer Reduktionsregel auf einen gegebenen Ausdruck: Prufen, obAnwendungsbedingungen (uber dem Strich) gelten, Finden einesUnterausdrucks, der mit der linken Seite der Reduktionsregel matched (gleichist, wenn Variablen entsprechend substitutiert werden konnen), ersetzen diesesUnterausdrucks durch die rechte Regelseite (in der Variablen durch substituiertwurden).Anmerkungen: Mit Variablen sind hier Platzhalter in den Reduktionsregelngemeint. Beispielsweise steht fi fur den Namen eines Feldes. Dieses konnntebeispielsweise fur die Klasse C = Pair durch fst substituiert werden und eimeint dann den Wert dieses Feldes, z.B. new B() .

• Sie haben die Form e→ e′ (ein Ableitungsschritt). Ganze Ketten vonAuswertungen werden mit ∗→ notiert (reflexive und transitive Hulle)

• Es gibt drei Reduktionsregeln: fur Feldzugriff, fur Methodenaufruf und furCasting.

• [d/x, e/y]e0 meint: in Ausdruck e0 werden Variablen xi durch Ausdrucke di undVariable y durch Ausdruck e ersetzt.

• Die Kongruenzregeln beschreiben, wie mit Teilausdrucken umgegangen wird,z.B.: wenn e→ e′ dann auch e.f → e′.f .

• Die Beziehung zwischen Typisierung und Auswertung sollte in Java (FJ)typkorrekt sein. Das heißt, fur korrekt typisierte Ausdrucke sollte die Auswertungsolcher Ausdrucke wieder typkorrekt sein!

• Dies kann fur FJ formal bewiesen werden: Wenn ein wohltypisierter Termreduziert wird, dann ist das Resultat entweder von einem Untertyp des Typs desOriginalterms oder ein Ausdruck, bei dem ein unzulassiger Downcast versuchtund abgewiesen wird.

• Ist keine Regel anwendbar, wird die Berechnung gestoppt (run time error).

8.3.3 Veranschaulichung

• Die Beweise sind in dem entsprechenden Artikel von Igarashi et al.nachzulesen.

• Beweis-Idee: Fur beliebige Ausdrucke von FJ wird gezeigt, dass die Anwendungder Reduktionsregeln auf korrekt typisierte Ausdrucke dann wieder zu korrekttypisiertenn Ausdrucken fuhrt, wenn nur upcasting vorkommt.

• Anstelle der Beweise wird im folgenden veranschaulicht, wie mit dem formalenKalkul von FJ, das die Semantik der Auswertung von Ausdrucken beschriebt,“gerechnet” werden kann.

110 Informatik B • SS 02

Abbildung 39: Reduktionsregeln fur FJ

Informatik B • SS 02 111

Feldzugriff: Anwendung von Regel R-FIELDnew Pair(new A(), new B()).snd → new B()Methoden-Aufruf: Anwendung von Regel R-INVKnew Pair(new A(), new B()).setfst(new B())

→[

new B()/newfst ,new Pair(new A(), new B())/this

]new Pair(newfst, this.snd)

new Pair(new B(), new Pair(new A(), new B()).snd)Casting:((Pair) new Pair(new Pair(new A(), new B()), new A()).fst).snd→ ((Pair) new Pair(new A(), new B())).snd→ new Pair(new A(), new B()).snd→ new B()Der Adressat des Cast wird zunachst zu einem Objekt (z. B. new A() ) reduziert.Wenn dieses Objekt zu einer Unterklasse des Target, gehort wird der Cast entfernt,anderenfalls ergibt sich ein Laufzeitfehler, z. B. fur (A) new(B) .

Drei Moglichkeiten, dass Berechnung scheitert:

• Versuch, auf ein Feld zuzugreifen, das nicht zur Klasse gehort.Passiert nicht in wohl-typisierten Programmen (Beweis)

• Versuch, eine Methode aufzurufen, die nicht zur Klasse gehort.(dito)

• Versuch, etwas zu einer Klasse zu casten, die nicht Oberklasse ist.Passiert nicht in wohl-typisierten Programmen, die keine Downcasts(“narrowing”) enthalten.

112 Informatik B • SS 02

9 Abstrakte Klassen und Interfaces

9.1 Abstrakte Klassen und Methoden

• Beispiel Circle (ist inzwischen Teil eines Pakets myshapes2 ).

• Erweiterung: Implementation einer Vielzahl verschiedener Shape -Klassen:Circle , Rectangle , Square , Ellipse , Triangle , ...

• Alle Shape -Klassen sollen area() - und circumference() -Methoden haben.

• Arbeiten mit einem Array von Shape -Objekten: Es ware gunstig, wenn einegemeinsame Oberklasse Shape existiert, die alle Komponenten definiert, dieallen geometrischen Formen gemeinsam sind.

• Was ist mit den Methoden area() und circumference() ?(Ohne konkrete geometrische Gestalt ist Berechnungsvorschrift unbekannt.)↪→ abstrakte Methoden!

• Abstrakte Methode: Definition ohne Implementation (Korper); Modifikatorabstract ; Methodenkopf abgeschlossen durch Semikolon.

• Jede Klasse, die eine abstrakte Methode enthalt, ist selbst abstrakt und mussals abstract deklariert werden.

• Eine abstrakte Klasse kann nicht instantiiert werden (keine Objekt-Erzeugungmit new moglich).

• Eine Unterklasse einer abstrakten Klasse kann nur instantiiert werden, wennalle abstrakten Methoden der Oberklasse implementiert werden.↪→ “konkrete” Unterklasse

• Eine Unterklasse, die nicht alle abstrakten Methoden implementiert, ist selbstabstrakt.

• static - und final -Methoden konnen nicht abstrakt sein, da diese nicht voneiner Unterklasse uberschrieben werden konnen.private Methoden sind implizit final . Ebenso konnen final Klassen keineabstrakten Methoden enthalten.

• Klassen konnen abstract deklariert werden, auch wenn sie keine abstraktenMethoden enthalten.Hinweis, dass Methoden unvollstandig sind und dass die Methode alsOberklasse fur konkrete Unterklassen gedacht ist.(Abstrakte Klassen konnen generell nicht instantiiert werden.)

• Objekte von Unterklassen konnen direkt (ohne Cast) an Variablen (z. B.Elemente eines Arrays von Shapes) der Oberklasse zugewiesen werden.

• Abstrakte Methoden der Oberklasse konnen fur jedes Objekt einer konkretenUnterklasse aufgerufen werden (dynamic method lookup).

Informatik B • SS 02 113

public abstract class Shape {public abstract double area(); // Abstract methods: notepublic abstract double circumference(); // semicolon instead of body

}

public class Circle extends Shape {public static final double PI = 3.14159265358979323846;protected double r; // Radius is hidden, but visible to subclasses

< code omitted ... >

// Methods to operate on the instance field// Implementation of abstract shape methodspublic double area() { return PI * r * r; }public double circumference() { return 2 * PI * r; }

}

public class Rectangle extends Shape {protected double w, h; // Instance fields

// width and height< code omitted ... >

// Instance methods// implementation of abstract methodspublic double area() { return w * h; }public double circumference() { return 2 * (w + h); }

}

Shape[] shapes = new Shape[3]; // Create an Array to hold shapesshapes[0] = new Circle(2.0); // Fill in the arrayshapes[1] = new Rectangle(1.0, 3.0);shapes[2] = new Rectangle(4.0, 2.0);

double total_area = 0;for (int i = 0; i < shapes.length; i++)

total_area += shapes[i].area(); // Compute area of shapes

9.2 Interfaces

• Nachste Erweiterung des Shapes -Beispiels: Nicht nur Grosse, auch Positionder geometrischen Objekte in der Ebene.

• Erste Idee: weitere abstrakte Klasse CenteredShape mit UnterklassenCenteredCircle , CenteredRectangle , ...

• CenteredCircle soll naturlich auch die Methoden von Circle erben.

• Problem: Java erlaubt nicht, dass eine Klasse mehr als eine Oberklasse hat!(Mehrfachvererbung)

114 Informatik B • SS 02

• Java Losung: Interfaces (Schnittstellen)Eine Klasse kann beliebig viele Interfaces implementieren.

• Ein Interface ist ein Referenztyp sehr ahnlich einer Klasse: Definiert wird eineFunktionalitat und nicht eine Implementation (Realisierung), ein Interface gibtSignaturen – Namen und Typen von Methoden (und Konstanten) – vor.

• Ein Interface wird mit dem Schlusselwort interface deklariert.

• Ein Interface enthalt keinerlei Methoden-Implementation.Alle Methoden sind implizit abstrakt, auch wenn ohne diesen Modifikatordeklariert.Ein Interface kann nur Instanz-Methoden enthalten.

• Ein Interface ist ohne Sichtbarkeitsmodifikator paketsichtbar. Als einzigerSichtbarkeitsmodifikator darf public angegeben werden. Alle Methoden sindimplizit public , auch wenn der Modifikator nicht explizit angegeben ist.Es ist ein Fehler, protected oder private Methoden in einem Interface zudeklarieren!

• Ein Interface kann keine Instanz-Felder definieren, aber als static und finaldeklarierte Konstanten.

• Da ein Interface nicht instantiiert werden kann, definiert es keinen Konstruktor.

• Interfaces sind reine Spezifikationen!

9.2.1 Implementation eines Interfaces

• Unterklasse extends <Oberklasse >Klasse implements <Interface >Schlusselwort implements folgt nach extends (falls Oberklasse angegeben);wird von einem oder mehreren (durch Komma getrennte) Namen von Interfacesgefolgt.

• implements bedeutet, dass in der implementierenden Klasse die Korper furMethoden des Interfaces definiert werden. Werden nicht alle Methodenimplementiert, so ist die Klasse abstrakt und muss als solche deklariert werden.(Alle Methoden des Interfaces werden Teil der Klasse.)

public interface Centered {public void setCenter(double x, double y);public double getCenterX();public double getCenterY();

}

public class CenteredRectangle extends Rectangle implements Centered {private double cx, cy; // New instance fields

public CenteredRectangle(double cx, double cy, double w, double h) {super(w, h);

Informatik B • SS 02 115

this.cx = cx;this.cy = cy;

}

// We inherit all the methods of Rectangle, but must// provide implementations of all the Centered methods.public void setCenter(double x, double y) { cx = x; cy = y; }public double getCenterX() { return cx; }public double getCenterY() { return cy; }

}

9.2.2 Interfaces und Konstanten

• Konstanten durfen in Interface-Deklarationen vorkommen.

• Alle Felder, die in einem Interface deklariert werden, werden implizit als staticund final aufgefasst, auch wenn nicht explizit so deklariert.

• Es ist jedoch guter Stil, diese Modifikatoren explizit anzugeben!

• Jede Klasse, die das Interface implementiert, erbt die Konstanten und kann siebenutzen, als waren sie direkt in der Klasse selbst deklariert (keineVoranstellung des Interface-Namens vor den Konstanten-Namen notwendig).

• Konstanten mussen nicht unbedingt mit festen Werten initialisiert werden:

public interface RandVals {int rint = (int) (Math.random() * 10);long rlong = (long) (Math.random() * 10);float rfloat = (float) (Math.random() * 10);double rdouble = Math.random() * 10;

}

• Manchmal nutzlich: Interface, das nur Konstanten enthalt.Konstanten, die von mehreren Klassen benutzt werden (wie Port-Nummern, dievon Client und Server benutzt werden).

• Beispiel: java.io.ObjectStreamConstants (Konstanten fur JavasSerialisierungs-Mechanismus)

9.2.3 Benutzung von Interfaces

• Wenn eine Klasse ein Interface implementiert, konnen Objekte dieser Klasse aneine Variable vom Typ des Interfaces zugewiesen werden.

• <Object > instanceof <Interface/Klasse > liefert Wahrheitswert.

Shape[] shapes = new Shape[3]; // Create an array to hold shapes

// Create some centered shapes, and store them in the Shape[]

116 Informatik B • SS 02

<<interface>>Centered

Square

CenteredCircle

CenteredRectangle

CenteredSquare

Rectangle

CircleShape

Abbildung 40: Struktur derShape -Klassen

// No cast necessary

shapes[0] = new CenteredCircle(1.0, 1.0, 1.0);shapes[1] = new CenteredSquare(2.5, 2, 3);shapes[2] = new CenteredRectangle(2.3, 4.5, 3, 4);

// Compute average area of the shapes and average distance from the origindouble totalArea = 0;double totalDistance = 0;for (int i = 0; i < shapes.length; i++) {

totalArea += shapes[i].area(); // Compute the area of the shapesif (shapes[i] instanceof Centered) { // The shape is a Centered shape// Note the required cast from Shape to Centered// No cast would be required to go from CenteredSquare to Centered etc.

Centered c = (Centered) shapes[i]; // Assign it to a Centered variabledouble cx = c.getCenterX();double cy = c.getCenterY();totalDistance += Math.sqrt(cx*cx + cy*cy);

}}System.out.println("Average area: " + totalArea/shapes.length);System.out.println("Average distance: " + totalDistance/shapes.length);

9.2.4 Interface vs. Abstrakte Klasse

• Entwurfsentscheidung zwischen abstrakter Klasse und Interface.

• + Interface: Jede Klasse kann es implementieren. Zwei nicht verwandte Klassenkonnen dasselbe Interface implementieren.− Abstrakte Klasse: Nur eine Klasse kann Oberklasse einer anderen Klassesein.

• − Interface: Nur abstrakte Methoden; wenn Methoden fur viele Klassen gleichsind, so mussen sie immer neu implementiert werden.

Informatik B • SS 02 117

+ Abstrakte Klasse: Kann Default-Implementation fur typische Methoden liefern.

• Kompatibilitat: Wenn Interface zum public API hinzugefugt wird und spater dasInterface um eine Methode erweitert wird, so sind alle Klassen, die das Interfaceimplementieren, “kaputt”.Zu abstrakten Klassen konnen implementierte Methoden gefahrlos hinzugefugtwerden.

• Manchmal nutzlich: Abstrakte Klasse, die ein Interface implementiert undDefault-Implementationen fur Methoden der Unterklassen liefert.(Adapter-Klasse)Alternativ: Delegate-Pattern (Support-Klasse), die Methoden eines Interfaceimplementieren. Eigene Klasse, die das Interface implementiert, kann alsKomponente ein Objekt einer Support-Klasse (die dasselbe Interfaceimplementiert) erzeugen (siehe Vorlesung Infomatik C).

// Here is a basic interface. It represents a shape that fits inside// a rectangular bounding box. Any class that wants to serve as a// RectangularShape can implement these methods from scratch.public interface RectangularShape {

public void setSize(double width, double height);public void setPosition(double x, double y);public void translate(double dx, double dy);public double area();

}

// Here is a partial implementation of that interface.// Many implementations may find this a useful starting point.public abstract class AbstractRectangularShape implements RectangularShape {

// The position and size of the shapeprotected double x, y, w, h;

// Default implementations of some of the interface methodspublic void setSize(double width, double height)

{ w = width; h = height; }public void setPosition(double x, double y) { this.x = x; this.y =y; }public void translate(double dx, double dy) { x += dx; y += dy; }

}

9.2.5 Implementation mehrerer Interfaces und Erweitern von Interfaces

• Wenn die Klasse, die mehrere Interfaces implementiert, nicht abstrakt sein soll,so mussen die Methoden aller Interfaces implementiert werden.

public class SuperDuperSquare extends Shapeimplements Centered, Scalable {// Methods omitted

}

118 Informatik B • SS 02

• Wie Klassen Unterklassen haben konnen, so konnen Interfaces Unter-Interfaceshaben.

• Bei Interfaces durfen hinter extends mehrere andere Interfaces stehen.

public interface Positionable extends Centered {public void setUpperRightCorner(double x, double y);public double getUpperRightX();public double getUpperRightY();

}public interface Transformable extends

Scalable, Translatable, Rotatable {}public interface SuperShape extends

Positionable, Transformable {}

• Hier kann man sich das Problem der Mehrfachvererbung teilweise docheinhandeln. Es gelten folgende Regeln, wenn Methoden gleichen Namens inverschiedenen (zu implementierenden, zu erweiternden) Interfaces deklariertwerden:

– Methoden mit gleichem Namen und gleicher Signatur werden einmalaufgenommen.

– Methoden mit gleichem Namen und verschiedenen Signaturen sinduberladen.

– Methoden mit gleichem Namen, gleichen Parametern und verschiedenemRuckgabetyp fuhren zu Ubersetungs-Fehler.

– Bei Methoden mit gleicher Signatur und verschiedenen spezifiziertenExceptions muss die “Schnittmenge” dieser Exceptions oder eineTeilmenge davon spezifiziert werden.

interface X {void setup() throws SomeException;

}

interface Y {void setup();

}

class Z implements X, Y {public void setup() {

// ...}

}

Folgender Code fuhrt zu einem ubersetzungs-Fehler:

interface X {

Informatik B • SS 02 119

void setup() throws FileNotFoundException;}

interface Y {void setup() throws IOException;

}

// Schnittmenge ist FileNotFoundExceptionclass Z implements X, Y {

public void setup() throws IOException {// ...

}}

9.2.6 Marker-Interfaces

• Manchmal ist es nutzlich, ein leeres Interface zu definieren.

• Klasse, die dieses Interface implementiert, muss keine Methodenimplementieren.

• Jede Instanz der Klasse ist zulassige “Instanz” des Interfaces.Prufbar mit instanceof

• Beispiele: Cloneable und java.io.Serializable

MyClass o; // Initialized elsewhereMyClass copy;if (o instanceof Cloneable) copy = o.clone();else copy = null;

9.3 Das Enumerator-Interface

• Idee: Fur eine Datenstruktur, die Elemente halt, sollen diese Elementeaufgezahlt werden.

• Typisch fur Collection-Klassen (siehe Kapitel ‘Collection-Klassen’), in denenObjekte gehalten werden.Beispiele: Stack, LinkedList

• Vordefiniertes Enumeration -Interface mit zwei Methoden:

– boolean hasMoreElements() : true, wenn die Aufzahlung noch weitereElemente enthalt, false sonst

– Object nextElement() : liefert das nachste Element, falls es existiert,sonst wird eine Exception ausgelost.

Beispiel: Collection ist einfache Array-Liste

• Objekte werden in einem Array abgelegt (Methode add() )

120 Informatik B • SS 02

• Wenn der Array gefullt ist, werden keine weiteren Elemente mehr angenommen.

• Es fehlen Methoden zum Loschen, zum Prufen, ob ein Element enthalten ist (mitentsprechender equals() -Methode), evtl. eine Methode zum Vergroßern desArrays, etc.

public class MyList {public static final int MAX = 100;protected Object[] list = new Object[MAX];protected int numOfEls = 0;

public boolean add(Object o) {if (numOfEls >= MAX)

return false;else {

list[numOfEls++] = o;return true;

}}

public Object get (int i) {return list[i];

}

public int size() {return numOfEls;

}}

Eine unelegante Art, den Inhalt einer Liste aufzuzahlen, ist es, mit einer Schleife uberdie Liste zu laufen:

MyList intlist = new MyList();for (int i=0; i < 10; i++) {

intlist.add(new Integer(i));}

// enumerate elements by indexfor (int i=0; i < intlist.size(); i++) {

System.out.println(intlist.get(i));

• Aufzahlen uber Index geht nur fur Collection-Klassen, die Index-Zugriff erlauben.

• Alternativ: Erzeugen eines Ennumerators fur MyList -Objekte.

• Ein Enumerator fur MyList muss das Enumeration -Interfaceimplementieren:

Informatik B • SS 02 121

public class ListEnumerator implements Enumeration {protected int current = 0;protected MyList collection;

public ListEnumerator(MyList c) { collection = c; }

public boolean hasMoreElements() {return current < collection.numOfEls;

}

public Object nextElement() {if (! hasMoreElements())

throw new java.util.NoSuchElementException();return collection.list[current++];

}

}

Jetzt kann der Inhalt der Liste folgendermaßen ausgegeben werdenn:

ListEnumerator enum = new ListEnumerator(intlist);while (enum.hasMoreElements()) System.out.println(enum.nextElement());

122 Informatik B • SS 02

10 Innere Klassen

• Bisher: “top-level” Klassen (direkte Mitglieder eines Pakets).Seit Java 1.1: Innere Klassen: definiert innerhalb einer anderen Klasse(Komponente einer Klasse, ahnlich Felder und Methoden)

• Vier Arten von inneren Klassen:

– Member Classes (“echte” innere Klasse)

– Static Member Classes (Nested Top-Level Classes)

– Local Classes

– Anonymous Classes

10.1 Member Classes

10.1.1 Anschauliches Beispiel

• Ein Paket ist ein strukturiertes Objekt, das aus Inhalt und Zielort aufgebaut ist.

• Sowohl Inhalt als auch Zielort sind selber Klassen mit Feldern und Methoden.

• Anmerkung: Wenn zwei Klassen in einer “Hat ein”/”ist Teil von” Beziehungstehen, bietet sich haufig eine Modellierung mit inneren Klassen an.(Komposition, siehe Abb. 41)

public class Parcel1 { // Bruce Eckelclass Contents {

private int i = 11;public int value() { return i; }

}class Destination {

private String label;Destination(String whereTo) {

label = whereTo;}String readLabel() { return label; }

}// Using inner classes looks just like// using any other class, within Parcel1:public void ship(String dest) {

Contents c = new Contents();Destination d = new Destination(dest);

}public static void main(String[] args) {

Parcel1 p = new Parcel1();p.ship("Tanzania");

}}

Informatik B • SS 02 123

i: Integer

value(): Integer

Contents

Destination

label: String

Parcel

ship(dest: String)

part−of

part−of

has

has

Abbildung 41: Ein Paket besteht aus Inhalt und Zielort

• In der Methode ship werden Inhalt und Zielort fur ein bestimmtes Paketerzeugt.

• Haufig hat die außere Klasse Methoden, um eine Referenz (“Handle”) auf einObjekt der inneren Klasse zu liefern.

public class Parcel2 {class Contents {

private int i = 11;public int value() { return i; }

}class Destination {

private String label;Destination(String whereTo) {

label = whereTo;}String readLabel() { return label; }

}public Destination to(String s) {

return new Destination(s);}public Contents cont() {

return new Contents();}public void ship(String dest) {

124 Informatik B • SS 02

Contents c = cont();Destination d = to(dest);

}public static void main(String[] args) {

Parcel2 p = new Parcel2();p.ship("Tanzania");Parcel2 q = new Parcel2();// Defining handles to inner classes:Parcel2.Contents c = q.cont();Parcel2.Destination d = q.to("Borneo");

}}

• Beachte: Ein Objekt einer inneren Klassen kann nur zusammen mit einemObjekt der umschliessenden Klasse existieren.

• Erst neues Paket erzeugen, dann Inhalt und Zielort fur dieses Paket erzeugen!

• Es ist nicht moglich, ein Objekt zum Typ Destination zu erzeugen, ohne dassein Paket, zu dem diese Destination gehoren soll, existiert!

10.1.2 Beispiel ‘Enumerator’

public class MyListMC {public static final int MAX = 100;protected Object[] list = new Object[MAX];protected int numOfEls = 0;

public boolean add(Object o) {if (numOfEls >= MAX)

return false;else {

list[numOfEls++] = o;return true;

}}

public int size() {return numOfEls;

}

public java.util.Enumeration enumerate() {return new Enumerator();

}

protected class Enumerator implements java.util.Enumeration {protected int current = 0;

// constructor not necessary

Informatik B • SS 02 125

public Enumerator() { current = 0; }

public boolean hasMoreElements() {return current < numOfEls;

}

public Object nextElement() {if (! hasMoreElements())

throw new java.util.NoSuchElementException();return list[current++];

}}

}

Erzeugen und Anwenden des Enumerators:

MyListMC intlist = new MyListMC();for (int i=0; i < 10; i++) {

intlist.add(new Integer(i));}

java.util.Enumeration enum = intlist.enumerate();while (enum.hasMoreElements()) System.out.println(enum.nextElement());

10.1.3 Eigenschaften von Member-Klassen

• Member-Klassen sind die typischen, “echten” inneren Klassen.

• Member-Klassen sind wie Instanz-Felder und -Methoden mit einer Instanz derKlasse, in der sie definiert sind, assoziiert.Also: Zugriff auf alle Komponenten der umschliessenden Klasse.

• Member-Klassen konnen beliebig tief geschachtelt werden. D. h., eine innereKlasse kann weitere innere Klassen enthalten.

• Eine Member-Klasse kann mit allen Sichtbarkeits-Modifikatoren deklariertwerden.

• Name muss verschieden vom Namen der umschliessenden Klasse sein.

• Member-Klassen durfen keine statischen Komponenten enthalten. Ausnahme:static und final deklarierte Konstanten.

• Interfaces konnen nicht als Member-Klassen definiert werden, da Interfaceskeine Instanz-Variablen besitzen durfen (also kein this -Verweis moglich).

• Wichtigstes Merkmal: Zugriff auf Instanz-Felder und -Methoden derumschliessenden Klasse.current < numOfElsWie funktioniert explizite Referenz?this.current < this.numOfEls

126 Informatik B • SS 02

Problem: this.numOfEls ist nicht zulassig (this bezieht sich aufEnumerator-Objekt)↪→ Erweiterte Syntax:this.current < MyListMC.this.numOfElsDiese Zugriffsform ist dann notwendig, wenn man sich auf eine Komponenteeiner ausseren Klasse beziehen will, die denselben Namen hat wie eineKomponente der inneren Klasse.

• Analoge Erweiterung der super -Syntax (Zugriff auf eine uberdeckte oderuberschriebene Komponente der Oberklasse der umschliessenden Klasse:<Klassenname >.super. <feld ><Klassenname >.super. <methode >

• Ausfuhrung des Member-Klassen Konstruktors bewirkt, dass die neue Instanzmit dem this Objekt der umschliessenden Klasse assoziiert wird.Gleichbedeutende Schreibweisen:public Enumeration enumerate() { return new Enumerator(); }public Enumeration enumerate() { return this.new Enumerator(); }

• Anstelle der Definition von enumerator() konnte eine Enumeration auch soerzeugt werden:MyListMC intlist = new MyListMC(); // Create empty listEnumeration enum = intlist.new Enumerator();

// Create Enum for it

Da die umschliessende Instanz implizit den Namen der umschliessendenKlasse spezifiziert, ist die explizite Angabe der Klasse ein Syntaxfehler:Enumeration e = intlist.new MyListMC.Enumerator();

// Syntax error

10.1.4 Implementation von Member-Klassen

• Innere Klassen seit Java 1.1.

• Erweiterung der Sprache (“syntactic sugar”) aber nicht der JVM: Java Compilerwandelt Reprasentation von inneren Klassen entsprechend um.(Disassemblierung mit javap , um zu sehen, welche Tricks der Compilerbenutzt.)

• Compilation in eigene top-level-Datei.

• Compiler muss Code so manipulieren, dass Zugriff auf Komponenten zwischeninnerer und ausserer Klasse funktioniert.

• this$0 Feld fur jede Member-Klasse (Assoziation mit Instanz derumschliessenden Klasse; Abspeichern der entsprechenden Referenz). Furweitere Referenzen zu umschliessenden Klassen wird entsprechendweitergezahlt (this$1 , etc.).

• Jeder Member-Klassen Konstruktor erhalt einen zusatzlichen Parameter, umdieses Feld zu initialisieren.

Informatik B • SS 02 127

• protected Member-Klassen werden public ; private Member-Klassenwerden default-sichtbar.

10.1.5 Member-Klassen und Vererbung

• Es ist erlaubt, dass eine top-level Klasse als Unterklasse einer Member-Klassedefiniert wird.

• Damit hat die Unterklasse keine umschliessende Klasse, aber ihre Oberklase!

• Wegen unklarer Semantik argumentieren einige dafur, dass diese Art derVererbung verboten werden soll.

• Atsushi Igarashi and Benjamin C. Pierce (2001). On inner classes. Informationand Control.Die Autoren haben bei der Definition einer Reduktions-Semantik fur innereKlassen und Vererbung Unterspezifikationen der Sprache Java aufgedeckt.

// A top-level class that extends a member classclass SpecialEnumerator extends MyListMC.Enumerator {

// The constructor must explicitely specify a containing instance// when invoking the superclass constructorpublic SpecialEnumerator(MyListMC l) { l.super(); }

// Rest of class omitted}

(Igarashi and Pierce, 2001)

class C {void who(){ System.out.println("I’m a C object"); }class D extends C{

void m(){ C.this.who(); }void who(){ System.out.println("I’m a C.D object"); }

}public static void main(String[] args){

new C().new D().m();}

}

• Qualified this: Fur eine innere Klasse C1.C2...Ci...Cn denotiert Ci.thisdie (n− i)-te direkt umschliessende Instanz; aber was ist, wenn Ci Superklassevon Cn ist?

• Compiliert mit JDK 1.1.7: I’m a C.D object (Compilerfehler),compiliert mit JDK 1.2.2: I’m a C object

• Zwei hierarchische Strukturen: Klassenhierarchie und Enthaltensein-Hierarchie(Containment)

• Es konnen Namenskonflikte zwischen vererbten Komponenten (Oberklasse)und Komponenten der umschliessenden Klasse auftreten.

128 Informatik B • SS 02

class A {int x;

}

class B {int x;class C extends A{

x; // inherited fieldthis.x; // inherited fieldB.this.x; // field of containing class

}}

10.2 Static Member Classes

10.2.1 Anschauliches Beispiel

• Alternative Modellierungsidee fur die Paket-Klasse:

– Inhalt und Zielort sind Objekte, die unabhangig von einem konkreten Paketexistieren konnen: diese Klassen benotigen keinen Zugriff auf Instanz-Felderund/oder -Methoden der Paket-Klasse.

– Statische innere Klassen dienen vor allem der Strukturierung von Programmcode.

abstract class Contents {abstract public int value();

}

interface Destination {String readLabel();

}

public class Parcel10 {private static class PContentsextends Contents {

private int i = 11;public int value() { return i; }

}protected static class PDestination

implements Destination {private String label;private PDestination(String whereTo) {

label = whereTo;}public String readLabel() { return label; }

}public static Destination dest(String s) {

return new PDestination(s);

Informatik B • SS 02 129

}public static Contents cont() {

return new PContents();}public static void main(String[] args) {

Contents c = cont();Destination d = dest("Tanzania");

}}

10.2.2 Eigenschaften von Static Member Classes

• Wahrend Member-Klassen analog zu Instanz-Feldern und -Methoden zu sehen sind,sind static member classes ahnlich wie Klassen-Felder und -Methoden zu verstehen.(“class class”)

• Sie haben Zugriff auf alle statischen Komponenten der umschliessenden Klasse.

• Static member classes werden auch als nested top-level classes bezeichnet.

• Interfaces durfen nur als static members definiert werden.

• Static Klassen konnen in einem Interface deklariert werden.

• Static member classes (und Interfaces) werden wie top-level Klassen behandelt. Siesind nicht mit einer Instanz der umschliessenden Klasse assoziiert (also: keinumschliessendes this -Objekt).

• Deklaration mit Zugriffsmodifikator genau wie fur andere Komponenten.

• Name muss verschieden vom Namen der umschliessenden Klasse sein.

• (unqualifizierter) Zugriff auf alle (auch privaten) statischen Komponenten derumschliessenden Klasse (inklusiver weiterer static member classes).Methoden der umschliessenden Klasse haben Zugriff auf alle Komponenten derMember-Klasse.

• Zugriff von externen Klassen: mit qualifiziertem Namen.Parcel10.PDestination

• Vorteil: Strukturierung, paket-ahnliche Organisation fur Klassen innerhalb einer Datei.

Merke: Member-Klassen (“echte” wie static deklarierte) sollen immer dann verwendetwerdenn, wenn eine Referenz “von innen nach aussen” benotigt wird. Auf derModellierungsebene heisst das: Ein Objekt ist aus anderen (inneren) Objekten aufgebaut, eskann nicht ohne diese inneren Objekte existieren, und die inneren Objekte benotigenInformation uber das umschliessende Objekt. Bei Member-Klassen werden Informationen derumschliessenden Instanz benotigt. Bei static deklarierten inneren Klassen werdenstatische bzw. keine Komponenten der umschliessenden Klasse benotigt, aber dieumschliessene Klasse kann auf Komponenten der inneren Klasse zugreifen.

10.2.3 Implementation von statischen Member-Klassen

• Compiler generiert zwei Klassen-Dateien, z.B. Parcel10.class undParcel10$PDestination.class (Innere Klasse PDestination wird zu top-levelKlasse).

130 Informatik B • SS 02

• Compiler qualifiziert Ausdrucke, die auf statische Komponenten der umschliessendenKlasse zugreifen, mit dem Klassennamen.

• Da auch auf private Komponenten zugegriffen werden darf: Automatische Generierungvon nicht-privaten Zugriffsmethoden (mit Default-Zugriffsrechten, paket-weit) undUmwandlung der entsprechenden Ausdrucke.

10.3 Lokale Klassen

10.3.1 Anschauliches Beispiel

• Alternative Modellierungsidee fur die Paket-Klasse

• Da die Klasse Zielort nur einmal, innerhalb der Methode dest() , benotigt wird, kanndie Klasse lokal definiert werden.

public class Parcel4 {public Destination dest(String s) {

class PDestinationimplements Destination {

private String label;private PDestination(String whereTo) {

label = whereTo;}public String readLabel() { return label; }

}return new PDestination(s);

}public static void main(String[] args) {

Parcel4 p = new Parcel4();Destination d = p.dest("Tanzania");

}}

10.3.2 Beispiel: ‘Enumerator’ als lokale Klasse

public class MyListLC {public static final int MAX = 100;protected Object[] list = new Object[MAX];protected int numOfEls = 0;

public boolean add(Object o) {if (numOfEls >= MAX)

return false;else {

list[numOfEls++] = o;return true;

}}

Informatik B • SS 02 131

public int size() {return numOfEls;

}

public java.util.Enumeration enumerate() {class Enumerator implements java.util.Enumeration {

protected int current = 0;

public boolean hasMoreElements() {return current < numOfEls;

}

public Object nextElement() {if (! hasMoreElements())

throw new java.util.NoSuchElementException();return list[current++];

}}return new Enumerator();

}}

10.3.3 Eigenschaften Lokaler Klassen

• Nicht Komponente einer Klasse, sondern innerhalb eines Blocks definiert.Typischerweise innerhalb einer Methode, auch innerhalb von Initialisierungsblocken.

• Analogie: Lokale Variable – lokale Klasse; Instanz-Feld – Member-Klasse

• Geltungsbereich: Innerhalb des Blocks

• Java ist eine lexically scoped Sprache:Geltungsbereich von Variablen ist durch ihre Position im Code definiert: innerhalb dergeschweiften Klammern, in die sie eingeschlossen sind.

• Wenn eine Member-Klasse nur innerhalb einer einzigen Methode der umschliessendenKlasse genutzt wird, kann sie ebenso gut als lokale Klasse definiert werden.

• Name muss verschieden vom Namen der umschliessenden Klasse sein.

• Interfaces konnen nicht lokal deklariert werden.

• Wie Member-Klassen: Zugriff auf alle Komponenten der umschliessenden Klasse.Zusatzlich auf alle im Block sichtbaren final Parameter und Variablen.

• Keine Sichtbarkeits-Modifikatoren erlaubt.

• Keine statischen Felder erlaubt (Ausnahme: static und final deklarierteKonstanten. (wie Member-Klassen)

• Zugriff auf sichtbare Variablen und Parameter nur, wenn diese final deklariert sind,weil die Lebensdauer einer Instanz einer lokalen Klasse langer sein kann als dieAusfuhrung der Methode, in der sie definiert ist. D.h., die lokale Klasse benotigt eine

132 Informatik B • SS 02

private Kopie aller lokalen Variablen, die sie verwendet (automatisch vom Compilererzeugt). Einzige Moglichkeit, Konsistenz zu garantieren (lokale Variablen und derenKopie bleiben identisch): final .

• Erweiterung der Java-Syntax: final -Modifikator darf nicht nur fur lokale Variablen,sondern auch fur Parameter von Methoden und Exception Parameter imcatch -Statement angegeben werden.

• Wie Member-Klassen haben lokale Klassen Zugriff auf die Instanz der umschliessendenKlasse, falls sie nicht in einer Klassenmethode vereinbart werden (qualifiziertes thisum auf Komponenten der umschliessenden Klasse zuzugreifen).

10.3.4 Geltungsbereich Lokaler Klassen

class A { protected char a = ’a’; }class B { protected char b = ’b’; }

public class C extends A {private char c = ’c’; // visible to local classpublic static char d = ’d’;public void createLocalObject(final char e) {

final char f = ’f’;int i = 0; // not final, not usable by local classclass Local extends B {

char g = ’g’;public void printVars(){// All of these fields and variable are accessibleSystem.out.println(g); // this.g, field of LocalSystem.out.println(f); // final local variableSystem.out.println(e); // final local parameterSystem.out.println(d); // C.this.d, field of containing classSystem.out.println(c); // C.this.cSystem.out.println(b); // inherited by LocalSystem.out.println(a); // inherited by containing class}

}Local l = new Local(); // Create instance of Locall.printVars(); // call its method

}}

public class Weird {// A static member interface used belowpublic static interface IntHolder { public int getValue(); }

public static void main(String[] args) {IntHolder[] holders = new IntHolder[10]; // An array to hold 10 objsfor (int i = 0; i < 10; i++) { // Loop to fill array

final int fi = i; // final local var, a new one for each iteration

Informatik B • SS 02 133

class MyIntHolder implements IntHolder { // local classpublic int getValue() { return fi; }

}holders[i] = new MyIntHolder(); // Instantiate local class

}

// The local class is now out of scope, so we can’t use its name.// But we’ve got 10 valid instances of that class in our array.// The local variable fi is not in our scope here, but each of the// 10 objects still has access to its local copy for use in// the getValue() method.// So call getValue() for each object and print it out.// This prints the digits 0 to 9.for(int i = 0; i < 10; i++) System.out.println(holders[i].getValue());}

}

10.4 Anonyme Klassen

• Namenlose lokale Klassen

• Kombination der Syntax von Klassen-Definition und Objekt-Erzeugung

• wie lokale Klassen innerhalb eines Ausdrucks definiert.

10.4.1 Beispiel: ‘Enumerator’ als anonyme Klasse

public java.util.Enumeration enumerate() {// The anonymous class is defined as part of the// return statementreturn new java.util.Enumeration() {

protected int current = 0;

public boolean hasMoreElements() {return current < numOfEls;

}

public Object nextElement() {if (! hasMoreElements())

throw new java.util.NoSuchElementException();return list[current++];

}}; // semicolon required to finish return statement

}

10.4.2 Eigenschaften von Anonymen Klassen

• Lokale Klasse ohne Namen.

• Definition und Instantiierung in einem einzigen Ausdruck (new Operator).

134 Informatik B • SS 02

• Zwei Formen:new <class-name > ( [ <argument-list > ] ) { <class-body > }

Konstruktoraufruf der Oberklasse (evtl. auch Default-Konstruktor), Erzeugung einesObjekts der anonymen Unterklasse.new <interface-name > ( ) { <class-body > }

Default-Konstruktoraufruf fur ein Interface, Erzeugung einer anonymen Unterklasse vonObject , die das Interface implementiert.

• Lokale Klasse ist Anweisung in einem Block, anonyme Klasse Ausdruck als Teil einesgrosseren Ausdrucks (z.B. Methodenaufruf).

• Verwendung: lokale Klasse, die nur einmal benutzt wird. (Definition und Nutzung genaudort, wo verwendet; weniger “clutter” im Code)

• Typische Anwendung: Implementation von Adapter-Klassen.Definition von Code, der von anderen Objekten aufgerufen wird.

• Beschrankungen wie fur lokale Klassen: keine statischen Komponenten, ausserstatic final Konstanten; nicht als public, private, protected, staticdeklarierbar.

• Da namenlos: keine Konstruktor-Definition moglich. Erbt – ausnahmsweise – dieKonstruktoren der Oberklasse. Im Fall eines Interfaces wird ein Default-Konstruktoreingefugt.

• Wenn eigener/anderer Konstruktor notwendig, als lokale Klasse definieren.

• Alternative: Instanz-Initialisierer (Initialisierungsblocke fur Instanzen wurden genau furanonyme Klassen eingefuhrt), Initialisierungsblock wird in die geerbtenKonstruktoren/den Default-Konstruktor eingefugt.

10.4.3 Implementation von Lokalen und Anonymen Klassen

• Zusatzlich zu den Zugriffsrechten von Member-Klassen, Zugriff auf final deklariertelokale Variablen im Geltungsbereich des Blocks, in dem sie definiert sind.

• Compiler gibt der inneren Klasse private Instanzfelder, um Kopien der lokalenVariablen zu halten.

• Compiler fugt versteckte Parameter fur jeden Konstruktor einer lokalen Klasse ein, umdiese private Felder zu initalisieren.

• Lokale Klasse hat nicht wirklich Zugriff auf die lokalen Variablen, sondern auf eineprivate Kopie dieser Variablen. final garantiert Konsistenz!

• “Hoch”-Compilation von anonymen Klassen: Vergabe von Nummern, z.B.MyListAC$1.class .

10.4.4 Adapter-Klassen als Anonyme Klassen

File f = new File("/src"); // The directory to list

// Now call the list() method with a single FilenameFilter argument// Define and instantiate an anonymous implementation of FilenameFilter// as part of the method invocation expression.

Informatik B • SS 02 135

String[] filelist = f.list(new FilenameFilter() {public boolean accept(File f, String s) {return s.endsWith(".java"); }

}); // Don’t forget the parenthesis and semicolon that end the method call!

• Methode list() aus java.io.File hat als Argument ein Objekt vom Typ desInterfaces FilenameFilter , das die Dateinamen des zu listenden Verzeichnissesfiltert.

• Anonyme Klasse implementiert Interface FilenameFilter aus java.io : Adaptationder accept() -Methode an konkrete Anforderung!.

• Kein extends oder implements kann fur anonyme Klassen spezifiziert werden!

• siehe Abschnitt “Adapter-Patterns”

10.4.5 Anwendung und Konventionen

Anonyme Klasse statt lokaler Klasse, wenn

• Klasse kleinen Korper hat

• nur eine Instanz der Klasse benotigt wird

• die Klasse direkt nach ihrer Definition benutzt wird

• Name fur die Klasse Code nicht leichter verstandlich macht.

Layout-Empfehlungen von Sun:

• Offnende geschweifte Klammer in selber Zeile wie new, und new in selber Zeile wie derAusdruck, zu dem die anonyme Klasse gehort.

• Einrucken des Korpers relativ zu der Zeile mit new.

• Schliessende geschweifte Klammer in selber Zeile wie Ende des umschliessendenAusdrucks. (z.B. Semikolon als Abschluss einer return -Anweisung)

10.5 Zusammenfassung

• Bisher: “top-level” Klassen (direkte Mitglieder eines Pakets).Seit Java 1.1: Innere Klassen: definiert innerhalb einer anderen Klasse (Komponenteeiner Klasse, ahnlich Felder und Methoden)

• Vier Arten von inneren Klassen:

– Static Member Classes (Nested Top-Level Classes):“class class” (vgl. Klassen-Feld, Klassen-Methode)Verhalt sich ahnlich wie top-level Klasse, hat Zugriff auf die statischenKomponenten der umschliessenden Klasse.Interfaces durfen nur als static member classes, nicht als non-static definiertwerden.

– Member Classes (“echte” innere Klasse):Analog zu Instanz-Feldern und Methoden, Zugriff auf alle Felder derumschliessenden Klasse.Spezielle Syntax zum Zugriff auf “umschliessende Instanz”.

136 Informatik B • SS 02

– Local Classes:definiert innerhalb eines Blocks von Java-Code (innerhalb einer Methode), ahnlichzu lokalen Variablen.Sichtbarkeit: nur innerhalb des Blocks. Zugriffsrechte wie Member-Klassen,zusatzlich Zugriff auf alle final lokalen Parameter und Variablen, die im Blocksichtbar sind.

– Anonymous Classes:Namenlose lokale Klasse; Kombination der Syntax von Klassen-Definition undObjekt-Instantiierung; definiert innerhalb eines Ausdrucks.

10.6 Beispiel-Code ‘Enumeration’

// A class that implements a stack as a linked listpublic class LinkedStack {

// This static member interface defines how objects are linkedpublic static interface Linkable {

public Linkable getNext();public void setNext(Linkable node);

}// The head of the list is a Linkable ObjectLinkable head;

// Methodspublic void push(Linkable node){

node.setNext(head);head = node;

}public Object pop(){

if (head != null){ Linkable oldtop = head;

head = head.getNext();return oldtop;

}else return "error";

}}

// This method returns an Enumeration object for this LinkedStackpublic java.util.Enumeration enumerate() { return new Enumerator(); }

// short for this.new Enumerator();

// Here is the implementation of the Enumeration interface// defined as a member class

// alternative realization as local class or anonymous class// see Java in a Nutshell

protected class Enumerator implements java.util.Enumeration {Linkable current;

Informatik B • SS 02 137

// The constructor uses the private head field of the containing classpublic Enumerator() { current = head; }

// explicit: this.current = LinkedStack.this.head;public boolean hasMoreElements() {return (current != null); }public Object nextElement() {

if (current == null) throw new java.util.NoSuchElementException();Object value = current;current = current.getNext();return value;

}}

}

// This class implements the static member interfaceclass LinkableInteger implements LinkedStack.Linkable {

// Here’s the node’s data and constructorint i;public LinkableInteger(int i) { this.i = i; }

// Here are the data and methods required to implement the interfaceLinkedStack.Linkable next;public LinkedStack.Linkable getNext() { return next; }public void setNext(LinkedStack.Linkable node) { next = node; }

}

public class IntStack {

public static void main (String[] args) {LinkedStack intstack = new LinkedStack();LinkableInteger li = new LinkableInteger(1);System.out.println("Push! New Integer-Element: " + li.i);intstack.push(li);System.out.println ("Top of Stack is " +

((LinkableInteger)(intstack.head)).i);LinkableInteger li2 = new LinkableInteger(2);System.out.println("Push! New Integer-Element: " + li2.i);intstack.push(li2);System.out.println ("Top of Stack is " +

((LinkableInteger)(intstack.head)).i);intstack.pop();System.out.println("pop!");System.out.println ("Top of Stack is " +

((LinkableInteger)(intstack.head)).i);

intstack.push(li2);

// Enumeratorjava.util.Enumeration intstackenum = intstack.enumerate();

138 Informatik B • SS 02

while (intstackenum.hasMoreElements()){System.out.println(

((LinkableInteger)(intstackenum.nextElement())).i);}}

}

10.7 Adapter-Patterns und Java Adapter-Klassen

• Adapter: Konvertierung eines API einer Klasse in das API einer anderen.

• Anwendung: Zusammenarbeit unverbundener Klassen in einem Programm.

• Konzept: Schreibe Klasse mit dem gewunschten Interface und lasse diese Klasse mitder Klasse kommunizieren, die ein anderes Interface hat.

• Zwei Moglichkeiten zur Realisierung:

– Klassen-Adapter: Ableitung einer neuen Klasse von der nicht-angepassten Klasseund Hinzufugen von Methoden so, dass die neue Klasse dem gewunschtenInterface genugt.

class A {// a class which "nearly" meets specification B

}

interface B {// ...

}

class AdA extends A implements B {// implement methods of B using A

}

– Objekt-Adapter: Einbetten eines Objekts der ursprunglichen Klasse in die neueKlasse und Definition von Methoden, um Aufrufe in der neuen Klasseentsprechend zu ubersetzen.

class AdA implements B {A a;// ...

}

• siehe Cooper, Java Design Patterns, Kap. 9.

• In Java wird der Begriff “Adapter” fur Klassen im GUI-Bereich verwendet.

• Hier sind Adapter-Klassen Klassen, die nur Methoden mit leerem Korper zur Verfugungstellen.

• Anwendung: Erzeugung eines entsprechenden Objekts und Uberschreiben derbenotigten Methoden.

Beispiel: ‘WindowAdapter’

Informatik B • SS 02 139

// illustrates using the WindowAdapter class// make an extended window adapter.// This class closes the frame// when the closing event is receivedclass MyWindowAdapter extends WindowAdapter {

public void windowClosing(WindowEvent e) {System.exit(0);

} }

public class Closer {public Closer() {

MyWindowAdapter win = new MyWindowAdapter();Frame f = new Frame();f.addWindowListener(win);f.setSize(new Dimension(100,100));f.setVisible(true);

}public static void main(String[] args) {

new Closer();}

}

Kompaktere Realisierung mit anonymer Klasse:

// create window listener for window closeaddWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e)

{System.exit(0);}});

10.8 Innere Klassen und Lexical Closures

• Lexical Closure: Funktion, die ihren Kontext erinnert und freie Variablen daruber bindet.Konzept aus der funktionalen Programmierung. Siehe, z.B. Steele, Common Lisp, Kap.7.1.

• Brent W. Benson (1999), Java Reflections: Inner Classes – Closures for the masses,ACM SIG-Plan Notices, 34(2), 32-35.

[1]> (defun adder (n) (function (lambda (m) (+ m n))))ADDER[2]> (setq add3 (adder 3))#<CLOSURE :LAMBDA (M) (+ M N)>[3]> (funcall add3 4)7

• Fur die innere, namenlose Funktion (lambda-Ausdruck) ist n eine freie Variable

• Ergebnis von (adder 3) ist eine Funktion , die die Zahl 3 zu ihrem Argument (m)addiert.

140 Informatik B • SS 02

10.8.1 Code as Data

• Behandlung von Code als Daten ist machtige Eigenschaft einer Programmiersprache.

• Common Lisp, Scheme, C: Funktionen als “First Class”-Objects, die in Variablengespeichert, manipuliert, und auf Daten angewendet werden konnen.In Java: Objekte als “First Class” Objects (Funktionen/Methoden sind untergeordnet).

• Fahigkeit, dass ein Stuck Code den Kontext erinnert, in dem es erzeugt wurde (Closure).

10.8.2 Adder-Beispiel

interface Adder{int add(int m);

}

public Adder makeAdder(final int n) {return new Adder() {

public int add (int m) {return m + n;}};

}

• In makeAdder wird das Adder -Interface fur eine spezielle Anforderung adaptiert!

• Die anonyme innere Klasse realisiert das Konzept der lexical closure.

Informatik B • SS 02 141

11 Abstrakte Datentypen und Collections

11.1 Abstrakte Datentypen

11.1.1 Grundlagen

• Abstrakter Datentyp (ADT): Sammlung von Objekten eines Typs, die in einer festenStruktur organisiert sind. Konstruktoren reprasentieren die Struktur des ADT (kleinstesElement und Aufbau einer Struktur durch Einfugen), empty-Test, Selektoren, weitereOperatoren. Alle Operatoren werden abstrakt definiert. Ihre Funktionalitat wird uberAxiome beschrieben.

• Beispiele: Liste, Stack, Menge, Bag, Binarbaum.

• ADT sind abstrakt, weil nur die Struktur, nicht aber die konkrete Realisierung festgelegtwird. Die Realisierung (Implementation) bedingt die Performanz: Speicheraufwand undAufwand fur Suchen, Einfugen, Loschen von Objekten.

• Abstrakte Datentypen und konkrete Implementationen in Java: Collections(java.util ).

• Funktionalitat in Java: Interface ↪→ Signatur der Operationen. Axiome alsnaturlichsprachiger Kommentar. Realisierung: Implementation des Interface.

11.1.2 Funktionalitaten von Collections

• In den folgenden Abschnitten: Beispielhafte Implementation von Collections. Ziel:Vertiefung der bisher vermittelten Konzepte der objekt-orientieren Programmierung mitJava an einem etwas komplexeren Beispiel (von A.T. Scheiner, Skript zurJava-Vorlesung)

• Wir betrachten einen ADT als Sammlung (Collection) von Objekten.

• Funktionalitaten: Einfugen (add() ), Loschen (sub() ), Finden (find() ) von Objekten,Anzahl von Objekten (count() ).

• Weitere Funktionalitaten: Aufzahlen (Enumeration), ...

• Charakterisierung der Basis-Funktionalitaten:

– Man kann nur Objekte mit find() entdecken, die irgendwann vorher mit add()eingefugt wurden.

– Man kann nur ein Objekt mir sub() loschen, das irgendwann vorher mit add()eingefugt wurde.

– count() wird von add() und sub() beeinflusst.

• Charakterisierung der abstrakten Struktur von Objekten:

– Kann das gleiche Objekt mehr als einmal hinzugefugt werden?nein ↪→ Set, ja ↪→ Bag

– Sind die Objekte geordnet?nein ↪→ Set, ja ↪→ List

– Kann nur von einer Seite hinzugefugt und geloscht werden?nein ↪→ Liste, ja ↪→ Queue oder Stack

142 Informatik B • SS 02

– Sind die Objekte uber einen Index zugreifbar?nein ↪→ Set oder List, ja ↪→ Array

• Weitere Aspekte:

– Definition von Gleichheit: Identitat oder Aquivalenz

– Status von null : als Objekt (das eingefugt, geloscht, gefunden werden kann) odernicht.

11.2 Implementation von Collections

• Im Prinzip kann die Funktionalitat eines Arrays uber eine Listen-Implementationrealisiert werden. Dies ist aber wohl der Performanz nicht zutraglich.

• Frage der Implementation: welche Funktionalitaten werden wie am bestenrealisiert?

• Im Folgenden: Set und Bag als Array, als doppelt verkettete Liste, alsBinarbaum.

// adt/MyCollection.java // A.T. Schreinerpackage adt;/** adt: rudimentary collection; an implementation<ul>

<li>may use equality or identity<li>may or may not accept null<li>may return original objects or objects from the container<li>may throw RuntimeException for unsuitable objects, overflow, etc.</ul>

*/public interface MyCollection {

/** insert an object into the collection.*/

Object add (Object x);/** locate an object in the collection.

*/Object find (Object x);/** remove an object from the collection.

*/Object sub (Object x);/** @return number of distinct objects in the collection;

zero, if the collection is empty.*/

int count ();}

Informatik B • SS 02 143

adt adt.array

MyCollection Bag Set EquivalenceSet<<interface>>>

MyCollection

add(x: Object): Object

find(x: Object): Objectsub(x: Object): Objectcount(): Integer

Abbildung 42: Struktur vonadt.array

11.3 Implementation mit Array

11.3.1 MyCollection/Array

Grundlegende Funktionalitat:Array fester Lange, erlaubt ‘null’ als Objekt, vergleicht auf Identitat, tragt gleiche Wertemehrfach ein, loscht immer nur ein Objekt.

// adt/array/MyCollection.java // A.T. Schreinerpackage adt.array;/** fixed size, array based container with multiple insertion.

*/public class MyCollection implements adt.MyCollection {

protected Object[] element; protected int count;/** define capacity of the collection.

@throws RuntimeException if capacity < 0.*/

public MyCollection (int capacity) {element = new Object[capacity];

}/** default capacity 128; permit package to use newInstance().

*/public MyCollection () { this(128); }/** insert an object into the collection, do not check if already present.

@param x object to be added, may be null.@return x.@throws ArrayIndexOutOfBoundsException for overflow.

*/public Object add (Object x) {

element[count] = x; ++ count; return x;}/** locate an object in the collection.

@param x object to be found.@return object from collection, as determined by locate().

144 Informatik B • SS 02

@throws ArrayIndexOutOfBoundsException if x cannot be found.*/

public Object find (Object x) {return element[locate(x)];

}/** remove an object from the collection.

@param x object to be removed.@return object from collection, as determined by locate().@throws ArrayIndexOutOfBoundsException if x cannot be found.

*/public Object sub (Object x) {

int n = locate(x); x = element[n];if (count > n+1) System.arraycopy(element, n+1, element, n, count-(n+1));-- count;return x;

}/** @return number of distinct objects in the collection;

zero, if the collection is empty.*/

public int count () { return count; }/** locate an object in the collection.

@param x object to be found.@return (last) position if present, based on identity.@throws ArrayIndexOutOfBoundsException if x cannot be found.

*/protected int locate (Object x) throws ArrayIndexOutOfBoundsException {

int n = count;while (element[--n] != x)

;return n;

}/** permit symbolic dump.

*/public String toString () {

StringBuffer buf = new StringBuffer(super.toString());buf.append(" count ").append(count);for (int n = 0; n < count; ++ n)

buf.append(’\n’).append(element[n]);return buf.toString();

}/** test: . display, -word remove, else add.

*/public static void main (String[] args) {

if (args != null) new MyCollection().test(args);}protected void test (String[] args) {

for (int a = 0; a < args.length; ++ a)try {

Informatik B • SS 02 145

if (args[a].equals(".")) System.out.println(this);else if (args[a].equals("null")) add(null);else if (!args[a].startsWith("-")) add(args[a]);else if (args[a].equals("-null")) sub(null);else sub(args[a].substring(1));

} catch (RuntimeException e) { System.err.println(e); }}

}

11.3.2 Erlauterungen zu ‘MyCollection’

• Lange des Arrays kann uber Konstruktor gesetzt werden.

• Beim Loschen eines Elements, das nicht an der letzten Indexposition (count )steht, muss der Sub-Array rechts von diesem Index um eins nach linksverschoben werden. Dies wird durch die Methode System.arraycopy()realisiert.

• sub() und find() mussen ein Objekt lokalisieren. Die Methode locate() istbisher so realisiert, dass Gleichheit Identitat meint (==). Alternativ: equals()(ist z.B. fur String-Objekte definiert).

• locate() ist protected deklariert: verstecktes Implementationsdetail.

• Wenn null als Objekt wie andere Werte eingefugt werden kann, mussenerfolglose Versuche, ein Objekt zu lokalisieren (in sub() , find() ) alsException behandelt werden. ArrayIndexOutOfBoundsException ist vonRuntimeException abgeleitet und muss deshalb nicht im Kopf der Methodeangegeben werden. Durch die Deklaration wird explizit darauf hingewiesen,dass diese Exception auftritt, wenn Objekt x nicht gefunden wird. (Hier wird dieArrayIndexOutOfBoundsException etwas “missbraucht”. Besser konnteeine NoSuchElementException() verwendet werden.)

• Um die Collection zu testen, konnen wir den Inhalt des Arrays mit toString()sichtbar machen. Die Oberklasse von MyContainer ist Object und furObject existiert eine Methode toString() , die wir benutzen konnen. Diereturn -Anweisung am Ende von toString() liefert den Inhalt desStringBuffers als String zuruck. (System.out.println() arbeitet auf mittoString() umgewandelten Objekten.)

• Die Methode test() reagiert auf folgende Kommandozeilen-Argumente: .zeigt Inhalt des Arrays an; -wort loscht, sonst wird hinzugefugt.

• null wird als Null-Referenz und nicht als Wort "null" aufgefasst.

11.3.3 Test-Protokoll fur ‘MyCollection’

$ javac -classpath ../.. MyCollection.java$ java -classpath ../.. adt.array.MyCollection null ’ ’ axel null . -null -axel .

146 Informatik B • SS 02

adt.array.MyCollection@65f57 count 4null

axelnulljava.lang.ArrayIndexOutOfBoundsException: -1adt.array.MyCollection@65f57 count 3null

axel

11.3.4 Bag/Array

Funktionalitat:Array fester Lange, der bei Bedarf verlangert (aber nie verkurzt) wird ; erlaubt ‘null’ alsObjekt, vergleicht auf Identitat, tragt gleiche Werte mehrfach ein, loscht immer nur einObjekt.↪→ Unterklasse von adt.array.MyCollection , Uberschreiben von add() : Bei Be-darf, Umkopieren des Arrays in einen Array mit mehr Indexplatzen.

// adt/array/Bag.java // A.T.Schreinerpackage adt.array;/** array based collection with multiple insertion.

*/public class Bag extends MyCollection {

/** define initial capacity of the collection.@throws RuntimeException if capacity < 0.

*/public Bag (int capacity) { super(capacity); }/** default initial capacity determined by superclass.

*/public Bag () { }/** insert an object into the collection, do not check if already present;

dynamically extend element array by 1k.@param x object to be added, may be null.@return x.

*/public Object add (Object x) {

try {return super.add(x);

} catch (ArrayIndexOutOfBoundsException e) {Object[] ne = new Object[element.length + 1024];System.arraycopy(element, 0, ne, 0, element.length);element = ne;return super.add(x);

} } }

Informatik B • SS 02 147

11.3.5 Erlauterungen zu ‘Bag’

• Als Unterklasse hat Bag (mindestens) die gleichen Klassen- undInstanzvariablen wie seine Oberklasse MyCollection .

• Die Methoden der Oberklasse konnen problemlos auf die Objekte derUnterklasse angewendet werde. Die Unterklasse erbt (die fur sie sichtbaren)Methoden der Oberklasse.

• Man kann aber Methoden uberschreiben (auch mit schwacherenSichtbarkeitsrestriktionen versehen). Uber super. <methodenname> hat manin den Methoden immer noch Zugriff auf die Methoden der Oberklasse.

• In add() uberlasst man das Einfugen selbst der Methode der Oberklasse undstellt nur bei Bedarf einen langeren Array zur Verfugung.

• Weil Konstruktoren nicht vererbt werden, mussen auch fur die UnterklasseKonstruktoren definiert werden.

• Konstruktoren sind verkettet und werden von “oben” (Object ) bis zurendgultigen Klasse hin ausgefuhrt.

• Als allererste Anweisung in einem Konstruktor muss entweder ein anderereigener Konstruktor (this() ) oder ein Oberklassen-Konstruktor (super() )aufgerufen werden. Ansonsten erfolgt implizit der Aufruf eines parameterlosenKonstruktors der Oberklasse, der existieren muss.

• Wird kein expliziter Konstruktor definiert, so wird automatisch einparameterloser Konstruktor generiert.

• Im leeren Konstruktor Bag() wird automatisch der Aufruf desOberklassenkonstruktors eingefugt.

11.3.6 Set/Array

Funktionalitat:Array fester Lange, der bei Bedarf verlangert (aber nie verkurzt) wird; erlaubt ‘null’ alsObjekt, vergleicht auf Identitat, tr agt gleiche Werte nur einmal ein, loscht immer nur einObjekt.↪→ Unterklasse zu adt.array.Bag , Uberschreiben von add() : Ist ein identischesObjekt schon im Array, so wird es nicht noch einmal eingefugt.

// adt/array/Set.java // A.T. Schreinerpackage adt.array;/** array based collection with unique identity insertion.

*/public class Set extends Bag {

/** define initial capacity of the collection.@throws RuntimeException if capacity < 0.

*/public Set (int capacity) { super(capacity); }

148 Informatik B • SS 02

/** default initial capacity determined by superclass.*/

public Set () { }/** insert an object into the collection, unless present.

@param x object to be added, may be null.@return object from collection.@throws RuntimeException for overflow.

*/public Object add (Object x) {

try {return super.find(x); // avoid inadvertent override

} catch (ArrayIndexOutOfBoundsException e) { }return super.add(x);

}/** test: . display, -word remove, else add.

*/public static void main (String[] args) {

if (args != null) new Set().test(args);}

}

11.3.7 Erlauterungen zu Set

• Es genugt, add() noch einmal zu uberschreiben.

• Es wird find() in add() verwendet:Vorsicht! Wenn in einer weiteren Unterklasse find() ersetzt wurde, so konntedie Funktionsweise von add() verandert werden. Denn jede Methode wird inder Klasse ihres Empfangers (‘Receiver’) gesucht, unabhangig davon, von woaus ihr Aufruf erfolgt.Mit super. startet die Suche in der Oberklasse der Klasse, in der der Aufruf mitsuper. steht. Dadurch kann add() nicht mehr durch ein Ersetzen von findbeeinflusst werden!

• Eine Funktion wird unmittelbar nach Ausfuhrung einer return Anweisungverlassen. Wird also ein Objekt im Array gefunden, so wird das Resultat vonsuper.find(x) zuruckgeliefert. Wird das Objekt nicht gefunden, so liefertfind() wegen der Benutzung von locate() eineArrayIndexOutOfBoundsException und als Ruckgabe erfolgtsuper.add(x) (das Objekt wird also eingefugt).

• Achtung: Der Java-Compiler verlangt, dass garantiert eine Return-Anweisungerreicht wird. Wurden wir return super.add(x) in den catch Blockschreiben, konnte der Compiler nicht feststellen, dass eine der beidenreturn-Anweisungen auf jeden Fall ausgefuhrt wird, und wurde mit einerFehlermeldung reagieren. Man kann sich in solchen Fallen mit derProgrammzeilereturn null; // never reached

Informatik B • SS 02 149

behelfen.

11.3.8 Test-Protokoll fur ‘Set’

$ javac -classpath ../.. Set.java$ java -classpath ../.. adt.array.Set axel null ’ ’ null . -null -axel .

adt.array.Set@65f55 count 3axelnull

java.lang.ArrayIndexOutOfBoundsException: -1adt.array.Set@65f55 count 2axel

11.3.9 EquivalenceSet/Array

Funktionalitat:Array fester Lange, der bei Bedarf verlangert (aber nie verkurzt) wird; erlaubt ‘null’ alsObjekt, vergleicht auf Aquivalenz, tragt gleiche Werte nur einmal ein, loscht immer nurein Objekt.

↪→ Unterklasse von adt.array.Set , Uberschreiben von locate() : Objektver-gleich mit equals() .

// adt/array/EquivalenceSet.java // A.T. Schreinerpackage adt.array;/** array based collection with unique insertion based on equals().

*/public class EquivalenceSet extends Set {

/** define initial capacity of the collection.@throws RuntimeException if capacity < 0.

*/public EquivalenceSet (int capacity) { super(capacity); }/** default initial capacity determined by superclass.

*/public EquivalenceSet () { }/** locate an object in the collection.

@param x object to be found, may be null.@return (last) position if present, based on equals().@throws ArrayIndexOutOfBoundsException if x cannot be found.

*/protected int locate (Object x) throws ArrayIndexOutOfBoundsException {

int n = count;while (!equals(x, element[--n])) ;return n;

}

150 Informatik B • SS 02

/** @returns x.equals(y), avoids NullPointerException.*/

public static boolean equals (Object x, Object y) {return x == null ? y == null : x.equals(y);

}/** test: . display, -word remove, else add.

*/public static void main (String[] args) {

if (args != null) new EquivalenceSet().test(args);}

}

11.3.10 Erlauterungen zu ‘EquivalenceSet’

• Alle Klassen erben von Object . In Object ist eine Methode equals()definiert, deren Empfanger sich selbst mit einem Argument vergleicht. DieMethode ist dort fur Identitat implementiert.

• Neue Klassen konnen die Methode uberschreiben. In java.lang.String wirdtrue zuruckgeliefert, wenn zwei String -Objekte aus denselbenCharacter-Folgen bestehen. Die Methode ist symmetrisch, wennn x und yStrings sind: x.equals(y) == y.equals(x) .

• In EquivalenceSet werden zwei equals() -Methoden benutzt, die sich durchihre Signatur unterscheiden:Die Methode equals() mit zwei Argumenten benotigt keinen Empfanger, istalso eine Klassenmethode (static ).Die fur Object definierte und von String uberschriebene Methode mit einemArgument benotigt einen von null verschiedenen Empfanger.

• return -Statement in equals() : Wenn x null ist, dann liefere true , wenn yebenfalls null ist, sonst rufe x.equals(y) auf. Falls x und y String sindwirdauf Aquivalenz verglichen.

• Bisher wurde Duplizierung von Code sorgfaltig vermieden. Alle Vergleiche sindin locate() gekapselt (sogar, als add() uberschrieben wurde). D.h., es istausreichend, locate() in einer Unterklasse zu uberschreiben, wobei null alsSpezialfall behandelt wird.

11.3.11 Test-Protokoll fur ‘EquivalenceSet’

• Set und EquivalenceSet fugen nur Objekte ein, die nicht bereits im Arrayvorhanden sind. Set arbeitet mit Identitat, EquivalenceSet arbeitet mitequals() .

$ java adt.array.Set null ’ ’ axel null . -null -axel .adt.array.Set@65f55 count 3null

Informatik B • SS 02 151

axeljava.lang.ArrayIndexOutofBoundsException: -1adt.array.Set@65f55 count 2

axel$ java adt.array.EquivalenceSet null ’ ’ axel null . -null -axel .adt.array.EquivalenceSet@65f54 count 3null

axeladt.array.EquivalenceSet@65f54 count 1

11.4 Implementation mit Offener Hash-Tabelle

11.4.1 Array versus Hash-Tabelle

• Lineare Suche im Array wird um so teurer, je langer der Array ist (Zahl derObjekte).

• Offene Hash-Tabelle: Feste Lange, Eintrag uber Hash-Code.Kollisionsauflosung: jeder Indexplatz enthalt eine Collection (ublicherweiseListe).

• Hash-Code muss moglichst eindeutigen Wert liefern. hashCode() berechnet(moglichst) eindeutigen int -Wert fur Empfanger-Objekt. Wenn equals()true liefert, muss hashCode() denselben Wert fur beide Objekte (Empfangerund Argument von equals() ) liefern.↪→Wenn equals() uberschrieben wird, muss man daran denken, auchhashCode() zu uberschreiben!

• “Gute” Hash-Funktion streut gleichmassig (keine Clusterbildung!).

• Ublich: Key/Data-Paare, Hash-Code wird uber Key berechnet.Im Folgenden: nur Daten, Key wird uber Daten direkt berechnet.

11.4.2 MyCollection/Hash

Grundlegende Funktionalitat:Offene Hash-Tabelle fur Daten als Array (bucket), bei dem jeder Indexplatz auf ei-ne Collection verweist. In welcher Collection ein Datum abgelegt wird, wird uberhashCode() ermittelt. Die Collections konnen verschieden realisiert werden, z.B. alsArray oder als Liste.

// adt/hash/MyCollection.java // A.T. Schreinerpackage adt.hash;/** base class for open hash based collections.

*/

152 Informatik B • SS 02

Hash−Tabelle Daten

Abbildung 43: Offene Hash-Tabelle

adt

Bag<<interface>>>

MyCollection

add(x: Object): Object

find(x: Object): Objectsub(x: Object): Objectcount(): Integer

adt.hash

MyCollection

Set

Abbildung 44: Struktur vonadt.hash

Informatik B • SS 02 153

public abstract class MyCollection implements adt.MyCollection {protected final adt.MyCollection[] bucket;/** define bucket table.

@throws RuntimeException if capacity < 0.*/

public MyCollection (int capacity) { bucket = new adt.MyCollection[capacity]; }/** default bucket capacity is 16.

Should use this(16), but JDK 1.1.6 complains about final.*/

public MyCollection () { bucket = new adt.MyCollection[16]; }/** insert an object into the collection.

*/public Object add (Object x) { return bucket(x, true).add(x); }/** locate an object in the collection.

@throws RuntimeException if not found.*/

public Object find (Object x) { return bucket(x, false).find(x); }/** remove an object from the collection.

@throws RuntimeException if not found.*/

public Object sub (Object x) { return bucket(x, false).sub(x); }/** @return number of distinct objects in the collection;

zero, if the collection is empty.*/

public int count () {int result = 0;for (int n = 0; n < bucket.length; ++ n)

if (bucket[n] != null) result += bucket[n].count();return result;

}

/** access function for bucket[].@param x object to hash, may be null.@param create true to create a missing bucket.@return bucket collection or null if create is false.

*/protected adt.MyCollection bucket (Object x, boolean create) {

int n = x == null ? 0 : Math.abs(x.hashCode() % bucket.length);if (create && bucket[n] == null) bucket[n] = newBucket();return bucket[n];

}/** factory method for bucket collections, decides class chracteristics.

*/protected abstract adt.MyCollection newBucket ();/** permit symbolic dump.

*/public String toString() {

154 Informatik B • SS 02

StringBuffer buf = new StringBuffer(super.toString());buf.append(" count ").append(count());for (int n = 0; n < bucket.length; ++ n)

buf.append(’\n’).append(bucket[n]);return buf.toString();

}}

}

11.4.3 Erlauterungen zu ‘MyCollection’

• Anders als ublich bei Hash-Tabellen, werden nicht Key/Data Assoziationen,sondern nur Daten eingetragen (vgl. HashSet in java.util.Collections ).

• adt.hash.MyCollection benutzt einen Array fester Lange mitadt.MyCollection -Objekten als Elemente (bucket ).

• Alle Nachrichten an ein MyCollection -Objekt werden an die entsprechendevon hashCode() ausgewahlte Collection weitergeleitet. (Methode bucket() )

• Alle Operationen (add() , sub() , find() ) werden uber eine Methodebucket() realisiert, die das entsprechende Element erzeugt oder findet.Zugriffsmethode (Access-Method) fur Array bucket[] .↪→ Elemente konnen “spat” erzeugt werden, Zugriffskontrolle, ...

• Konkrete Auswahl eines Collection-Elements und damit das Verhalten vonMyCollection wird uber newBucket() realisiert:abstrakte Methode ↪→ abstrakte Klasse,newBucket() regelt Erzeugung von Objekten und wird in Unterklassen durchkonkrete Methoden uberschrieben: Factory-Pattern!

• Weil Array-Indizes positiv sein mussen, wird Math.abs() verwendet.

• Fur null kann man keine Methode, also auch nicht hashCode() aufrufen.

11.4.4 Bag/Hash

Funktionalitat:Array fester Lange, der bei Bedarf verlangert (aber nie verkurzt) wird; erlaubt ‘null’ alsObjekt, vergleicht auf Identitat, tragt gleiche Werte mehrmals einmal ein, loscht immernur ein Objekt.↪→ newBucket() liefert ein adt.array.Bag Objekt

// adt/hash/Bag.java // A.T. Schreinerpackage adt.hash;/** open hash based container with multiple insertion.

*/public class Bag extends MyCollection {

/** define bucket table.@throws RuntimeException if capacity < 0.

Informatik B • SS 02 155

*/public Bag (int capacity) { super(capacity); }/** default initial capacity determined by superclass.

*/public Bag () { }/** factory method for bucket collections, decides class chracteristics.

@return adt.array.Bag.*/

protected adt.MyCollection newBucket () { return new adt.array.Bag(); }}

11.4.5 Set/Hash

Funktionalitat:Array fester Lange, der bei Bedarf verlangert (aber nie verkurzt) wird; erlaubt ‘null’ alsObjekt, vergleicht auf Identitat, tragt gleiche Werte nur einmal ein, loscht immer nur einObjekt.↪→ newBucket() liefert ein adt.list.Set Objekt

// adt/hash/Set.java // A.T. Schreinerpackage adt.hash;/** open hash based collection with unique identity insertion.

*/public class Set extends MyCollection {

/** define bucket table.@throws RuntimeException if capacity < 0.

*/public Set (int capacity) { super(capacity); }/** default initial capacity determined by superclass.

*/public Set () { }/** factory method for bucket collections, decides class chracteristics.

@return adt.list.Set.*/

protected adt.Container newBucket () { return new adt.list.Set(); }}

11.5 ADT-Test

11.5.1 Anforderungen an ‘Test’

• Da adt.array.MyCollection und adt.hash.MyCollection nur Objectals gemeinsame Oberklasse haben, musste die fur array definierte Methodetest() kopiert werden.

• Definition einer allgemeinen Test-Klasse adt/Test.java , mit der beliebigeRealisationen von Bag, Set und EquivalenceSet als array , hash , listoder tree getestet werden konnen!

156 Informatik B • SS 02

• Funktionalitat von adt/Test :. toString() Ausgabe der Collection auf Standard-Output.# count() Anzeige der Anzahl von Objekten in der Collection.- sub() Entferne nachstes Wort.word add() Trage Wort ein.

• Das Wort “null” wird als null -Referenz eingefugt/geloscht.

• Test soll die zu testende Collection als Kommandozeilen-Argument (z.B.adt.hash.Set ) ubergeben bekommen.

• intern() erlaubt, dass Strings mit identischen Zeichenfolgen als ein- unddasselbe Objekt behandelt werden. Mit -i soll dies in Test unterbundenwerden.

$ wc -w Test.java376 Test.java

$ export CLASSPSTH=..$ { cat Test.java; echo ’#’; } | java adt.Test adt.hash.Set179$ { cat Test.java; echo ’#’; } | java adt.Test -i adt.hash.Set376

Das Unix-Commando wc liefert die Anzahl der Worte (durch Leerzeichenseparierte Zeichenfolgen) in einer Datei.

• Die tatsachlichen Kommandos (Einfugen/Loschen von Worten, ...) sollen alsKommandozeilen-Argumente (wie bisher) oder von Standard-Input oder auseiner Datei gelesen werden konnen (abstrakte Methode next() ).

• Zentrale Methode in Test : test()intern ja oder nein; Manipulation einer Collection (Einfugen/Loschen vonWorten).

11.5.2 Test/ADT

// adt/Test.java // A.T. Schreinerpackage adt;import java.io.EOFException;import java.io.IOException;import java.io.InputStreamReader;import java.io.StreamTokenizer;/** test collections using strings with or without intern().

*/public abstract class Test {

/** @return next input word, maybe null.@throws EOFException if no more input.@throws IOException if input error.

*/public abstract String next () throws IOException;

Informatik B • SS 02 157

/** tests collections with words delivered by next() until exception.<dl><dt>.<dd>display collection on stdout<dt>#<dd>display count on stderr<dt>-<dd>remove next word<dt>null<dd>represents <tt>null</tt><dt>word<dd>add word</dl>@param collection to be tested.@param intern if true, intern() is used on each word.@throws EOFException if no more input.@throws IOException if input error.

*/public void test (MyCollection collection, boolean intern) throws IOException {

for (;;) {String s = next();if (s == null) collection.add(null);else {

String i = s.intern();if (i == ".") System.out.println(collection);else if (i == "#") System.err.println(collection.count());else if (i == "-")

try {s = next();if (s == null || s.equals("null")) collection.sub(null);else collection.sub(intern ? s.intern() : s);

} catch (RuntimeException e) {System.out.println("sub "+s+" not found");

}else if (i == "null") collection.add(null);else collection.add(intern ? i : s);

}}

}/** run test(), either on arguments or on words from standard input.

Optional argument <tt>-i</tt> suppresses use of intern().First argument is full class name.

*/public static void main (final String[] args) {

if (args == null) return;

int a = 0;

boolean intern = true;if (a >= args.length) return;if (args[a].equals("-i")) { intern = false; ++ a; }

MyCollection collection;if (a >= args.length) return;

158 Informatik B • SS 02

try {collection = (MyCollection)Class.forName(args[a]).newInstance(); ++ a;

} catch (ClassNotFoundException e) { System.err.println(e); return;} catch (IllegalAccessException e) { System.err.println(e); return;} catch (InstantiationException e) { System.err.println(e); return;}// generate local Test object and run test()try {

Test test;if (a < args.length) {

final int n = a;test = new Test() {

int a = n;public String next () throws IOException {

if (a < args.length) return args[a++];throw new EOFException();

}};

} elsetest = new Test() {

StreamTokenizer st =new StreamTokenizer(new InputStreamReader(System.in));

{ st.resetSyntax();st.wordChars(’\0’, ’˜’); st.whitespaceChars(’\0’, ’ ’);

}public String next () throws IOException {

if (st.nextToken() == st.TT_WORD) return st.sval;throw new EOFException();

}};

test.test(collection, intern);} catch (EOFException e) {} catch (IOException e) { System.err.println(e);}

}}

11.5.3 Erlauterungen zu ‘Test’

• Fur String -Konstanten kann mit intern() erzwungen werden, dassidentische Zeichenketten mit einem Objekt identifiziert werden.

• Es wird generell MyCollection.intern() benutzt, um Eingaben wie “null”oder “#” durch einfache Vergleichsoperationen entdecken zu konnen.

• Durch Verwendung von intern() pruft == auf Aquivalenz!

• Identitatsprufung wie vorher realisiert: durch Schalter -i (boolean intern intest() ).

Informatik B • SS 02 159

• Abstrakte Methode next() kann null liefern, also muss in test() zunachstgepruft werden, ob dies der Fall ist, bevor intern() oder equals()aufgerufen wird.

• In test() wird Wort “null” als null -Referenz behandelt.

• main() pruft zunachst, ob -i als Option fur Test angegeben wurde. Danachwird der Name der Klasse von der Kommandozeile gelesen und einentsprechendes Collection-Objekt erzeugt.

• java.lang.Class ist die Klasse der Klassenbeschreibungen in Java. JedeKlasse hat ein eindeutiges Class -Objekt, das folgendermassen angesprochenwerden kann:

someObject.getClass()SomeClass.classint.classfloat[].class

Die Klassen-Methode forName() erzeugt ein Class -Objekt fur einenvollstandigen Klassennamen wie adt.array.Set , das dann die Klasseadt.array.Set reprasentiert (wenn sie gefunden wird!). newInstance()kann an ein Class -Objekt gesendet werden um ein neues Objekt zu erzeugen(wenn ein paramterloser Konstruktor existiert!).(siehe Kapitel “Reflections”)

• Beim Erzeugen eines Objekts auf diese Art konnen zahlreiche Exceptionsauftreten! Dafur ist Test aber sehr flexibel.

• Es soll moglich sein, dass die tatsachlichen Manipulationen der Collection uberweitere Kommandozeilen-Argumente oder von der Standard-Eingabe (Tastatur)kommen. Entsprechend muss in main() in Abhangigkeit von den weiterenArgumenten auf der Kommandozeile ein Test -Objekt erzeugt werden.

• Dies wird mit zwei anonymen Klassen realisiert.

• System.in liefert Standard-Input als Byte-Folge. Ein InputStreamReadererlaubt, Bytes in Characters umzuwandeln. Ein StreamTokenizer konstruiertWorte aus Zeichen. Hier wurde als Trennung (whitespaceChars ) zwischenWorten (Tokens) Leerzeichen definiert (Initializer-Block, da anonyme Klassekeinen expliziten Konstruktor definieren kann!).

11.6 Implementation mit Liste

11.6.1 Dynamische Datenstrukturen

• Ein Array hat eine fest vorgegebene Lange. Wachst die Anzahl der Elemente,muss der Array evtl. in einen langeren Array umkopiert werden. Beim Loschenmussen Elemente verschoben werden, um “Locher” zu vermeiden.

160 Informatik B • SS 02

null

info

prev next

x

prev

next

p a nprev

prev prev

next next next

p.next

n.prev

leere Liste: Einfügen von ‘x’:

Löschen von ‘a’:

next

prev

dummy dummy

Bag

Abbildung 45: Doppelt-verkettete Liste mit Dummy-Element

adt

<<interface>>>MyCollection

add(x: Object): Object

find(x: Object): Objectsub(x: Object): Objectcount(): Integer

adt.list

Bag Set EquivalenceSet

Abbildung 46: Struktur vonadt.list

• Dynamische Datentypen (Listen, Baume): haben keine fest vorgegebeneKapazitat.

• Doppelt-verkettete Liste: jedes Element verweist auf seinen Nachfolger undseinen Vorganger.

• Organisation der Liste als Ring mit ausgezeichnetem, zusatzlichem“Dummy”-Element (das nicht geloscht werden kann). Dadurch wird Einfugenund Loschen sehr einfach.

• Realisation von Bag als Implementation von adt/MyCollection . Danach:Set als Unterklasse von Bag und EquivalenceSet als Unterklasse von Set .

Informatik B • SS 02 161

11.6.2 Bag/List

Funktionalitat:Doppelt-verkettete Liste mit Dummy-Element; erlaubt ‘null’ als Objekt, vergleicht aufIdentitat, tragt gleiche Werte mehrfach ein, loscht immer nur ein Objekt.

// adt/list/Bag.java // A.T. Schreinerpackage adt.list;import adt.MyCollection;/** doubly linked list based collection with multiple insertion.

*/public class Bag implements MyCollection {

/** element structure.*/

protected static class Element {public final Object info; public Element prev, next;/** create and doubly link.

*/public Element (Object info, Element prev, Element next) {

this.info = info;this.prev = prev; prev.next = this;this.next = next; next.prev = this;

}/** create dummy: null information, linked to itself.

*/public Element () { info = null; prev = next = this; }/** detach from within a list.

*/public void unlink () { prev.next = next; next.prev = prev; }/** permit symbolic dump.

*/public String toString () {

return id()+" prev "+prev.id()+" next "+next.id()+" info "+info;}protected String id () {

String result = super.toString();return result.substring(result.lastIndexOf(’.’)+1);

}}/** list header, used as dummy element.

*/protected Element list = new Element();protected int count;/** insert an object into the collection, do not check if already present.

The object is added at list.next.@param x object to be added, may be null.@return x.

*/

162 Informatik B • SS 02

public Object add (Object x) {new Element(x, list, list.next); ++ count; return x;

}/** locate an object in the collection.

@param x object to be found.@return object from collection, as determined by locate().@throws RuntimeException if x cannot be found.

*/public Object find (Object x) throws RuntimeException {

return locate(x).info;}/** remove an object from the collection.

@param x object to be removed.@return object from collection, as determined by locate().@throws RuntimeException if x cannot be found.

*/public Object sub (Object x) {

Element e = locate(x); e.unlink(); -- count; return e.info;}/** @return number of distinct objects in the collection;

zero, if the collection is empty.*/

public int count () { return count; }/** locate an object in the collection.

@param x object to be found.@return (last) element if present, based on identity.@throws RuntimeException if x cannot be found.

*/protected Element locate (Object x) {

for (Element e = list.next; e != list; e = e.next)if (e.info == x) return e;

throw new RuntimeException(x+": not found");}/** permit symbolic dump.

*/public String toString() {

StringBuffer buf = new StringBuffer(super.toString());buf.append(" count ").append(count);Element e = list;do

buf.append(’\n’).append(e);while ((e = e.next) != list);return buf.toString();

}}

Informatik B • SS 02 163

11.6.3 Erlauterungen zu ‘Bag’

• Innere KlasseElement : ist nested top-level (static ).Kein Zugriff von Element auf Instanz-Felder der umschliessenden Klasse Bagnotwendig.

• Inhalt eines Elements ist vom Typ Object und final !

• Konstruktor mit drei Argumenten: Einhangen eines neuen Elements mit Inhaltinfo und Verkettung mit Vorganger prev und Nachfolger next .

• Konstruktor ohne Argumente: Erzeugung des Dummy-Element mit sich selbstals Vorganger und Nachfolger.

• unlink() veranlasst ein Element , sich selbst aus einer Liste auszuklinken,indem es einfach seine Nachbarn aufeinander verweisen lasst.

• Ausgabe: id() liefert Objekt-Referenz als String, wobei der volle Nameabgeschnitten wird. (super.toString() ist Aufruf der Methode derOberklasse Object ).

• Element -Konstruktoren, unlink() und toString() sind public , damit siein Unterklassen von Bag benutzt werden konnen.

• Der Struktur-Zugriff von der außeren Klasse Bag auf Komponenten derInnneren Klasse Element macht Implementierung effizienter (keine speziellenAccessor-Methoden). Es ware nicht notig gewesen, die Instanzvariablen vonElement public zu deklarieren, da in Java die außere Klasse auf alleKomponenten der inneren Klasse Zugriff hat.

• Ausserhalb von adt.list.Bag ist Element unsichtbar! (Element ist nur viaBag erreichbar. Element ist protected , also nur in Unterklassen von Bagzugreifbar.) Das Innenleben von Bag geht niemand etwas an, Bag ist eineStruktur, in der Elemente aufbewahrt werden.

• Die MyCollection-Operationen (add() , sub() , find() und count() ) werdenauf Element -Operationen zuruckgespielt.

• Nach dem bewahrten Schema muss eine einzige Methode – locate() –bemuht werden, um das Element zu finden, in dem ein Object gespeichert ist.Wird ein Objekt nicht gefunden, wird eine RunTimeExeception geworfen.(besser ware spezifische Exception)

• Suche beginnt bei next vom Ring-Element list (Dummy) und darf list nichterreichen. Eine leere Liste besteht nur aus list , das dann mit sich selbstverkettet ist.

• Bei der symbolischen Darstellung muss man ein bisschen aufpassen: Bagfordert jedes Element – inklusive list – auf, sich selbst darzustellen. EinElement darf aber seine Nachbarn nur nach id() und nicht nach ihrerDarstellung fragen, sonst wird das Ganze im Ring herum rekursiv.

• Zum Testen wird adt.Test verwendet. Ohne Schalter −i werdenString-Objekte mit denselben Zeichenketten als identische Objekte behandelt!

164 Informatik B • SS 02

• Als erstes Element wird immer das Dummy-Element ausgegeben.

$ java adt.Test adt.list.Bag axel null ’ ’ null . - null - axel .adt.list.Bag@65fcc count 4Bag$Element@65fca prev Bag$Element@65fbf next Bag$Element@65fbc info nullBag$Element@65fbc prev Bag$Element@65fca next Bag$Element@65fbd info nullBag$Element@65fbd prev Bag$Element@65fbc next Bag$Element@65fbe infoBag$Element@65fbe prev Bag$Element@65fbd next Bag$Element@65fbf info nullBag$Element@65fbf prev Bag$Element@65fbe next Bag$Element@65fca info axeladt.list.Bag@65fcc count 2Bag$Element@65fca prev Bag$Element@65fbe next Bag$Element@65fbd info nullBag$Element@65fbd prev Bag$Element@65fca next Bag$Element@65fbe infoBag$Element@65fbe prev Bag$Element@65fbd next Bag$Element@65fca info null

11.6.4 Unterklasse ‘Set’

Funktionalitat:Doppelt-verkettete Liste mit Dummy-Element; erlaubt ‘null’ als Objekt, vergleicht aufIdentitat, tragt gleiche Werte nur einmal ein, loscht immer nur ein Objekt.↪→ Unterschied zu Bag: Methode add() kontrolliert, ob sein Argument schon vorhan-den ist.

// adt/list/Set.java // A.T. Schreinerpackage adt.list;/** doubly linked list based collection with unique identity insertion.

*/public class Set extends Bag {

/** insert an object into the collection, unless present.@param x object to be added, may be null.@return object from collection.

*/public Object add (Object x) {

try {return super.find(x); // avoid inadvertent override

} catch (RuntimeException e) { }return super.add(x);

}}

Implementierung analog zu adt.array.Set.java . Kein Reuse, da eine Klasse nureine Oberklasse erweitern kann.

11.6.5 Unterklasse ‘EquivalenceSet’

Funktionalitat:Doppelt-verkettete Liste mit Dummy-Element; erlaubt ‘null’ als Objekt, vergleicht aufAquivalenz, tragt gleiche Werte nur einmal ein, loscht immer nur ein Objekt.↪→ Unterklasse zu Set , Uberschreiben von locate() .

Informatik B • SS 02 165

// adt/list/EquivalenceSet.java // A.T. Schreinerpackage adt.list;/** doubly linked list based collection with unique insertion based on

equals().*/

public class EquivalenceSet extends Set {/** locate an object in the collection.

@param x object to be found.@return (last) element if present, based on equals().@throws RuntimeException if x cannot be found.

*/protected Element locate (Object x) {

for (Element e = list.next; e != list; e = e.next)if (adt.array.EquivalenceSet.equals(x, e.info)) return e;

throw new RuntimeException(x+": not found");}

}

Aufruf der public definierten Klassenmethode von adt.array.EquivalenceSet !

11.7 Implementation mit Suchbaum

11.7.1 Suchbaume

• Suchbaum: dynamische Datenstruktur mit Ordnung.

• Suche nach Objekten wird effizienter (O(log2 n)) als lineares Suchen in Arraysund Listen (O(n)).

• Aber: Einfugen und Loschen wird aufwendiger, da die Ordnung im Baumerhalten bleiben muss.

• Hauufig: Binarer Baum mit key/data-Paaren in den Knoten. InvarianteEigenschaft: alle keys im linken Unterbaum sind kleiner als der key desaktuellen Knotens, alle keys im rechten Unterbaum grosser.

• Um Suche effizient zu halten, sollte der Baum moglichst ausgewogen sein(Hohen-Balance, Gewichts-Balance fur Elemente mit annahernd gleichenZugriffswahrscheinlichkeiten).

• Im Folgenden: Eingetragen werden nicht key/data-Paare sondern Elemente. DieElemente mussen Comparable sein! (vgl. Marker-Interface).

• Das Interface Comparable deklariert die Methode compareTo() , dieanti-symmetrisch ist (Ordnungsrelation!) und angibt, ob ihr Empfanger kleiner(Resultat < 0), gleich (Resultat = 0) oder grosser (Resultat > 0) als dasArgument-Objekt ist. (Gleichheit muss vertraglich mit equals() sein.)

166 Informatik B • SS 02

2

1 3 7

6

4

5

root

2 6

left rightinfo

left leftinfo info

right right4

Set

sub

Abbildung 47: Suchbaum: Klassische Darstellung (links) und alsadt.tree.set

11.7.2 Set/Tree

Funktionalitat:Speichern eines von add() gelieferten Comparable Wertes in einem Element, dasrekursiv auf kleinere und grossere Werte verweist, die ebenfalls mit Element -Objektengespeichert sind.erlaubt ‘null’ als Objekt, vergleicht auf Identitat, tragt gleiche Werte nur einmal ein,loscht immer nur ein Objekt.

• Grundgedanke: Es wird wieder eine Hilfsfunktion locate() verwendet, um einObjekt in der Collection aufzufinden, die von add() , find() und sub()verwendet wird.

• locate() realisiert die Traversierung des Baums.

• Funktionalitat von locate() im Suchbaum:

– Ist der Wert des gesuchten Objekts gleich dem aktuellen Element, dannliefere das Element zuruck.

– Ist der Wert des gesuchten Objekts kleiner dem aktuellen Element, dannSuche im linken Unterbaum weiter.

– Ist der Wert des gesuchten Objekts grosser dem aktuellen Element, dannSuche im rechten Unterbaum weiter.

• Spezialbehandlung des null -Objekts ist wieder notwendig: null ist kleinstesElement, also “ganz links unten” im Suchbaum.

• Wenn locate() das gesuchte Objekt nicht gefunden hat, so sind wir bei derTraverse aber an der Stelle gelandet, wo es stehen sollte.

Informatik B • SS 02 167

NotFound

Found

MyCollection<<interface>>

locate(x: Object): Result

Set

Set.Element

Result <<interface>>

at: Integer

at: Integer

add(x: Object): Object

find(): Objectsub(): Object

...

...kennt

Abbildung 48: Objekt-Orientierter Entwurf vonadt.tree.set

• Problem: add() , sub() und find() benotigen die Position im Baum, an derdas gesuchte Objekt steht/eingetragen werden soll.Beim Array war dies einfach: (1) Suche liefert Indexplatz, (2) Methode springtan den entsprechenden Platz.Um weiterhin die Lokalisation unabhangig von den MyCollection -Methodenzu halten, muss man sich die Position im Baum merken, um sie in diesenMethoden nutzen zu konnen.Objekt-Orientierte Losung: “Einfrieren” des Ergebnisses der Traverse in einemObjekt! (das das Interface Result ) implementiert.

• Spezielle Realisierung der Datenstruktur “Suchbaum”: Element ist selbstSuchbaum, besteht also aus Eintrag und Verweis auf linken und rechtenUnterbaum.

// adt/tree/Set.java // A.T. Schreinerpackage adt.tree;import adt.MyCollection;import adt.Visitable;import adt.Visitor;/** binary tree based collection for <tt>Comparable</tt> with unique insertion.

*/public class Set implements MyCollection, Visitable {

protected Element[] sub = { null };/** element structure, <b>not</b> limited to <tt>Comparable</tt>.

*/protected static class Element extends Set {

public final Object info;/** create.

*/public Element (Object info) { this(info, null, null); }

168 Informatik B • SS 02

/** create and link.*/

public Element (Object info, Element left, Element right) {this.info = info; sub = new Element[] { left, right };

}/** let this disappear.

@return combined subtrees as a tree.*/

public Element unroot () {if (sub[0] == null) return sub[1]; // nothing at left... rightif (sub[1] == null) return sub[0]; // nothing at right... leftElement e = sub[0]; // else start at left...while (e.sub[1] != null) e = e.sub[1]; // ...move to it’s bottom righte.sub[1] = sub[1]; // ...and attach my right therereturn sub[0]; // ...all is below left

}/** adjust count by current element.

*/public int count () { return super.count()+1; }/** permit symbolic dump.

*/public String toString () { return info+""; }/** receive a visitor.

*/public boolean visit (Visitor v) {

return visit(0, v) && v.visit(info) && visit(1, v);}

}/** inefficient, unless the collection is empty.

@return number of distinct objects in the collection;zero, if the collection is empty.

*/public int count () {

int result = 0;for (int n = 0; n < sub.length; ++ n)

if (sub[n] != null) result += sub[n].count();return result;

}/** insert an object into the collection.

@throws ClassCastException if x is not <tt>Comparable</tt>.*/

public Object add (Object x) throws ClassCastException {return locate(x).add(x);

}/** locate an object in the collection.

@throws RuntimeException if not found.@throws ClassCastException if x is not <tt>Comparable</tt>.

*/

Informatik B • SS 02 169

public Object find (Object x) throws ClassCastException {return locate(x).find();

}/** remove an object from the collection.

@throws RuntimeException if not found.@throws ClassCastException if x is not <tt>Comparable</tt>.

*/public Object sub (Object x) throws ClassCastException {

return locate(x).sub();}/** operations on comparison state of locate().

*/protected interface Result {

Object add (Object x);Object find ();Object sub ();

}/** locate an object in the collection.

@param x object to be found.@return comparison state for further processing.

*/protected Result locate (Object x) throws ClassCastException {

Comparable info = (Comparable)x; // can still be nullSet s = this; int at = 0;for (;;) {

if (s.sub[at] == null) return s.new NotFound(at);// cannot involve null in compareTo...

int c; // ...make null less than anythingif (s.sub[at].info == null) c = info == null ? 0 : 1;else c = info == null ? -1 : info.compareTo(s.sub[at].info);if (c == 0) return s.new Found(at);s = s.sub[at]; at = c < 0 ? 0 : 1;

}}/** this.sub[at] is null and should be Element(x).

*/protected class NotFound implements Result {

protected final int at;public NotFound (int at) { this.at = at; }public Object add (Object x) { sub[at] = new Element(x); return x; }public Object find () { throw new RuntimeException("not found"); }public Object sub () { throw new RuntimeException("not found"); }

}/** this.sub[at].info is x.

*/protected class Found implements Result {

protected final int at;public Found (int at) { this.at = at; }

170 Informatik B • SS 02

public Object add (Object x) { return sub[at].info; }public Object find () { return sub[at].info; }public Object sub () {

Object result = sub[at].info; sub[at] = sub[at].unroot(); return result;}

}/** receive a visitor.

*/public boolean visit (Visitor v) { return visit(0, v); }protected boolean visit (int at, Visitor v) {

return sub[at] != null ? sub[at].visit(v) : true;}/** permit symbolic dump.

*/public String toString () {

class Dumper implements Visitor {protected StringBuffer buf = new StringBuffer();public boolean visit (Object o) {

buf.append(’\n’).append(o); return true;}public String toString () { return buf.toString(); }

}Dumper d = new Dumper(); visit(d);return super.toString()+" count "+count()+d.toString();

}}

11.7.3 Erlauterungen zu ‘Set’

• Visitor , Visitable : Interfaces in adt (vgl. Visitor Pattern, Cooper, Kap. 26).siehe weiter unten

• Instanzvariable sub als Array von Element -en.Idee: Bei Set hat sub ein Element, namlich den kompletten Suchbaum. BeiElement hat sub zwei Elemente, mit sub[0] als linkem (kleinere Elemente)und sub[1] als rechtem (grossere Elemente) Unterbaum.

• Wieder Element als statische innere Klasse, aber: stammt von Set ab und erbtdeshalb die Instanzvariable sub .

• Die Modellierung des ADT Suchbaum uber Element als Unterklasse desSuchbaums selbst ist nicht Standard! (vgl. Realisierung in Vorlesung InformatikA) Bei der hier gezeigten Implementierung werden dafur objekt-orientierteTechniken sehr schon verdeutlicht.

• info -Objekte sind hier allgemein als vom Typ Object deklariert und nicht aufComparable beschrankt. (Platz fur eigene Definitionen von Vergleichen)

• Analog zur Liste gibt es zwei Konstruktoren: Wurzel mit zwei Unterbaumen oderBlatt.

Informatik B • SS 02 171

Tabelle 5: Verhalten vonlocate()

Gesucht Eintrag Wert weiternull = null 0 fertiganderes > null 1 rechtsnull < anderes -1 linksanderes ? anderescompareTo() depends

• Analog zu unlink() ist unroot() realisiert: Hat das aktuelle Element keinenoder nur einen Unterbaum wird dieser (null wenn kein Unterbaum)zuruckgeliefert.Komplizierterer Fall: Element hat zwei Unterbaume. An das rechteste Elementim linken Unterbaum (grosstes Element vor dem aktuellen) wird der rechteUnterbaum angehangt.

• count() wird mit super auf Set zuruckgespielt und muss zusatzlich dasElement selbst zahlen, da super.count() die Anzahl der Elemente derUnterbaume aufaddiert.

• add() , find() und sub() werden wieder uber locate() realisiert.locate() muss entweder ein vorhandenes Element im Suchbaum finden odereine geeignete Position liefern, an der ein Element eingefugt werden soll.

• Neue Realisation: locate() liefert ein Objekt, das man mit Einfugen, Findenoder Loschen beauftragen kann. In diesem Objekt wird der Zustand deraktuellen Baumtraverse eingefroren (Verweis auf aktuellen Knoten Element ).

• Startet mit s beim Set und Index at bei 0. Das Argument (Object x ) mussComparable sein.

• Ist sub[at] null , so gibt es das gesuchte Element nicht. Es hatte aber andiese Stelle gehort.

• Spezielle Behandlung von null -Referenz: Entweder null ist an Position ateingetragen, dann wurde der Wert gefunden; anderenfalls wird -1zuruckgeliefert (null ist kleiner als alle anderen Werte).

• Das endgultige Vergleichsresultat hangt vom weiteren Verlauf der Suche ab:Entweder der Vergleich stimmt, dann wurde eine Position fur den gesuchtenWert gefunden, oder die Suche geht im linken oder rechten Unterbaum weiter.

• Ein Wert wird bei s.sub[at] gefunden oder er musste dort gespeichertwerden.

• Member-Klassen NotFound und Found : zur Weiterverarbeitung des vonlocate() gelieferten Result -Objekts.

• Sie haben Zugriff auf Instanz-Komponenten der umschliessenden Klasse, furdie sie erzeugt wurden – hier speziell auf Komponenten von s .

172 Informatik B • SS 02

• Ein NotFound - oder Found -Objekt kennt also durch seine Konstruktion dasElement oder Set s , das bei der Suche entdeckt wurde und hat damit Zugriffauf dessen sub . Es muss sich nur den Index at explizit merken.

• Durch die Definition des Result -Interfaces und der inneren Klassen NotFoundund Found lassen sich add() , find() und sub() wesentlich einfacherrealisieren als durch explizite if -Abfragen zur Fallunterscheidung in diesenMethoden selbst.

• Der einzig komplizierte Fall – das Loschen eines Wertes – kann mithilfe vonunroot() leicht bewerkstelligt werden.

• Nested top-level Klassen sind weniger aufwendig als echte Member-Klassen.Man sollte echte Member-Klassen nur dann verwenden, wenn man denimpliziten Verweis auf die umschliessende Instanz benotigt.

• Haufig wird als Erzeuger fur die innere Instanz this (vor new) verwendet.

• Eine Konstruktion wie die NotFound - und Found -Objekte in adt.tree.Setwird auch als Closure bezeichnet: Bei der Konstruktion wird eine bestimmteSituation eingefangen, die spater durch Nachricht an ein solches Objektweiterverarbeitet werden kann (vgl. auch die anonymen Klassen in adt.Test ).

11.8 Visitor

11.8.1 Konzept eines Visitor

• Ganz allgemein kann man von einer Collection verlangen, dass einem Besucher(Visitor) alle Insassen (Elemente) genau einmal vorgestellt werden.

• Interface Visitable : Methode zum Anliefern eines Visitor bei derCollection.Ein beliebiges Objekt ist ein Visitor, wenn ihm Objekte vorgefuhrt werdenkonnen.

• Interface Visitor : Methode, mit der die Collection dem Visitor ihre Insassenvorstellt.Eine Collection ist Visitable, wenn sie Besucher empfangen kann.

• Ausbaumoglichkeit: visit() in Visitor konnte mit verschiedenen Signaturenverschiedene Arten von Insassen unterscheiden.

• Beim Suchbaum hat man die schone Moglichkeit, Eintrage sortiertauszugeben. Beispielsweise kann adt.Test mit adt.tree.Set Wortereinlesen (String ist Comparable ) und sortiert ausgeben.

• Ein Suchbaum sollte Visitable sein, um die Sortierung ausnutzen zu konnen.

• Implementiert man einen Visitor , der die Insassen in einen StringBufferabbildet, kann man den Baum sehr elegant darstellen lassen. (Methodenvisit() und toString() in adt.tree.Set )

Informatik B • SS 02 173

Visitable<<interface>>

Visitor<<interface>>

visit(v: Visitor): Boolean visit(x: Object): Boolean

Set

visit(v: Visitor): Boolean

visit(at: Integer, v: Visitor): Boolean

toString(): String Dumper

visit(x: Object): Boolean

Set.Element

visit(v: Visitor): Boolean

Abbildung 49: Realisierung des Visitor-Patterns inadt.tree.set

• Die visit() -Methoden haben als Resultat-Wert boolean . Uber das Resultatder Methode in Visitor kann der Besucher steuern, ob die Traversefortgesetzt werden soll (Besucher sagt: “weiter” oder “ich will nicht mehr”).

11.8.2 ‘Visitor’, ‘Visitable’/ADT

// adt/Visitable.java // A.T. Schreinerpackage adt;/** framework for visitor pattern: ability to be visited.

*/public interface Visitable {

/** receive a visitor, manage the visit.@return true if the visitor always replies true.

*/boolean visit (Visitor v);

}

// adt/Visitor.java // A.T. Schreinerpackage adt;/** framework for visitor pattern: visiting object.

*/

174 Informatik B • SS 02

public interface Visitor {/** visit an object.

@return true to continue visiting.*/

boolean visit (Object x);}

11.8.3 Suchbaum mit Visitor

• In Set wird eine inorder Traversierung realisiert. (Drei Moglichkeiten, einenBaum zu traversieren: Inorder, Praorder, Postorder).

• visit() -Methoden in Set : visit() mit einem Argument schickt Visitor zusub[0] , visit() mit zwei Argumenten schickt Visitor zu Position at .

• visit() -Methoden in Element : visit() mit einem Argument realisiertInorder, visit() mit zwei Argumenten wird von Set geerbt.

• Fur adt.tree.Set implementiert man toString() mit einemDumper-Objekt, das jeden Insassen in seinen StringBuffer eintragt unddiesen bei toString() (von Dumper) als seine eigene Darstellung abliefert.

• Dumper ist ein Beispiel fur eine lokale Klasse (Es hatte auch eine anonymeKlasse genugt). Eine lokale Klasse kann jedoch mehr als ein Interface aufeinmal implementieren.

• Innerhalb der lokalen Klasse wird wieder eine visit() -Methode implementiert.

• In toString() wird die visit() -Methode von Set aufgerufen, der einDumper-Objekt ubergeben wird.

• Im zwei-parametrigen visit() wird gepruft, ob an der aktuellen Position nochein Unterbaum existiert. Wenn ja, wird die visit() -Methode fur diesenUnterbaum an Position at aufgerufen.

• Die eigentliche Arbeit erledigt die visit() -Methode von Element : Hier wirddie Inorder-Traverse realisiert. Das Objekt info wird an die visit() -Methodedes Visitors ubergeben.

11.9 Java Collection Classes

11.9.1 Grundstruktur

• Java collection framework in java.util : wichtige Klassen und Interfaces, ummit Collections zu arbeiten.

• Bis Java 1.1: nur Vector (jetzt ArrayList ) und HashTable (jetzt HashMap).

• Zwei Grundtypen von Collections:

Informatik B • SS 02 175

1. Collection (Interface): Gruppe von Objektenmit Set (Interface) als Collections ohne Dublikateund List (Interface) als Collection mit geordneten Elementen

2. Map (Interface): Menge von Assoziationen (Mappings) zwischen Objekten.

• weitere Interfaces: Iterator , ListIterator .Ahnlich zum Enumeration -Interface:

public interface Iterator {boolean hasNext(); // vgl. hasMoreElements() in EnumerationObject next(); // vgl. nextElement() in Enumerationvoid remove(); // zusaetzlich

}

remove() erlaubt sicheres Loschen von Elementen wahrend der Iteration.Geloscht wird das als letztes von next() gelieferte Element.Modifikation der Collection wahrend ihrer Aufzahlung ist mit remove() (und nurmit remove() ) moglich!

• Fur Objekte eigener Klassen, die in Collections gespeichert werden sollen,sollten die Methoden equals() und hashcode() entsprechend dergewunschten Funktionalitat uberschrieben werden.

• Die Klasse Collections liefert statische Methoden und Konstanten, die beimArbeiten mit Collections nutzlich sind.

11.9.2 Illustration

Set s = new HashSet(); // Implementation based on a hash tables.add("test"); // Add a String object to the setboolean b = s.contains("test2"); // Check whether a set contains an objs.remove("test"); // Remove a member from a set

Set ss = new TreeSet(); // TreeSet implements SortedSetss.add("b"); // Add some elementsss.add("a");// Now iterate through the elements (in sorted order) and print themfor(Iterator i = ss.iterator(); i.hasNext();)

System.out.println(i.next());

List l = new LinkedList(); // LinkedList implements a doubly linked listl = new ArrayList(); // ArrayList is more efficient, usuallyVector v = new Vector(); // Vector is an alternative in Java 1.1/1.0l.addAll(ss); // Append some elements to itl.addAll(1, ss); // Insert elements again at index 1Object o = l.get(1); // Get the second elementl.set(3, "new element"); // Set the fourth element

176 Informatik B • SS 02

C

C

C

C

C

S

S

S

S

S

C

C

S

S

java.lang

Object AbstractCollection AbstractList AbstractSequentialList LinkedList

ArrayList

Vector

HashSet

TreeSet

AbstractSet

Stack

Collection<<interface>>

List

Set SortedSet

<<interface>>

<<interface>> <<interface>>

java.util

AbstractMap HashMap

TreeMap

<<interface>>Map SortedMap

<<interface>>

Iterator ListIterator

Comparator

<<interface>> <<interface>>

<<interface>>

Abbildung 50: Java Collection Classes (S: implements Serializable, C: implements Clonable)

Informatik B • SS 02 177

l.add("test"); // Append a new element to the endl.add(0, "test2"); // Insert a new element at the startl.remove(1); // Remove the second elementl.remove("a"); // Remove the element "a"l.removeAll(ss); // Remove elements from this setif(!l.isEmpty()) // If list is not empty

System.out.println(l.size()); // print out the number of elements in itboolean b1 = l.contains("a"); // Does it contain this value?booelan b2 = l.containsAll(ss); // Does it contain all these values?List sublist = l.subList(1,3); // A sublist of the 2nd and 3rd elementsObject[] elements = l.toArray(); // Convert it to an arrayl.clear(); // Delete all elements

Map m = new HashMap(); // Hashtable an alternative in Java 1.1./1.0m.put("key", new Integer(42)); // Associate a value object with key objectObject value = m.get("key"); // Look up the value association from the Mapm.remove("key"); // Remove association from the MapSet keys = m.keySet(); // Get the set of keys held by the Map

Arrays und Collections konnen wechselseitig konvertiert werden:

Object[] members = set.toArray(); // Get set elements as an arrayObject[] items = list.toArray(); // Get list elements as an arrayObject[] keys = map.keySet().toArray(); // Get map key objects as an arrayObject[] values = map.values().toArray(); // Get map value objects as an array

List l = Arrays.asList(elements); // View array as ungrowable listList l = new ArrayList(Arrays.asList(elements));

// Make a growable copy of it

So wie java.util.Arrays Methoden zur Manipulation von Arrays anbietet,definiert java.util.Collections Methoden zum Umgang mit Collections.Beispiele:

Collections.sort(list); // Sort a listint pos = Collections.binarySearch(list, "key"); // List must be sorted firstCollections.max(c); // Find largest element in Collection cCollections.min(c); // Find smallest element in Collection cCollections.reverse(list); // Reverse listCollections.shuffle(list); // Mix up list

178 Informatik B • SS 02

12 Reflections

12.1 Methoden des Reflection-API

• Das Reflection-API reprasentiert (reflektiert) Klassen, Schnittstellen und Objektein der aktuellem JVM.

• Anwendung: vor allem fur Debugger, Class-Browser, GUI-Builder.

• Dale E. Parson (2000). Using Java Reflection to Automate Extension Language Parsing.ACM SIGPLAN Notices, 35(1), pp. 67–80.

Methodenubersicht:

• Bestimmung der Klasse eines Objekts.

• Information uber Modifikatoren, Felder, Methoden, Konstruktoren, Oberklasseneiner Klasse.

• Information, welche Konstanten und Methoden-Deklarationen zu einemInterface gehoren.

• Erzeugung einer Instanz einer Klasse, deren Namen erst zur Laufzeit bekanntist.

• Zugriff und Belegung eines Objekt-Feldes, auch wenn der Name des Feldes erstzur Laufzeit bekannt ist.

• Aufruf (Invocation) einer Methode eines Objekts, auch wenn die Methode erstzur Laufzeit bekannt ist.

• Erzeugen eines neuen Arrays, dessen Grosse und Komponenten-Typ erst zurLaufzeit bekannt sind, und Modifikation von Komponenten.

12.2 Die Klassen ‘Class’, ‘Method’, ‘Field’ und ‘Constructor’

• Die Klasse Class reprasentiert einen Java-Typ (Klasse, Interface, primitiverTyp).Fur jede von der JVM geladene Klasse existiert genau ein Class -Objekt.Dieses Objekt kann durch Aufruf der getClass() -Methode fur jede beliebigeInstanz besorgt werden. Wie man Klassen mit Class -Methoden inspizierenkann, wird im nachsten Abschnitt dargestellt.

public final class Class extends Object implements Serializable {public static Class forName(String name) throws ClassNotFoundException;public Field[] getFields() throws SecurityException;public Method[] getMethods() throws SecurityException;public Constructor[] getConstractors() throws SecurityException;// many more

}

Informatik B • SS 02 179

• Die java.lang.reflect -Klassen Method , Field und Constructorreprasentieren Methoden, Felder und Konstruktoren einer Klasse.Entsprechende Objekte werden von entsprechenden get -Methoden einesClass -Objekts zuruckgeliefert.

• Diese Klassen sind Unterklassen von AccessibleObject und implementierendas Member-Interface. Wie Klassenkomponenten inspiziert werden konnen,wird im nachsten Abschnitt dargestellt. Mit newInstance() konnen zurLaufzeit neue Objekte erzeugt werden (ubernachster Abschnitt).

public final class Method extends AccessibleObject implements Member {public String getName();public Class[] getParameterTypes();public Class getReturnType();public Object invoke(Object obj, Object[] args)

throws IllegalAccessException, IllegalArgumentException,InvocationTargetException;

// many more}

public final class Field extends AccessibleObject implements Member {public String getName();public Class getType();public boolean equals(Object obj);public int hashCode();// many more

}

public final class Constructor extends AccessibleObject implements Member {public String getName();public Class[] getParameterTypes();public Class[] getExceptionTypes();public Object newInstance(Object[] initargs) throws

InstantiationException, IllegalAccessException, IllegalArgumentException;// many more

}

12.3 Inspektion von Klassen

• Das Laufzeitsystem halt fur jede Klasse/Schnittstelle ein nicht-anderbaresClass -Objekt, das Informationen uber die Klasse/Schnittstelle enthalt.

12.3.1 Abruf eines ‘Class’ Objekts

<object >.getClass() → Class

<class >.getSuperClass() → Class

180 Informatik B • SS 02

Class.forName( <String >) → Class

<class >.class → Class

• Wenn eine Instanz einer Klasse verfugbar ist, kann dessen Klasse abgefragtwerden: Class c = mystery.getClass();

• Abruf der Oberklasse: (Circle -Objekt mit Oberklasse Shape )

Circle k = new Circle();Class c = k.getClass();Class s = c.getSuperClass();

• Wenn der Name einer Klasse zur Compile-Zeit bekannt ist, kann dasKlassenobjekt abgerufen werden, indem .class an den Namen angehangtwird.

Class c = java.awt.Button.class;

• Wenn der Klassen-Name erst zur Laufzeit verfugbar ist, kann dasKlassen-Objekt uber den Namen (als String reprasentiert) erzeugt werden.

Class c = Class.forName(strg);

12.3.2 Abruf des Klassen-Namens eines Objekts

<class >.getName() → String

import java.awt.Button;

class SampleName {public static void main(String[] args) {

Button b = new Button();printName(b);

}

static void printName(Object o) { Class c = o.getClass(); String s =c.getName(); System.out.println(s);

} }

Ruckgabe des voll qualifizierten Namens der Klasse als String :java.awt.Button

Informatik B • SS 02 181

12.3.3 Abruf von Klassen-Modifikatoren

<class >.getModifiers() → int

Modifier.isPublic( <intcode >) → bool

Modifier.isAbstract( <intcode >) → bool

Modifier.isFinal( <intcode >) → bool

import java.lang.reflect.Modifier;

class SampleModifier {

public static void main(String[] args) {String s = new String();printModifiers(s);

}

public static void printModifiers(Object o) {Class c = o.getClass();int m = c.getModifiers();if (Modifier.isPublic(m))

System.out.println("public");if (Modifier.isAbstract(m))

System.out.println("abstract");if (Modifier.isFinal(m))

System.out.println("final");}

}

Ausgabe: Modifikatoren von String sind:

publicfinal

12.3.4 Abruf von Oberklassen

<class >.getSuperclass() → Class

import java.awt.Button;

class SampleSuper {public static void main(String[] args) { Button b = new Button();

printSuperclasses(b);}

static void printSuperclasses(Object o) {Class subclass = o.getClass();Class superclass = subclass.getSuperclass();

182 Informatik B • SS 02

while (superclass != null) {String className = superclass.getName();System.out.println(className);subclass = superclass;superclass = subclass.getSuperclass();

} } }

Die Oberklasse von Button ist Component und deren Oberklasse ist Object .

java.awt.Componentjava.lang.Object

12.3.5 Abruf des implementierten Interfaces einer Klasse

<class >.getInterfaces() → Class[]

import java.io.RandomAccessFile;import java.io.IOException;

class SampleInterface {public static void main(String[] args) {

try {RandomAccessFile r = new RandomAccessFile("myfile", "r");printInterfaceNames(r);

} catch (IOException e) { System.err.println(e); }}

static void printInterfaceNames(Object o) {Class c = o.getClass();Class[] theInterfaces = c.getInterfaces();for (int i = 0; i < theInterfaces.length; i++) {

String interfaceName = theInterfaces[i].getName();System.out.println(interfaceName);

} } }

Die Klasse RandomAccessFile implementiert die Interfaces DataOutput undDataInput :

java.io.DataOutputjava.io.DataInput

12.3.6 Interface oder Klasse?

<class >.isInterface() → bool

import java.util.Observer;import java.util.Observable;

Informatik B • SS 02 183

class SampleCheckInterface {public static void main(String[] args) {

Class observer = Observer.class;Class observable = Observable.class;verifyInterface(observer);verifyInterface(observable);

}

static void verifyInterface(Class c) {String name = c.getName();if (c.isInterface()) {

System.out.println(name + " is an interface.");} else { System.out.println(name + " is a class."); }

} }

Ausgabe:

java.util.Observer is an interface.java.util.Observable is a class.

12.3.7 Abruf von Klassen-Feldern

<class >.getFields() → Field[]

<field >.getType() → Class

import java.lang.reflect.Field;import java.awt.GridBagConstraints;

class SampleField {public static void main(String[] args) {

GridBagConstraints g = new GridBagConstraints();printFieldNames(g);

}

static void printFieldNames(Object o) {Class c = o.getClass();Field[] publicFields = c.getFields();for (int i = 0; i < publicFields.length; i++) {

String fieldName = publicFields[i].getName();Class typeClass = publicFields[i].getType();String fieldType = typeClass.getName();System.out.println("Name: " + fieldName +

", Type: " + fieldType);}

} }

Beginn der Ausgabe:

184 Informatik B • SS 02

Name: RELATIVE, Type: intName: REMAINDER, Type: intName: NONE, Type: intName: BOTH, Type: intName: HORIZONTAL, Type: intName: VERTICAL, Type: int ...

12.3.8 Abruf von Klassen-Konstruktoren

<class >.getConstructors() → Constructors[]

<constructor >.getParameterTypes() → Class[]

import java.lang.reflect.Constructor;import java.awt.Rectangle;

class SampleConstructor {public static void main(String[] args) {

Rectangle r = new Rectangle();showConstructors(r);

}static void showConstructors(Object o) {

Class c = o.getClass();Constructor[] theConstructors = c.getConstructors();for (int i = 0; i < theConstructors.length; i++) {

System.out.print("( ");Class[] parameterTypes =

theConstructors[i].getParameterTypes();for (int k = 0; k < parameterTypes.length; k ++) {

String parameterString = parameterTypes[k].getName();System.out.print(parameterString + " ");

}System.out.println(")");

}} }

( )( int int )( int int int int )( java.awt.Dimension )( java.awt.Point )( java.awt.Point java.awt.Dimension )( java.awt.Rectangle )

12.3.9 Abruf von Methoden-Information

<class >.getMethods() → Method[]

<method >.getReturnType() → Class

Informatik B • SS 02 185

<method >.getParameterTypes() → Class[]

import java.lang.reflect.Method;import java.awt.Polygon;

class SampleMethod {public static void main(String[] args) {

Polygon p = new Polygon();showMethods(p);

}

static void showMethods(Object o) {Class c = o.getClass();Method[] theMethods = c.getMethods();for (int i = 0; i < theMethods.length; i++) {

String methodString = theMethods[i].getName();System.out.println("Name: " + methodString);String returnString =

theMethods[i].getReturnType().getName();System.out.println(" Return Type: " + returnString);Class[] parameterTypes = theMethods[i].getParameterTypes();System.out.print(" Parameter Types:");for (int k = 0; k < parameterTypes.length; k ++) {

String parameterString = parameterTypes[k].getName();System.out.print(" " + parameterString);

}System.out.println();

}}

}

Name: equalsReturn Type: booleanParameter Types: java.lang.Object

Name: getClassReturn Type: java.lang.ClassParameter Types:

Name: hashCodeReturn Type: intParameter Types:

.

.Name: intersects

Return Type: booleanParameter Types: double double double double

Name: intersectsReturn Type: booleanParameter Types: java.awt.geom.Rectangle2D

186 Informatik B • SS 02

Name: translateReturn Type: voidParameter Types: int int

12.4 Manipulation von Objekten zur Laufzeit

• Erzeugung und Manipulation von Objekten, deren Klassennamen erst zurLaufzeit bekannt sind.

12.4.1 Dynamische Erzeugung von Objekten

• Der new-Operator kann nicht auf Variablen angewendet werden. Stattdessen:newInstance() .

import java.awt.Rectangle;class SampleNoArg {

public static void main(String[] args) {Rectangle r = (Rectangle) createObject("java.awt.Rectangle");System.out.println(r);

}static Object createObject(String className) {

Object object = null;try {

Class classDefinition = Class.forName(className);object = classDefinition.newInstance();

} catch (InstantiationException e) { System.err.println(e); }catch (IllegalAccessException e) { System.err.println(e); }catch (ClassNotFoundException e) { System.err.println(e); }

return object;} }

Ausgabe: java.awt.Rectangle[x=0,y=0,width=0,height=0]

12.4.2 Exceptions beim dynamischen Erzeugen von Objekten

• ClassNotFoundException : Es wird versucht, ein Objekt einer Klasse zuerzeugen, die nicht (auf dem aktuellen Pfad) existiert.

• IllegalAccessException : Klasse darf nicht zugegriffen werden (z. B. nichtpublic )

• InstantiationException : Fehler bei der Objekterzeugung (z.B. es gibtkeinen Konstruktor ohne Argumente)

• IllegalArgumentException : beim Aufruf von Konstruktor/Methode mitArgumenten. (RuntimeException )

• InvocationTargetException : “Meta”-Exception; es tritt Exception innerhalbdes aufgerufenen Konstruktors (bzw. der aufgerufenen Methode) auf.

Informatik B • SS 02 187

12.4.3 Dynamische Erzeugung mit Konstruktor-Argumenten

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.awt.Rectangle;

class SampleInstance {

public static void main(String[] args) {

Rectangle rectangle;Class rectangleDefinition;Class[] intArgsClass = new Class[] {int.class, int.class};Integer height = new Integer(12);Integer width = new Integer(34);Object[] intArgs = new Object[] {height, width};Constructor intArgsConstructor;

try {rectangleDefinition = Class.forName("java.awt.Rectangle");intArgsConstructor =

rectangleDefinition.getConstructor(intArgsClass);rectangle =

(Rectangle) createObject(intArgsConstructor, intArgs);} catch (ClassNotFoundException e) {

System.err.println(e);} catch (NoSuchMethodException e) {

System.err.println(e);}

}

public static Object createObject(Constructor constructor,Object[] arguments) {

System.out.println ("Constructor: " + constructor);Object object = null;

try {object = constructor.newInstance(arguments);System.out.println ("Object: " + object);return object;

} catch (InstantiationException e) {System.err.println(e);

} catch (IllegalAccessException e) {System.err.println(e);

} catch (IllegalArgumentException e) {System.err.println(e);

} catch (InvocationTargetException e) {

188 Informatik B • SS 02

System.err.println(e);}return object;

}}

Ausgabe:

Constructor: public java.awt.Rectangle(int,int)Object: java.awt.Rectangle[x=0,y=0,width=12,height=34]

12.4.4 Abruf und Belegung von Feldern

<class >.getField( <string >) → Field

<field >.set( <object >, <object >) <field >.get( <object >)

import java.lang.reflect.Field;import java.lang.reflect.NoSuchFieldException;import java.awt.Rectangle;

class SampleSet {public static void main(String[] args) {

Rectangle r = new Rectangle(100, 20);System.out.println("original: " + r.toString());modifyWidth(r, new Integer(300));System.out.println("modified: " + r.toString());

}static void modifyWidth(Rectangle r, Integer widthParam ) {

Field widthField;Integer widthValue;Class c = r.getClass();try {

widthField = c.getField("width");widthField.set(r, widthParam);

} catch (NoSuchFieldException e) { System.err.println(e); }catch (IllegalAccessException e) { System.err.println(e); }

} }

Ausgabe:

original: java.awt.Rectangle[x=0,y=0,width=100,height=20]modified: java.awt.Rectangle[x=0,y=0,width=300,height=20]

12.4.5 Method Invocation

<class >.getMethod( <string >, parTypes) → Method

<method >.invoke( <object >, <arguments[] >)

Informatik B • SS 02 189

import java.lang.reflect.Method;import java.lang.reflect.NoSuchMethodException;import java.lang.reflect.InvocationTargetException;

class SampleInvoke {

public static void main(String[] args) {String firstWord = "Hello ";String secondWord = "everybody.";String bothWords = append(firstWord, secondWord);System.out.println(bothWords);

}

public static String append(String firstWord, String secondWord) {String result = null;Class c = String.class;Class[] parameterTypes = new Class[] {String.class};Method concatMethod;Object[] arguments = new Object[] {secondWord};try {

concatMethod = c.getMethod("concat", parameterTypes);result = (String) concatMethod.invoke(firstWord, arguments);

} catch (NoSuchMethodException e) {System.err.println(e);

} catch (IllegalAccessException e) {System.err.println(e);

} catch (InvocationTargetException e) {System.err.println(e);

}return result;

}

Ausgabe: Hello everybody.

12.5 Bemerkungen

• Reflections erlauben es, Entscheidungen auf die Laufzeit zu verschieben, dieman zur Compile-Zeit nicht treffen will oder kann (z.B. Erzeugung von Objektenvon zur Compile-Zeit unbekannten Klassen).

• Dadurch mussen bestimmte Arbeiten, die normalerweise der Compiler leistetzur Laufzeit erledigt werden (z.B. NoSuchMethodException ).

• Man sollte nicht unbedingt das Reflection API verwenden, wenn sich andereMoglichkeiten ergeben.Beispiel: Anstatt Method -Objekte zu benutzen, ist es meist sinnvoller, einInterface zu definieren und in der Klasse, die eine bestimmte Methode habensoll, zu implementieren.

190 Informatik B • SS 02

• Bei dynamischer Erzeugung und Nutzung von Objekten (Methoden) konnenviele Exceptions auftreten.

• Dynamisches Laden von Klassen kann einfach mit Class realisiert werden:Class c = Class.forName(classname) (siehe z.B. Kapitel “Collections”,Test

• Alternativen: java.lang.ClassLoader oder java.net.URLClassLoader .

Informatik B • SS 02 191

13 Multi-Threading – Grundlagen der Nebenlaufigkeit

13.1 Sequentialitat, Determinismus, Determiniertheit

• Sequentielles Programm:Es gibt genau einen nachsten Ausfuhrungsschritt, undalle Schritte werden nacheinander ausgefuhrt.

v = x;w = x;x = y;

v und w erhalten den Wert von x, danach erhalt x den Wert von y

• Deterministisches Programm:Programm, dessen Ablauf eindeutigvorherbestimmt ist; vgl. deterministische Automaten: bei gegebener Eingabegibt es in jedem Zustand genau einen klar definierten Folgezustand.

• Determiniertes Programm: Jede Ausfuhrung liefert bei gleichen Ausgangswertendas identische Ergebnis. (Ein deterministisches Programm ist immerdeterminiert, der Umkehrschluss gilt nicht zwangslaufig.)Darstellung mit Vor- und Nachbedingungen (vgl. Hoare-Kalkul):

{x = i, y = j}v = x;w = x;x = y;{v = w = i, x = y = j}

13.1.1 Nebenlaufigkeit

• Verzicht auf Sequentialitat: ↪→ Nebenlaufigkeit (concurrency)

– Anweisungen konnen parallel ausgefuhrt werden (mehrere Prozessorenoder Threads).

– Anweisungen konnen sequentiell in beliebiger Reihenfolge ausgefuhrtwerden.

• Sequentielle Programme lassen nicht explizit erkennen, ob die sequentielleOrdnung zur Losung eines gegebenen Problems tatsachlich erforderlich ist.Es ist schwierig, in einem sequentiellen Programm die potentiellparallelisierbaren Aktionen herauszufinden.

• Nebenlaufigkeit explizit sichtbar machen:

{x = i, y = j}conc w = x || v = x end conc;x = y;{v = w = i, x = y = j}

192 Informatik B • SS 02

willkurliche Sequentialisierung:

w = x; v = x; x = y;v = x; w = x; x = y;

• Im Bereich KI-Planung werden (bei partial order Planern) unabhangig losbareTeilprobleme automatisch beim Planaufbau erkannt (z.B. NOAH, Graphplan).

13.1.2 Nicht-Determinismus

• Manchmal sind nicht-deterministische Programme sinnvoll: Vermeidung vonUberspezifikation bei Gewahrleistung von Determiniertheit.

• Beispiel: Maximum zweier Zahlen

if (a > b) max = a; else max = b;

Dieser Algorithmuus ist bzgl. der Problemstellung uberspezifiziert: wenn a = bist, dann wird b zuruckgeliefert, obwohl es egal ist, ob a oder b zuruckgeliefertwird.

• Nicht-deterministische Auswahl mit Wachtern:

selecta >= b -> max = a

[] a <= b -> max = bend select

• [] “oder wenn”Wachter (guard) regelt, ob eine Alternative prinzipiell ausgewahlt werden kann.Alternativen sind nicht notwendigerweise disjunkt.

• Auswertung der Wachter in willkurlicher Reihenfolge.

13.1.3 Nicht-Determiniertheit

• In der Regel mochte man – auch bei nicht-deterministischen Programmen –determinierte Ergebnisse.

• Ergebnisse sind determiniert genau dann, wenn keine Schreib-/Schreib- undkeine Schreib-/Lese-Konflikte auftreten (Veranderung von Variablen-Werten).

• Erwunschte Nicht-Determiniertheit:Beispiel: Bestimme den kurzesten Weg in einem Graphen. Wenn es mehrerekurzeste Wege gibt, ist es egal, welcher davon zuruckgeliefert wird.

Beispiel:

{x = i, y = j}conc w = x || v = x || x = y; end conc;{v = w = ?, x = y = j}

Informatik B • SS 02 193

willkurliche Sequentialisierung:

w = x; v = x; x = y;v = x; x = y; w = x;x = y; w = x; v = x;...

ist nicht-determiniert.

13.1.4 Verzahnung

concw = x; v = w+1

|| y = x; z = yend conc

Mogliche Sequentialisierungen

(1) w = x; v = w+1; y = x; z = y;(2) y = x; z = y; w = x; v = w+1;

Weitere Verzahnungen

(3) w = x; y = x; v = w+1; z = y;(4) w = x; y = x; z = y; v = w+1;(5) y = x; w = x; v = w+1; z = y;(6) y = x; w = x; z = y; v = w+1;

• Bei der Sequentialisierung nebenlaufiger Anweisungsfolgen muss nur die injeder Anweisungsfolge vorgegebene Sequenz beachtet werden. Ansonstenkann beliebig verzahnt werden (interleaving).

• Hier ist das Ergebnis trotz nicht-deterministischer Auswahl determiniert, da keineKonflike auftreten und die vorgeschriebene Sequentialisierung erhalten bleibt.

• Bei jeder Programmausfuhrung kann eine andere Verzahnung auftreten. DieProgrammausfuhrung ist nicht reproduzierbar.

• Fehler konnen sich je nach Verzahnung nur gelegentlich bemerkbar machen.↪→ nebenlaufige Programm sind schwerer zu testen (validieren) und zuverifizieren als sequentielle!Vielfalt moglicher Zustandsubergange bei der Programmausfuhrung.

13.2 Nebenlaufigkeit in Java: Threads

• Greifen verschiedene (nebenlaufige) Aktivitaten auf verschiedene Adressraumezu, so spricht man von (parallelen) Prozessen.Findet Nebenlaufigkeit im selben Adressraum statt (z.B. eine Java VM), sospricht man von Threads (“Programmfaden”).(Addressraum: Menge aller zugreifbaren Speicherbereiche.)

194 Informatik B • SS 02

Runnable<<interface>>

run()

Thread

MAX_PRIORITY...

ErsterThread ZweiterThread

run()

join()start()run()

sleep()

...

runs run()

Abbildung 51: Definition von Threads

• In Java sind Threads integraler Bestandteil der Sprache und nahtlos in dasKonzept der Objekt-Orientierung eingebaut (Threads sind Objekte).

• Probleme: Synchronisation, Deadlocks

13.2.1 Definition von Threads

Zwei Moglichkeiten:

• Als Unterklasse der Klasse Thread .

• Durch Implementieren der Runnable -Schnittstelle (immer dann, wenn Klassebereits eine andere Klasse erweitert; z.B. bei Applets)

13.2.2 Die Klasse Thread

• Die run() -Methode definiert, was ein Thread (quasi gleichzeitig mit anderenThreads) ausfuhren mochte (analog zu main() ).

• Wie bei allen Methoden kann auch die run() -Methode auf Methoden undFelder anderer Objekte zugreifen.

Informatik B • SS 02 195

• Wichtige Methoden:

– start() : Starten des Threads (Aufruf der run() -Methode beimRunnable durch das System).

– join() : Warten auf das Zuendegehen eines Threads.

– sleep(long) : Schlafenlegen eines Threads.

– yield() : Pausieren, um anderen Threads eine Chance zu geben.

• Priorit aten: setPriority(int) / getPriority()

MIN_PRIORITY = 1 MAX_PRIORITY = 10 NORM_PRIORITY = 5

Konventionen:10 Crisis Management

7-9 Interactive, event-driven4-6 IO-bound2-3 Background computation

1 Run only, if nothing else can

• Deprecated (Termination bzw. Unterbrechung in inkonsistenten Zustandenmoglich): stop() , suspend() , resume() .(Anmerkung: Spater wird eine sichere Realisierung des Unterbrechens vonThreads uber interrupt() dargestellt.)

// Set a thread t to lower than normal priorityt.setPriority(Thread.NORM_PRIORITY-1);

// Set a thread to lower priority than the current threadt.setPriority(Thread.currentThread().getPriority()-1);

// Threads that don’t pause for I/O should explicitely yield the CPU// to give other threads with the same priority a chance to run.Thread t = new Thread(new Runnable() {

public void run() {for(int i = 0; i < data.length; i++) { // Loop through a bunch of data

process(data[i]); // Process itif (i % 10 == 0) // But after every 10 iterations

Thread.yield(); // Let other threads run.}

}});

13.2.3 Einfaches Beispiel: ‘ThreadDemo’

class ErsterThread extends Thread {public void run () {

for (int i = 0; i < 10; i++)

196 Informatik B • SS 02

try {Thread.sleep( Math.round (1000 * Math.random ()) );System.out.println (this + " " + i);

}catch (InterruptedException e) {

System.err.println (e);}

}}

class ZweiterThread implements Runnable {public void run () {

for (int i = 0; i < 10; i++)try {

Thread.sleep (Math.round (1000 * Math.random ()));System.out.println (Thread.currentThread().toString () + " " + i);

}catch (InterruptedException e) {

System.err.println (e);} } }

public class ThreadDemo {static public void main (String args[]) {

ErsterThread thread1 = new ErsterThread ();thread1.start ();Thread thread2 = new Thread(new ZweiterThread ());thread2.start ();try {

thread1.join ();thread2.join ();

}catch (InterruptedException e) {

System.err.println (e);} } }

Thread[Thread-5,5,main] 0Thread[Thread-5,5,main] 1Thread[Thread-4,5,main] 0Thread[Thread-5,5,main] 2Thread[Thread-5,5,main] 3Thread[Thread-4,5,main] 1Thread[Thread-5,5,main] 4Thread[Thread-4,5,main] 2Thread[Thread-5,5,main] 5Thread[Thread-4,5,main] 3Thread[Thread-5,5,main] 6Thread[Thread-4,5,main] 4Thread[Thread-5,5,main] 7Thread[Thread-5,5,main] 8Thread[Thread-5,5,main] 9

Informatik B • SS 02 197

Zeit

thread2

thread1

main

start thread1

start thread2

join thread2

join thread1

Abbildung 52: Zusammenspiel von Threads inThreadDemo

Thread[Thread-4,5,main] 5Thread[Thread-4,5,main] 6Thread[Thread-4,5,main] 7Thread[Thread-4,5,main] 8Thread[Thread-4,5,main] 9

13.2.4 Erlauterungen zu ‘ThreadDemo’

• Klasse Thread implementiert Runnable . Dort ist eine Methode run()spezifiziert. Mit der Methode start() wird ein Thread gestartet, indem run()aufgerufen wird. Methode join() wartet auf Beendigung des Thread.

• ErsterThread ist Unterklasse von Thread . Die run -Methode von Threadwird uberschrieben.

• sleep() legt einen Thread fur eine spezifizierte Zeit (in Millisekunden)schlafen. Hier wird zufallig eine Zeit zwischen 0 und 1000 ms gewartet und dannder Wert des Schleifenzahlers ausgegeben.Mit toString() wird die Information des aktuellen Thread-Objektszuruckgeliefert: sein Name, seine Prioritat (zwischen 1 und 10), und seinerzeugender Thread.

• ZweiterThread implementiert Runnable . Hier muss explizit eine Instanz vonThread erzeugt werden.

• Die Instanz von ZweiterThread wird einem Thread -Objekt ubergeben, derdie run() -Methode “betreibt”.

• ErsterThread kann sich selber schlafen legen. ZweiterThread legt diebenutzte Instanz von Thread schlafen.

• Bei Programmstart existiert immer automatisch ein erster Thread, dessenAusfuhrung in der main() -Methode beginnt. Dieser main-Thread startet nunzwei weitere Threads (fork) und wartet (join() ) auf das Ende dieser Threads.

• Bei jedem Ablauf ergibt sich nicht-deterministisch eine andere Reihenfolge derAusgaben.

198 Informatik B • SS 02

fertigbereit laufend

wartend(blockiert)

vorhanden

vorhanden: mit new als Instanz erzeugt.

bereit: ablaufbereit, aber die Ablaufsteuerung hat alle CPUs an andere Threads vergeben.

laufend: hat eine CPU des Systems.

wartend: es fehlen Betriebsmittel (z. B. File ist nicht zum Lesen/Schreiben freigegeben),sleep()oder Warten auf Signal eines anderen Threads.

fertig: Ende derrun() -Methode erreicht.

(Anmerkung: Diese Abbildung wird spater fur Monitore verfeinert.)

Abbildung 53: Zustande von Threads

13.2.5 Zustande von Threads

Threads haben verschiedene Zustande, die sie zum Teil selbst beeinflussen konnen,die aber auch von ihrer Umgebung manipulierbar sind (siehe Abb. 53).

13.3 Kooperierende und Konkurrierende Prozesse

13.3.1 Kooperierende Prozesse

• Nebenlaufige Prozesse, die Koordination erfordern, heissen voneinanderabhangig. Grundlegende Kommunikationsformen:

– Erzeuger/Verbraucher Muster (producer/consumer): Ein Prozess nimmtDaten auf, die ein anderer erzeugt hat.Beispiel: Buchungssystem im Supermarkt

– Auftraggeber/Auftragnehmer Muster (client/server)Beispiel: Verkehrsleitzentrale.

Beispiel: Buchungssystem im Supermarkt

• Strichcode-Leser, Buchungsprozessor, Drucker

• Jedem Gerat wird ein Prozess zugeordnet (wichtigesProgramm-Strukturierungs-Prinzip)

• Leseprozess erfasst uber Strichcodeleser die Kennung des Artikels

• Information wird an Buchungsprozess weitergegeben, der Bezeichung und Preisdes Artikels feststellt

Informatik B • SS 02 199

Produzent

Konsument

Auftraggeber

Auftragnehmer

1 2

Abbildung 54: Arten der Kooperation

Lesen Buchen Drucken

...

Butter 2 1,29Kaffee 1 7,99

Abbildung 55: Beispiel: Buchungssystem im Supermarkt

• Werte werden an Druckprozess weitergegeben, der sie auf Drucker ausgibt.

• Prozesse sind nebenlaufig: Wahrend der Buchungsprozess alte Eingabedatenverarbeitet, kann der Leseprozess neue Daten lesen.

• Prozesse sind abhangig: Buchungsprozess kann erst arbeiten, wenn er Datenvom Leseprozess erhalten hat.

Beispiel: Verkehrsleitzentrale

• gibt Auskunft uber aktuellen Straßenzustand und schlagt Fahrstrecken vor.

• Prozess im Bordcomputer (Client) stellt Anfrage an Auskunftsprozess in derZentrale (Server).

• Auskunftsprozess gibt die Information erst, wenn nach ihr gefragt wird.

• Prozess im Bordcomputer wartet, bis er die gewunschte Information erhalt.

• Prozesse sind wechselseitig abhangig.

13.3.2 Konkurrierende Prozesse

• Abhangigkeit nebenlaufiger Prozesse kann auch as Konkurrenz der Prozesse(um gemeinsame Ressourcen) resultieren.Die Aktivitat eines Prozesses behindert einen anderen Prozess.

• Beispiel: Eingleisige Teilstrecke im Eisenbahnverkehr

200 Informatik B • SS 02

• Beispiel: Drucker im Mehrbenutzersystem

Schreib-/Schreib-Konflikt: Beispiel

concx = x + 1 || x = x + 1

end conc;

kann zu ein- oder zweimaliger Inkrementierung von x fuhren.Folgende Verzahnung fuhrt zur einmaligen Inkrementierung:(Notation in Pseudo-Assembler mit Pi als Prozesse und ri als Register)

P1 P2 x r1 r2i ? ?

LOAD x, r1 i i ?LOAD x, r2 i i i

INCR r1 i i+1 iINCR r2 i i+1 i+1

STORE r1,x i+1 i+1 i+1STORE r2,x i+1 i+1 i+1

(“STORE r1,x direkt nach “INCR r1” resultiert in zweimaliger Inkrementierung.)

Schreib-/Lese-Konflikt: Beispiel

boolean art; // false = bar, true = scheckint schecks;int gesamt;

void einnahme(art zahlungsart, int betrag) {if (zahlungsart) schecks = schecks + betrag;gesamt = gesamt + betrag;

}

void kassensturz () {System.out.println("Einnahmen: " + gesamt);if (gesamt > 0)

System.out.println("Davon prozentual als Scheckzahlung: " +100 * schecks/gesamt);

}

Gegebener Kontostand sei 100,- Euro. Wenn einnahme(1, 200) undkassensturz() nebenlaufig abgearbeitet werden, kann es zu inkonsistentenInformationen kommen:

P1 P2 gesamt scheck Output100 0

schecks+200 100 200kassensturz 100 200 200%

gesamt+200 300 200

Informatik B • SS 02 201

13.4 Synchronisation

• Die gezielte Sequentialisierung nebenlaufiger Prozesse heisst Synchronisation.

• Synchronisierte Prozesse mussen Information austauschen, alsokommunizieren.

• Kommunikation kann realisiert werden durch:(1) gemeinsamen Datenbereich, auf den mehrere Prozesse zugreifen konnen.(2) Operationen, die Daten vom Datenbereich eines Prozesses in den desanderen transportieren.

• Anstelle ganzer Prozesse konnen auch kritische Abschnitte (Anweisungsblocke)synchronisiert werden.

Arten von Synchronisation:(A1 und A2 seien verschiedenen Prozessen zugeordnete Aktivitaten)

• Kausale Abhangigkeit (Produzent/Konsument): A1 → A2

Transitiver Abschluss (partielle Ordnung der Aktivitaten A1 . . . An)Einseitige Synchronisation (blockiert wird hochstens A2) erzwingt Reihenfolge.(vgl. Supermarkt-Buchungssystem)

• Ausschluss der Nebenlaufigkeit (Schreib-/Schreib- und Schreib-/Lese-Konflikte):A1 ↔ A2

Symmetrie von “nicht zusammen mit”Mehrseitige Synchronisation: Bei gleicher Prioritat ist keine Reihenfolgefestgelegt.(vgl. eingleisiges Eisenbahnstuck)

13.5 Monitore in Java

13.5.1 Synchronized

• Wird mehr als ein Thread verwendet, so tritt haufig Synchronisations-Bedarf auf.

• Zugriff auf kritische Daten muss kontrolliert werden.

• Hierzu wird ein Monitor-Objekt eingesetzt, das den Zugang von Threads zuuden Daten steuert. (Jedes beliebige Objekt kann als Monitor verwendet werden.)

• In Java wird synchronized verwendet, um einen kritischen Bereich zudefinieren und diesem Bereich ein Monitor-Objekt zuzuordnen.

• synchronized(monitor) fur Blocke (kritische Abschnitte)

• Wenn sich ein synchronized(this) -Block auf eine komplette Methodebezieht, kann alternativ der Modifikator synchronized fur diese Methodeangegeben werden.

• Der Modifikator synchronized kann auch fur Klassen-Methoden angegebenwerden. Hier wird das Klassen-Objekt zum Monitor.

202 Informatik B • SS 02

Monitor

Zugang zum Monitor

anderen Threads

geschützte Daten

blockiert für alle

Abbildung 56: Monitor

• Kommunikation bei Monitoren:

– wait() (Warte und gib den Monitor frei),

– notify() (Benachrichtige einen auf den Monitor wartenden Thread) und

– notifyAll() (Benachrichtige alle auf den Monitor wartenden Threads).

• Diese Methoden gehoren nicht zur Klasse Thread , sondern zu einemMonitor-Objekt.

synchronized void einnahme(art zahlungsart, int betrag) {if (zahlungsart) schecks = schecks + betrag;gesamt = gesamt + betrag;

}

synchronized void kassensturz () {System.out.println("Einnahmen: " + gesamt);if (gesamt > 0)

System.out.println("Davon prozentual als Scheckzahlung: " +100 * schecks/gesamt);

}

// This method swaps two array elements in a synchronized blockpublic static void swap(Object[] array, int index1, int index2) {

synchronized(array) {Object tmp = array[index1];array[index1] = array[index2];array[index2] = tmp;

}}

Informatik B • SS 02 203

bereit laufendvorhanden

blockiert

wait()

fertig

wartend

Monitor durch anderen Thread besetzt

notify()

Threads

zum Monitorwenn Zutritt

eines anderen

Abbildung 57: Zustande von Threads (bzgl. Monitor-Objekt)

13.5.2 Funktion von ‘synchronized’

• Wenn in einer Klasse eine Methode mit dem Modifikator synchronizedangegeben ist – also this als Monitor definiert wird – so verwendenverschiedene Aufrufe bei verschiedenen Instanzen dieser Klasse verschiedeneMonitore.

• Monitore konnen “Wettrennen” (race-conditions) zwischen Threads verhindern.

• Zu jedem Zeitpunkt kann nur eine der synchronized() -Aktivitaten furdasselbe Monitor-Objekt aufgerufen werden.

• Beispiel Produzent/Konsument bzw. Schreib-/Lese-Konflikt: Falls derjenigeThread, der die Daten ausliest, unterbrochen wird und ein zweiter Thread mitSchreibzugriffen aktiv wird, so muss der zweite Thread warten, bis der ersteThread (Leser) den Monitor verlassen hat.

• Java-Monitore sind “re-entrant”: Ein Thread, der im Monitor ist, wird nicht durchsich selbst dadurch blockiert, dass er eine andere auf denselben Monitorsynchronisierte Methode aufruft.

13.5.3 Warten auf Ereignisse mit Monitoren

• Beispiel (Produzent/Konsument): Thread wartet auf Daten, die von einemanderen Thread geliefert werden mussen.

• Aktives Warten blockiert CPU unnotig: Schleife, die standig eine Variableabfragt.

• Alternativ: wait() ↪→ Thread verbraucht keine CPU-Zeit, verlasst den Monitorund “schlaft”. Ein mit notify() bzw. notifyAll() aufgeweckter Threadwartet wieder auf Zugang zum Monitor (ist blockiert, solange bis Monitorfreigegeben ist).

• wait() versussleep()

204 Informatik B • SS 02

– sleep() ist eine Thread-Methode wahrend wait() eine Monitor-Methodeist.

– Wenn ein Thread im Besitz des Monitors sich schlafen legt, so bleibt er inBesitz des Monitors.Ein wartender Thread gibt dagegen den Monitor ab.

– Wenn ein wartender Thread aufwacht, kann es sein, dass er nichtausgefuhrt werden kann, weil er den Monitor nicht (sofort) wieder belegenkann.

– Ein wartender Thread kann fur immer warten, wenn nie ein notify erfolgt.

– Sowohl wait() als auch sleep() konnen durch interrupt()unterbrochen werden. (Einbettung in

try{ ... } catch (InterruptedException e) { ... } )

13.6 Beispiel: Produzent/Konsument

public class ConsumerProducer {

public static void main (String[] args) {Object[] d = { null };Producer p = new Producer(d, 0);Producer p2 = new Producer(d, 100);Consumer c = new Consumer(d);p.start();p2.start();c.start();try {

p.join();p2.join();c.join();

} catch (InterruptedException e) { System.err.println(e); }}

public static class Producer extends Thread {

protected Object[] data;protected int count;protected int offset;

public Producer (Object[] d, int o) {data = d;offset = o;

}

public void run () {

Informatik B • SS 02 205

Integer d;while (count < 8) {

d = new Integer (count++ + offset);while (!store(d));report(d);

} }

protected boolean store (Object d) {if (data[0] == null) {

try { sleep(500);} catch (InterruptedException e) { System.err.println(e); }data[0] = d;return true;

} else return false;}

protected void report(Object d) {System.out.println(this + " produced " + d);

}} // end Producer

public static class Consumer extends Thread {

protected Object[] data;protected int count;

public Consumer (Object[] d) {data = d;

}

public void run () {while (count < 16) {

Object d;d = fetch();if (d != null) {

report(d);emptyStore();count++;

}} }

protected Object fetch() {return data[0];

}

protected void report(Object d) {System.out.println(this + " consumed " + d);

206 Informatik B • SS 02

}

protected void emptyStore() {data[0] = null;

}} // end Consumer

}

• Anmerkung: Producer und Consumer sind als nested top-level Klassen inderselben Datei wie ConsumerProducer .

• Producer und Consumer sind Unterklassen von Thread , die run -Methodenwerden also nebenlaufig ausgefuhrt.

• Der Consumer soll ein Objekt abholen, der Producer soll ein Objekt ablegen.

• Problem: Mehrere Threads wollen lesend bzw. schreibend auf data zugreifen.Klassischer Schreib-Lese-Konflikt!

• synchronized fur die run() -Methoden macht keinen Sinn: this wurde alsMonitor verwendet, und jeder Thread hatte damit seinen eigenen Monitor!

• Synchronisationsblocke in den jeweiligen run-Methoden mit data als Monitorverhindern zwar gleichzeitigen Zugriff, bergen aber die Gefahr von deadlocks.

• Losung: Conditional Critical Region (siehe Kapitel “Semaphoren undDeadlocks”).

Informatik B • SS 02 207

14 Multi-Threading: Semaphoren und Deadlocks

14.1 Semaphoren

14.1.1 Konzept

• Von Dijkstra zur Synchronisation nebenlaufiger Prozesse eingefuhrt.

• Begriff aus der Seefahrt: Optisches Signal zum Passeeren/passer (Passieren)und Vrijgeven/verlaat (Freigeben).

• Idee: Prozess wird im Synchronisationsfall blockiert und in Warteschlangeeingeordnet.

• Semaphoren sind abstrakte Datentypen:

– Objekte bestehen aus Zahler und Warteschlange.

– Operation P: Zahler wird um eins erniedrigt. Wenn negativer Wert, dann istProzess blockiert. (Warten auf das Eintreten einer Bedingung)

– Operation V: Zahler wird um eins erhoht. (Signalisieren des Eintretenseiner Bedingung).

• Die Warteschlange muss in Java nicht explizit definiert werden. Sie existiertimplizit als Menge der blockierten Prozesse. Durch notify() wird ein Prozessaktiviert (nicht unbedingt der, der am langsten wartet).

14.1.2 Klasse ‘Semaphore’

/** A class for the classical semaphore -- A.T. Schreiner */public class Semaphore {

/** the value, nonnegative.*/

protected int n;/** set initial value.

*/public Semaphore (int n) { this.n = n; }/** passer: decrement; may block until decrementing is possible.

*/public synchronized void P () {

while (n <= 0)try {

wait(); // blockiert} catch (InterruptedException e) { }

-- n;}/** verlaat: increment; inform if necessary.

*/public synchronized void V () {

if (++ n > 0)

208 Informatik B • SS 02

notify(); // nur _ein_ wartender Prozess wird aus Blockierung entlassen}

}

14.1.3 Einseitige und Mehrseitige Synchronisation

Einseitige Synchronisation

• Jeder Synchronisationsbedingung wird eine Semaphorvariable zugeordnet.

• P -Operation in einem Prozess wartet auf V -Operation in einem anderenProzess.

Semaphore s = new Semaphore(0);void process1 () { void process2 () {// ... // ...s.V(); // Ereignis signalisieren s.P(); // Ereignis abwarten// ... // ...} }

Mehrseitige Synchronisation

• Kritischer Abschnitt (critical region): Bereich, zu dem nur eine Aktivitat zu einerZeit Zugang hat.

• Initialwert des Semaphorzahlers legt die maximale Anzahl von Prozessen fest,die den kritischen Abschnitt betreten durfen.

• P und V umschliessen kritischen Abschnitt.

Semaphore s = new Semaphore(1);void process1 () { void process2 () {// ... // ...s.P(); s.P();// ... kritischer Abschnitt // ... kritischer Abschnitts.V(); s.V();// ... // ...} }

14.1.4 Erzeuger-/Verbraucher-Problem mit Semaphoren

/** semaphore demonstration with member class pattern.*/

public class ProdConsDemo {/** controls access to data.

*/protected Semaphore available = new Semaphore(0);/** signals that data has been copied.

*/protected Semaphore copied = new Semaphore(1);

Informatik B • SS 02 209

/** "global" buffer.*/

protected String data;/** producer: has command line copied by several threads in consumer.

*/public static void main (String[] args) {

if (args != null) {int nt = args.length+1 >> 1; // divide by 2ProdConsDemo producer = new ProdConsDemo(); // owns semaphoresfor (int n = 0; n < nt; ++ n)

producer.new Consumer(""+n).start(); // performs copy// int as String

producer.produce (args);producer.terminateConsumers (nt);

}}

/** producing some data*/

protected void produce (String[] args) {for (int n = 0; n < args.length; ++ n) {

copied.P(); // critical sectiondata = args[n]; // writes informationavailable.V();

}}

/** terminate consumer threads*/

protected void terminateConsumers (int nt) {for (int n = 0; n < nt; ++ n) { // done: inform all

copied.P();data = null; // termination markeravailable.V();

}}

/** consumer thread: copies data to standard output until data == null.*/

protected class Consumer extends Thread {/** save name.

*/public Consumer (String name) { super(name); }/** performs copy.

*/public void run () {

String copy;do {

210 Informatik B • SS 02

available.P(); copy = data; copied.V(); // critical sectionif (copy != null)

System.out.println(getName()+" "+copy);} while (copy != null);

}}

}

$ java ProdConsDemo a b c d e f g h i j1 b1 c0 a0 e0 f0 g0 h0 i0 j1 d

Erlauterungen:

• Das Produzent/Konsument Muster ist hier mit Member-Klasse realisiert: Immain -Thread wird produziert (ein Produzent). Es werden halb sovieleConsumer-Threads generiert, wie Argumente uber die Eingabezeile angegebenwerden.

• Uber das Feld data werden String-Objekte ausgetauscht.

• Zwei Semaphoren: copied schutzt Schreibzugriff auf data ; availableschutzt Lesezugriff.

14.2 Conditional Critical Regions

• Konzept von Hoare, allgemeiner als Semaphoren.

• Es existiert ein kritischer Abschnitt, wobei der Zugang durch eine Bedingunggeschutzt wird.

• Typischerweise mit while -Schleife realisiert.Wurde man if anstelle von while verwenden, so wurden aufgeweckteThreads nicht merken, dass ein anderer Thread die condition verandert hat.(Wahrend man schlaft konnen andere arbeiten.)

Typisches Muster:

synchronized(o) { synchronized(o) {while (!condition ) { // condition == false

// ... // tu was

Informatik B • SS 02 211

o.wait(); condition = true;// ... o.notifyAll();

} }// tu was// evtl. condition = false

}

14.2.1 Monitore, CCRs, Semaphoren

• Monitor: Ein Java-Objekt, das den Zugang zu synchronisierten(Instanz)-Methoden/Blocken kontrolliert.

• Conditional Critical Region: kritischer Abschnitt (in einem synchronisiertenBlock), bei dem auf Zugang gewartet wird (wait() ), solange bis eineBedingung erfullt ist. Ein anderer Block macht die Bedingung wahr und gibt denkritischen Abschnitt frei (notify() , notifyAll() ).

• Semaphoren: Sperren und Freigeben, realisiert durch Zahler undWarteschlange. Spezielle Technik, um CCRs zu realisieren.

14.3 Deadlocks

• Eine Situation in der zwei oder mehr Prozesse/Threads nicht weiterarbeitenkonnen, weil jeder darauf wartet, dass mindestens ein anderer etwasbestimmtes erledigt, heisst Deadlock.

• Standardbeispiel: Dining PhilosophersFunf Philosophen sitzen um einen runden Tisch. Vor jedem Philosoph steht einTeller, zwischen jedem Teller-Paar liegt eine Gabel. Es existieren also funfGabeln, aber um zu essen braucht jeder Philosoph zwei Gabeln (die zu seinerrechten und zu seiner linken Seite).↪→Wenn alle funf Philosophen zur Gabel zu ihrer Rechten greifen, entsteht einDeadlock!

• Zweites Problem: Aushungern eines Philosophen (die anderen sind immerschneller beim Zugreifen). Kann mit Semaphoren oder kritischen Abschnittenalleine nicht verhindert werden. Java erlaubt immer einem beliebigen Thread,dass er zum Zug kommt.

14.3.1 Losung mit Semaphoren

Nicht verklemmungsfrei:

// Anzahl von Gabeln ist 5.// Jede Gabel sei eine Semaphore, die mit 1 initialisiert wird.//// F ur einen Philosophen i:

212 Informatik B • SS 02

Abbildung 58: Dining Philosophers

Informatik B • SS 02 213

while(true) {think();gabel[i].P();gabel[(i+1)%anzahl].P(); // wg. i+1 gr oßer 4eat();gabel[i].V();gabel[(i+1)%anzahl].V();

}

• Verklemmungsfreie Losung mit Semaphoren?Eine globale Semaphore “table ”, die jeweils nur einem Philosoph erlaubt, zuprufen, ob seine linke und rechte Gabel frei sind und diese dann aufzunehmen.

Deadlocks konnen auftreten, wenn

• Exklusive Belegung: Betriebsmittel sind entweder von genau einem Prozessbelegt oder frei. (eine Gabel)

• Belegen und Warten: Prozesse belegen Betriebsmittel und warten wahrend derBelegung auf die Zuteilung weiterer Betriebsmittel. (linke und rechte Gabel)

• Kein zwangsweises Freigeben: Betriebsmittel konnen nicht entzogen werden,sondern mussen vom Prozess zuruckgegeben werden (Hinlegen einer Gabel)

• Zyklische Wartebedingung: Es muss einen Ring aus zwei oder mehr Prozessenbestehen, bei der jeder Prozess auf ein von einem anderen Prozess aus derKette belegtes Betriebsmittel wartet. (5 Philosophen)

14.3.2 Dining Philosophers – Losung mit globaler Kontrolle

(nach Jobst, Programmieren in Java, Hanser)

• Conditional Critical Region Konzept: takeForks() und putForks()

• Aushungern theoretisch moglich.

• Erweiterung: Anderung von Prioritaten, z.B. “hungrig” und “satt” als Eigenschaftder Philosophen (Threads). Fairness!

// Der Manager handelt nach der Philosophie: gib nur dann Gabeln an einen// Philosophen, wenn ALLE benoetigten Gabeln frei sind. Damit werden// Deadlocks vermieden (vgl. Literaturangaben)//public class Manager {

public final static int N = 5; // fuenf Philosophenprivate static int phils[] = new int [N]; // Zustaende der Philosophenprivate final static int NOTHING = 0;private final static int EATING = 1;

private int left (int i) { return (i-1+N) % N; } // Linker Nachbar

214 Informatik B • SS 02

private int right (int i) { return (i+1) % N; } // Rechter Nachbar

synchronized public void takeForks (int no) {while (phils[left(no)] == EATING || // Wenn nur einer der Nachbarn isst:

phils[right(no)] == EATING) { // Warte bis fertig.try {

wait ();} catch (InterruptedException e) { System.err.println(e); }

}phils[no] = EATING;

}

synchronized public void putForks (int no) {phils[no] = NOTHING; // Markiere freinotifyAll (); // Nachricht an Wartende

}

synchronized public void display () {StringBuffer s = new StringBuffer("Philosophen : ");for (int i = 0; i < N; i++)

if (phils[i] == EATING)s.append(" " + i);

System.out.println (s);}

public static void main (String[] args) {Manager m = new Manager (); // Manager zuerst installierenThread p[] = new Thread [N];for (int i = 0; i < p.length; i++)

p[i] = new Philosopher (i, m);for (int i = 0; i < p.length; i++)

p[i].start ();for (int i = 0; i < p.length; i++) {

try {p[i].join ();

} catch (InterruptedException e) {System.err.println (e);

}}

}}

class Philosopher extends Thread {protected int no; // Die (unpersoenliche) Nummer des Philosophenprotected Manager m; // Referenz zum Manager

public Philosopher (int no, Manager m) {super ("Phil. " + no);

Informatik B • SS 02 215

this.no = no;this.m = m;

}

protected void eat () {m.display ();try {

sleep (Math.round (1000 * Math.random ()));}catch (InterruptedException e) {}

}

protected void think () {try {

sleep (Math.round (1000 * Math.random ()));} catch (InterruptedException e) {}

}

public void run () {for (int j = 0; j < 5; j++) {

think (); // Denken ....m.takeForks (no); // Auf Zugang warteneat (); // Essenm.putForks (no); // Zugang fuer die Kollegen ermoeglichen

}}

}

Zu einem Zeitpunkt konnen hochstens zwei, nicht nebeneinander sitzendePhilosophen essen:

Philosophen : 4Philosophen : 3Philosophen : 0 3Philosophen : 1 3Philosophen : 1 3Philosophen : 0 3Philosophen : 0 2Philosophen : 1 4Philosophen : 1 4Philosophen : 2 4Philosophen : 0 2Philosophen : 0 3Philosophen : 4Philosophen : 1 4Philosophen : 2 4Philosophen : 0 2Philosophen : 2 4

216 Informatik B • SS 02

Philosophen : 1 4Philosophen : 0 3Philosophen : 0 3Philosophen : 2Philosophen : 2 4Philosophen : 1 3Philosophen : 1 3Philosophen : 2

14.3.3 Dining Philosophers – Bedingter Zugriff auf Gabel

// Philosopher A.T. Schreinerimport java.util.Random;/** the Dining Philosophers.

*/public class Philosopher2 extends Thread {

/** the fork between two philosophers.*/

protected static class Fork {protected int me; // number for traceprotected boolean inUse; // true if fork is in usepublic Fork (int me) {

this.me = me;}/** returns true if fork is obtained, false if not.

*/public synchronized boolean get (int who) {

System.err.println(who+(inUse ? " misses " : " grabs ")+me);return inUse ? false : (inUse = true);

}/** drops the fork.

*/public synchronized void put (int who) {

System.err.println(who+" drops "+me);inUse = false; notify();

}/** returns once fork is obtained.

*/public synchronized void waitFor (int who) {

while (! get(who))try {

wait();} catch (InterruptedException e) { e.printStackTrace(); }

}}/** make one diner.

*/public Philosopher2 (int me, Fork left, Fork right) {

Informatik B • SS 02 217

this.me = me; this.left = left; this.right = right;}protected static Random random = new Random(); // randomizeprotected int me; // number for traceprotected Fork left, right; // my forks/** philosopher’s body: think and eat 5 times.

*/public void run () {

for (int n = 1; n <= 5; ++ n) {System.out.println(me+" thinks");try {

Thread.sleep((long)(random.nextFloat()*1000));} catch (InterruptedException e) { e.printStackTrace(); }for (;;)

try {left.waitFor(me);if (right.get(me)) {

System.out.println(me+" eats");try {

Thread.sleep((long)(random.nextFloat()*1000));} catch (InterruptedException e) { e.printStackTrace(); }right.put(me);break;

}} finally {

left.put(me);}

}System.out.println(me+" leaves");

}/** sets up for 5 philosophers.

*/public static void main (String args []) {

Fork f[] = new Fork[5];for (int n = 0; n < 5; ++ n) f[n] = new Fork(n);Philosopher2 p[] = new Philosopher2[5];p[0] = new Philosopher2(0, f[4], f[0]);for (int n = 1; n < 5; ++ n) p[n] = new Philosopher2(n, f[n-1], f[n]);for (int n = 0; n < 5; ++ n) p[n].start();

}}

Losung fuhrt zum Aushungern von 2 durch 1 und 3!!!

0 thinks1 thinks2 thinks3 thinks4 thinks

218 Informatik B • SS 02

1 grabs 01 grabs 11 eats3 grabs 23 grabs 33 eats1 drops 11 drops 01 thinks2 grabs 12 misses 22 drops 12 grabs 12 misses 22 drops 12 grabs 1...

14.3.4 Deadlocks durch falsche Anordnung

// When two threads try to lock two objects, deadlock can occur unless// they always request the locks in the same order.final Object resource1 = new Object(); // Here are two objects to lockfinal Object resource2 = new Object();Thread t1 = new Thread(new Runnable() { // Locks resource1 then resource2

public void run() {synchronized(resource1) {

synchronized(resource2) { compute(); }}

}});Thread t2 = new Thread(new Runnable() { // Locks resource2 then resource1

public void run() {synchronized(resource2) {

synchronized(resource1) { compute(); }}

}});

t1.start(); // Locks resource1t2.start(); // Locks resource2 and now neither thread can progress!

14.4 Threads: Erganzungen

• Threads konnen durch setDaemon(true) zu Damon-Threads gemachtwerden: Der Interpreter wird beendet, wenn alle Nicht-Damon-Threads beendetsind.

Informatik B • SS 02 219

• Threads konnen Thread-Gruppen zugeordnet werden und dann gemeinsambehandelt werden. Ohne explizite Angabe einer Gruppe gehort ein Thread zurGruppe ‘System’.

• Vordefinierte Klassen, die Collection , Set , List oder Map implementieren,haben in der Regel keine synchronized() -Methoden (z.B. ArrayList ). Eskonnen synchronisierte Wrapper-Objekte erzeugt werden:

List synclist = Collections.synchronizedList(list);Map syncmap = Collections.synchronizedMap(map);

• Ordentliches Unterbrechen eines Threads durch interrupt() .wait() und sleep() erlauben einen Interrupt, also kann ein Thread nicht“mitten beim Arbeiten” angehalten werden.

class T extends Thread {public void run() {

while(true) { // This thread runs until asked to stopprocess(); // Do somethingtry { Thread.sleep(1000); } // Wait 1000 millisecscatch (InterruptedException e) { // Handle the interrupt

return;}

}}

public stopThread() {interrupt();

}}

14.5 Pipe-Strome

• Pipes werden benutzt, um von einem Thread erzeugte Daten einem anderenThread zur Verfugung zu stellen.

• Klassen PipedReader /PipedWriter (Character-Stream) bzw.PipedInputStream /PipedOutputStream

• Beispiel: Klasse, die verschiedene String-Manipulationen durchfuhrt (Sortieren,Umkehren von Text).Ermittlung von reimenden Worten: Jedes Wort einer Liste umdrehen, sortieren,wieder umdrehen.

• Ohne Pipe-Strome mussen die Operationen Umdrehen, Sortieren, Umdrehensequentiell abgearbeitet werden, da jedes Zwischenergebnis explizit, z. B. ineiner Datei, gespeichert werden muss.

• Mit Pipe-Stromen kann der Output einer Operation direkt an die nachfolgendeOperation ubergeben werden.

220 Informatik B • SS 02

Reverse Sort

Reverse Sort

Reverse

Reverse

List of reversedwords

List of words List of reversedsorted words

List of rhymingwords

List of words List of rhymingwords

Abbildung 59: Kommunikation ohne/mit PipeStreams

• In der main-Methode wird ein Reader-Objekt erzeugt. Die Ermittlung derreimenden Worte wird uber den verschachtelten Methodenaufrufreverse(sort(reverse(words))) realisiert.

• Die Methoden reverse() und sort() arbeiten mit Threads undkommunizieren uber Pipe-Strome (siehe Abb. 60):

– Ein PipeReader wird “auf” einem PipeWriter erzeugt: Was auf denPipeWriter geschrieben wird, kann vom PipeReader gelesen werden!

– Dazu gibt es einen BufferedReader, der die Eingabe (aus einer Quelle, z.B.der Pipe) erhalt, und einen PrintWriter, der die Ausgabe in eine Sink (z.B.Pipe) schreibt.

• Anmerkung: Im Prinzip kann mit Pipes nebenlaufig gearbeitet werden. Z.B. kannein Thread bereits konsumieren (lesen und verarbeiten), wahrend ein anderernoch produziert. Die Methode sort() kann jedoch erst arbeiten, wenn alleWorte von reverse() umgedreht wurden. Ein Beispiel fur “parallele”Verarbeitung mit Pipe-Stromen ist im begleitenden Code zur Vorlesungangegeben (SuffixExtract.java ).

import java.io.*;

Informatik B • SS 02 221

Abbildung 60: Direkte Kommunikation mit PipeStream

public class RhymingWords {public static void main(String[] args) throws IOException {

FileReader words = new FileReader("words.txt");

// do the reversing and sortingReader rhymedWords = reverse(sort(reverse(words)));

// write new list to standard outBufferedReader in = new BufferedReader(rhymedWords);String input;

while ((input = in.readLine()) != null)System.out.println(input);

in.close();}

public static Reader reverse(Reader source) throws IOException {

BufferedReader in = new BufferedReader(source);

PipedWriter pipeOut = new PipedWriter();PipedReader pipeIn = new PipedReader(pipeOut);PrintWriter out = new PrintWriter(pipeOut);

new ReverseThread(out, in).start();

return pipeIn;}

public static Reader sort(Reader source) throws IOException {

BufferedReader in = new BufferedReader(source);

PipedWriter pipeOut = new PipedWriter();PipedReader pipeIn = new PipedReader(pipeOut);PrintWriter out = new PrintWriter(pipeOut);

new SortThread(out, in).start();

222 Informatik B • SS 02

return pipeIn;}

}

import java.io.*;

public class ReverseThread extends Thread {private PrintWriter out = null;private BufferedReader in = null;

public ReverseThread(PrintWriter out, BufferedReader in) {this.out = out;this.in = in;

}

public void run() {if (out != null && in != null) {

try {String input;while ((input = in.readLine()) != null) {

out.println(reverseIt(input));out.flush();

}out.close();

} catch (IOException e) {System.err.println("ReverseThread run: " + e);

}}

}

private String reverseIt(String source) {int i, len = source.length();StringBuffer dest = new StringBuffer(len);

for (i = (len - 1); i >= 0; i--)dest.append(source.charAt(i));

return dest.toString();}

}

import java.io.*;

public class SortThread extends Thread {private PrintWriter out = null;private BufferedReader in = null;

Informatik B • SS 02 223

public SortThread(PrintWriter out, BufferedReader in) {this.out = out;this.in = in;

}

public void run() {int MAXWORDS = 50;

if (out != null && in != null) {try {

String[] listOfWords = new String[MAXWORDS];int numwords = 0;

while ((listOfWords[numwords] = in.readLine()) != null)numwords++;

quicksort(listOfWords, 0, numwords-1);for (int i = 0; i < numwords; i++)

out.println(listOfWords[i]);out.close();

} catch (IOException e) {System.err.println("SortThread run: " + e);

}}

}

private static void quicksort(String[] a, int lo0, int hi0) {int lo = lo0;int hi = hi0;

if (lo >= hi)return;

String mid = a[(lo + hi) / 2];while (lo < hi) {

while (lo<hi && a[lo].compareTo(mid) < 0)lo++;

while (lo<hi && a[hi].compareTo(mid) > 0)hi--;

if (lo < hi) {String T = a[lo];a[lo] = a[hi];a[hi] = T;lo++;hi--;

}}if (hi < lo) {

int T = hi;

224 Informatik B • SS 02

hi = lo;lo = T;

}quicksort(a, lo0, lo);quicksort(a, lo == lo0 ? lo+1 : lo, hi0);

}}

Informatik B • SS 02 225

15 Regulare Ausdrucke und Pattern-Matching

Achtung: Dieses Kapitel wird nochuberarbeitet und erweitert!

15.1 String Pattern-Matching

• Zu den Klassen von Algorithmen, die jeder Informatiker kennen sollte, gehorenneben Such-, Sortier-, und Graphalgorithmen auch Pattern-MatchingAlgorithmen.

• Im folgenden werden die Grundlagen fur String Pattern-Matching eingefuhrt(siehe Baase & van Gelder, Kap. 11).

• Der Schwerpunkt liegt auf den Algorithmen, nicht auf der Java-Implementierung.Entsprechend werden die Algorithmen in Pseudo-Code angegeben,

15.1.1 Motivation

• Problem: Finden eines Teilstrings (Muster/Pattern) in einem anderen String(Text).

• Anwendungsbereiche: Textverarbeitung, Information-Retrieval, Suche uberVerzeichnisbaume, Bioinformatik, etc.

15.1.2 Straightforward Losung

• Algothmische Idee:

– Starte beim ersten Zeichen im Text und prufe, ob die Zeichenfolge desPatterns mit der anfanglichen Zeichenfolge im Text matched.

– Wenn ja: Erfolg,Wenn nein: Starte neu beim zweiten Zeichen im Text

• Nicht gerade effizient: Anzahl von Zeichen-Vergleichen ist O(m · n) fur m =Lange des Patterns und n = Lange des Texts!

P: ABABC ABABC ABABCvvvvv vvvvv vvvvv

T: ABABABCCA ABABABCCA ABABABCCA

15.1.3 String-Matching mit endlichen Automaten

• Idee: Reprasentation eines Patterns als endlichen Automaten (siehe Kapitel1.4.1 “Formale Sprachen”). Text als Input in den Automaten, Termination inEndzustand, wenn Pattern entdeckt.

226 Informatik B • SS 02

Tabelle 6: Einfaches String Pattern-Matchingint simpleScan(char[] P, char[] T, int m)

int match; // value to return

int i; // current guess where P begins in T

int j; // index of current char in T

int k; // index of current char in P

match = -1;

i = j = 1; k = 1;

while (!endText(T, j))

if (k > m)

match = i; // match found

break;

if (T[j] == P[k])

j++;

k++;

else

// Back up over matched chars

int backup = k-1;

j = j-backup;

k = k-backup;

// Slide pattern forward, start over

j++;

i = j;

// Continue loop

return match;

Informatik B • SS 02 227

1 2 3 4 *Start

B, C

A A B C

B, C

C

A

B

Abbildung 61: Endlicher Automat fur P = AABC

• Vorteil: Jeder Buchstabe im Text muss nur einmal angeschaut werden: O(n);allerdings gilt dieser Vorteil nur, wenn die automatische Konstruktion desendlichen Automaten aus dem Pattern effizient durchgefuhrt werden kann.

• In Abb. 61 ist ein endlicher Automat fur das Pattern “AAABC” angegeben. “*”markiert einen Endzustand, in allen anderen Zustanden wird das nachsteZeichen auf dem Band gelesen und der Schreib-Lese-Kopf um ein Zeichen nachrechts verschoben.

• Leider ist das Erstellen des endlichen Automaten (die entsprechendeUbergangstabelle) recht aufwendig.↪→ der Knuth-Morris-Pratt Algorithmus arbeitet mit einer einfacheren Variantezum endlichen Automat – einer sogenannten Verschiebetabelle, die in linearerZeit in der Pattern-Lange konstruiert werden kann!

15.1.4 Der Knuth-Morris-Pratt (KPM) Algorithmus

• KPM-Idee: Verschiebetabelle statt Ubergangstabelle

• Grundidee: Wenn in einem Text nach einem Pattern gesucht wird, und bereitsder Anfang des Patterns (Prafix) matched,

12345678P: ABABABCBT: ...ABABABx....

i=1

dann soll bei Miss-Match das Pattern so (nach rechts) uber dem Textverschoben werden, dass die nachstmogliche Position des Patterns im Textgefunden werden kann.Moglicher nachster Beginn des Patterns im Text ist das großte Prafix desPatterns, das mit einem Suffix (Endstuck) des bisher verarbeiteten Textsubereinstimmt:

228 Informatik B • SS 02

Tabelle 7: Konstruktion der Verschiebetabellevoid kmpSetup(char[] P, int m, int [] fail)

fail[1] = 0;

k = 0; // Position des Anfangsabschnitts

for (int q = 2; q≤m; q++)

while ((k > 0) && (P[k+1] ! = P[q])) k = fail[k];

if (P[k+1] == P[q]) k++;

fail[q] = k;

12345678P: ABABABCBT: ...ABABABx....

i=1

• Problem: Die Verschiebetablle soll nur bezuglich des Patterns, also unabhangigvon einem konkreten Text, konstruiert werden.Trick: Man weiss etwas uber den bisher verarbeiteten Text. Das bishergematchte Prafix des Patterns muss das Suffix des Texts sein!

• Berechnung der Rucksprunge:

i 12345678P ABABABCBfail 00123400

Rucksprung ist jeweils derjenige Indexplatz im Pattern, der das großte Prafix furdas bisher verarbeitete Pattern darstellt.

• Beispiel:

12345678910T: ...ABABABABCB...T[1] A ok P[1]T[2] B ok P[2]T[3] A ok P[3]T[4] B ok P[4]T[5] A ok P[5]T[6] B ok P[6]T[7] A missmatch --> gehe zu P[4] (nimm ABAB als gematched an)T[7] A ok P[5]T[8] B ok P[6]T[9] C ok P[7]T[10]B ok P[8] --> output 10-8 = 2

Erlauterung: Berechnung der Verschiebetabelle

Informatik B • SS 02 229

Tabelle 8: Der KPM-Algorithmusint kpmScan(char[] P, char[] T, int m, int [] fail)

int q = 0; // Zahl der Pos. in denen T und Pubereinstimmen

for (int i = 0; i ≤ n; i++)

while ((q> 0) && (P[q+1] ! = T[i])) q = fail[q];

if (P[q+1] = T[i]) q++;

IF (q == m) output (i-m)

Tabelle 9: Illustration

Konstruktion der Verschie-betabelle fur “ABABABCB”q k P[k+1] P[q] k’ fail[q]2 0 A B - 03 0 A A 1 14 1 B B 2 25 2 A A 3 36 3 B B 4 47 4 A C - 2

A A C - 00 A C - 0

8 0 A B - 0

KPM-Algorithmus: Pattern “ABA-BABCB” und Text “ABABABABCB”i q P[q+1] T[i] q’1 0 A A 12 1 B B 23 2 A A 34 3 B B 45 4 A A 56 5 B B 67 6 C A 4

4 A A 58 5 B B 69 6 C C 710 7 B B 8

output: 10-8

• Bestimmung der Verschiebungen: Ausgehend von fail[1] = 0 lassen sichdie weiteren Verschiebungen mithilfe der bereits errechneten bestimmen. Furdie Pattern-Position q > 1 ist k immer maximal gewahlt, so daß gilt:P [1 . . . k + 1] = P [q − k . . . q]. Daraus ergibt sich fail[q] = k + 1 .

• Aufwand: For-Schleife (Index q) geht uber Lange des Patterns m; Die k-Wertekonnen innerhalb der while-Schleife maximal den Wert q − 1 annehmen. Diemaximale Anzahl von Anderungen des k-Werts kann auf 2m abgeschatztwerden.Damit gilt fur die Berechnung der Verschiebetabelle O(m). Da derMatching-Algorithmus linear in der Lange des Textes n ist, ergibt sich einGesamtaufwand von O(n+m).

15.1.5 Pattern-Matching mit Regularen Ausdrucken

• Statt konstanter Strings will man haufig nach allgemeineren Muster suchen.

• Beispiele:

230 Informatik B • SS 02

– Finde alle Folgen aus drei Zeichen, die mit “T” beginnen und mit “r” enden:T.r(“.” matched jedes Zeichen ausser “newline”)

– Finde alle Worte, die mit “F” beginnen und mit “l” enden: F.*l(Der Kleene-Stern definiert eine Folge aus 0 bis n Zeichen derangegebenen Menge.)

– Finde Jahreszahlen zwischen 1970 und 1999 19[789][0-9](Eckige Klammern geben eine Zeichen-Klasse/Menge an. Mit x-y kannman Bereiche fur geordnete Zeichenmengen definieren.)

• Auch fur Pattern-Matching mit regularen Ausdrucken existieren Pattern-Matcher.Diese Matcher basieren typischerweise auf endlichen Automaten.

• Das grep -Kommando implementiert einen Matcher fur regulare Ausdrucke. DieProgrammiersprache Perl ist im wesentlichen ein Matcher fur regulareAusdrucke

• Naturlich konnen Matcher fur regulare Ausdrucke auch String-Pattern-Matching– konstante Strings sind spezielle regulare Ausdrucke.

15.2 Java 1.4 ‘regex’

• Vor Java 1.4: Pattern-Matching konnte mithilfe der StringTokenizer undcharAt() -Methoden nur sehr umstandlich realisiert werden. Neu:java.util.regex

• Flanagan nominiert regular expressions als Nummer 2 der Top-Ten Liste von“cool new features in Java 1.4”.

• Die Syntax fur regulare Ausdrucke in Java ist sehr ahnlich zu Perl.

15.2.1 Konstruktion regularer Ausdr ucke

• Neben den standardmassig zur Beschreibung regularer Ausdruckeverwendbaren Konstrukte werden einige Zusatzkonstrukte erlaubt, die eseinfacher machen regulare Ausdrucke aufzuschreiben.

• Im Tabelle 10 wird ein kurzer Uberblick gegeben (weitere Information ist in derDokumentation nachzulesen).

• Die Symbole fur special characters (wie $ ˆ . * + ) und die Syntax furZeichenklassen sind Standard fur die Notation von regularen Ausdrucken.Weitere Notationen, insbesondere die Moglichkeit von Kurznotationen furvordefinierte Zeichenklassen sind spezifisch fur Java bzw. Perl.

• Achtung bei greedy-Quantoren: a.*i wurde im String gadji beri binblassa glassala laula lonni cadorsu sassala bim bis zu demletzten ‘i’ in ‘bim’ matchen! (Zeile aus dem Gedicht ’Gadji beri bimba’ von HugoBall)

Informatik B • SS 02 231

• Achtung: Da das Pattern als Java-String angegeben wird, mussen Zeichen, diewortlich gematched werden sollen, mit zweifachem Backslash eingeleitetwerden, z. B. \\. .

15.2.2 Die Pattern-Klasse

• Die Pattern-Klasse reprasentiert einen regularen Ausdruck, der als Stringspezifiziert wurde.

• Mit der Klassenmethode Pattern.compile(string) wird das Pattern ineine effiziente interne Reprasentation umgewandelt.

Pattern p = Pattern.compile("[,\\s]+");erzeugt ein Pattern fur Trennung durch Komma oder Whitespace

• Weitere Methoden:

– split() : Teilt den gegebenen Input bezuuglich der Matches zum PatternString[] result = p.split("one two, three four , five ”);,

– matcher() : erzeugt einen Matcher, der gegebenen Input gegen dasPattern vergleicht

Matcher m = p.matcher("onetwothree four five six”);,

15.2.3 Die Matcher-Klasse

• Die Eingabe an einen Matcher muss dem Interface CharSequence genugen.Im obigen Beispiel wurde ein String -Objekt ubergeben. Beispielsweiseimplementieren String , StringBuffer und CharBuffer dieses Interface.

• Wichtige Methoden:

– matches() : Vergleicht den gesamten Input gegen das Pattern und lieferttrue, bei Ubereinstimmung, false sonst.

– find() : Scanned die eingegebene Zeichenfolge und sucht die nachsteTeilfolge, die mit dem Pattern ubereinstimmt.

– appendReplacement() , appendTail() : Sammeln des Ergebnisstringsin einem StringBuffer

– replaceAll() : liefert String, in dem jedes vorkommen des Patternsdurch alternatives Pattern ersetzt wird.

15.2.4 Beispiel: Suche und Ersetze

import java.util.regex.*;

public class Replacement {public static void main(String[] args)

throws Exception {

232 Informatik B • SS 02

Tabelle 10: Konstruktion regularer Ausdrucke

Zeichenx Zeichen x\\ Backslash\t Tab\n Newline\cx Control-Zeichen x

... ...Zeichenklassen

[abc] einfache Klasse (a, b, oder c)[ˆabc] Negation (ein beliebiges Zeichen ausser a, b, oder c)[a-zA-Z] inklusiver Bereich (alle Gross- und Kleinbuchstaben)[a-z-[bc]] Subtraktion (a bis Z ausser b und c)[a-z-[m-p]] Subtraktion mit inkl. Bereich (a bis z ausser m bis p)[a-z-[ˆdef]] (d, e, oder f)

Vordefinierte Zeichenklassen. beliebiges Zeichen (evtl. exklusive Zeilenendzeichen)\d eine Ziffer [0-9]\D keine Ziffer [ˆ0-9]\s Trenner (whitespace) [ \t\n\x0B\f\r]\S kein Trenner\w Textzeichen [a-zA-Z_0-9]\W kein Textzeichen

Begrenzerˆ Zeilenanfang weitere Verwendung Negation$ Zeilenende\b Wortgrenze\B keine Wortgrenze

... ...Greedy Quantoren

* 0 bis n des vorangestellten Zeichens Kleene-Stern+ 1 bis n des vorangestellten Zeichens? das vorangestellte Zeichen

0- oder 1-mal... ...

Weitere Quantoren... ...

Quotation\ markiert das folgende Zeichen

als “wortlich zu nehmen”

Logische OperatorenXY Sequenz (X gefolgt von Y)X | Y Oder (vgl. BNF)

Informatik B • SS 02 233

// Create a pattern to match catPattern p = Pattern.compile("cat");// Create a matcher with an input stringMatcher m = p.matcher("one cat," +

" two cats in the yard");StringBuffer sb = new StringBuffer();boolean result = m.find();// Loop through and create a new String// with the replacementswhile(result) {

m.appendReplacement(sb, "dog");result = m.find();

}// Add the last segment of input to// the new Stringm.appendTail(sb);System.out.println(sb.toString());

}}

• Allgemein konnen regulare Ausdrucke durch Strings uber Variablen ersetztwerden.

• Hierzu werden im regularen Ausdruck Gruppen gebildet:\[([a-z])\.([A-Z])\] kann durch (\1,\2) ersetzt werden.

Beispiele:[a.B] durch (a,B)[x.Y] durch (x,Y)

• Gruppen werden durch runde Klammern eingeschlossen.

• Wie genau Variablen notiert werden, hangt vom verwendeten Programm ab.

234 Informatik B • SS 02

16 Assertions

Achtung: Dieses Kapitel wird nochuberarbeitet und erweitert!

16.1 Zusicherungskalkul

• Im Kapitel “Typsicherheit” wurde gezeigt, wie im Prinzip die Korrektheit einerProgrammiersprache bewiesen werden kann.

• Schreibt man Programme, so mochte man gegeben die Semantik derentsprechenden Implementierungssprache, zusichern, dass diese korrekt sind.

• Verifikation: Das Programm erfullt seine Spezifikation (Beweis der partiellenKorrektheit).Validierung: Das Programm tut, was es tun soll (Testen, siehe Vorlesung“Informatik C”).

• In der Vorlesung “Informatik A” wurde das Zusicherungskalkul (Hoare-Kalkul)eingefuhrt.

• Dieses Kalkul ist eine formale Methode zum Korrektheitsbeweis vonProgrammen, das bis zu halbautomatischen Beweisern ausgebaut werdenkannn.

• Das Zustandskalkul ermoglicht die Angabe von Vor- und Nachbedingungen furProgrammanweisungen.

• Fur alle Typen von Anweisungen (Zuweisung, bedingte Anweisung, ...) undSchleifen sind Axiome vorgegeben. Von besonderer Bedeutung sindSchleifeninvarianten.

• Beispiel:Aus {P ∧ b}A{P} folgt P{while b loop A end} P ∧ ¬b.• Typischerweise gibt man Zusicherungen als Kommentare vor. Die Beweise

folgen als “symbolische Auswertung” per Hand.

/* P */while b {

/* P && b */...

/* P */}/* P && !b */

• Seit Java 1.4 gibt es die assert -Anweisung – von Flanagan als das “Numberone cool feature of Java 1.4” nominiert.

• Zusicherungen enthalten boolesche Ausdrucke, von denen der Programmiererannimmt, dass sie an der entsprechenden Stelle gelten.

Informatik B • SS 02 235

• Arbeiten mit Zusicherungen ist ein schneller und effizienter Weg um Fehler imProgramm zu erkennen und korrigieren. Sie dienen gleichzeitig alsDokumentation der Funktionalitat des Programms und erhohen damit seineWartbarkeit!

16.2 Die ‘assert’-Anweisung

Erganzung folgt

236 Informatik B • SS 02

17 Ausblick: GUIs und Event Handling

↪→ im Detail in “Informatik C: Oberflachenprogrammierung”

17.1 Java Foundation Classes

• Java Foundation Classes (JFC): Sammlung von Standard Java APIs fur Graphikund GUIs.“Foundation”: weil die meisten Java (client-seitigen) Applikationen daraufaufgebaut sind.

• Abstract Windowing Toolkit (AWT): bis Java 1.1, rudimentar und “heavyweight”(auf native GUI Komponenten aufgebaut). Durch native look and feel ergebensich viele kleine Unterschiede in der Darstellung zwischen verschiedenenPlattformen.Erweiterung Java2D: unterstutzt das Erstellen zweidimensionaler Graphiken,Erstellung von Zeichenprogrammen und Bildeditoren.

• Swing: state-of-the-art GUI toolkit, das vollstandig in Java geschrieben ist(“lightweight”). Swing unterstutzt pluggable look and feel, das heisst, dass dasAussehen der GUI dynamisch an verschiedene Plattformen undBetriebssysteme angepasst werden kann.

• Aber Achtung: Swing-Klassen sind auf AWT-Klassen aufgebaut.

• Applikationen: Java-Programme mit graphischer Oberflache, Ausgabe vonGraphik und Text auf Bildschirm oder Drucker, Daten-Transfer via drag-and-drop.

• Applets: Kleine Applikationen, die in einem Web-Browser (z.B. Netscape) laufen.

• GUI-Builder: sind visuelle Programmierumgebungen, die automatisch Code furgraphisch spezifizierte Oberflachen erzeugen. Dadurch kann sich dieEntwicklungszeit verringern und es besteht eine einfachce Moglichkeit,verschiedene Design auszuprobieren.

17.2 Swing-Komponenten

17.2.1 Erstes Beispiel ‘HelloWorldSwing’

import javax.swing.*;public class HelloWorldSwing {

public static void main(String[] args) {JFrame frame = new JFrame("HelloWorldSwing");final JLabel label = new JLabel("Hello World");frame.getContentPane().add(label);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.pack();frame.setVisible(true);

} }

Informatik B • SS 02 237

• Paket-Prafix javax : Swing kann als Erweiterung (eXtension) fur Java 1.1benutzt werden. Fur Java 2 gehort Swing zu den core-packages.

• Klasse JFrame : ist ein “top-level” ContainerHierarchie:

{\tt Objectjava.awt.Component (Serializable)java.awt.Containerjava.awt.Windowjava.awt.Framejavax.swing.JFrame

• Methode getContentPane() liefert Container und Container habenMethode add() .

• pack() ist Methode von Window: macht das Fenster Displayable ,Berechnung der Grosse fur das praferierte Layout und die Grossen derenthaltenen Komponenten.

• setVisible() : Methode einer Component , Zeigen oder Verstecken einerComponent. (alternativ show() )Bei Dialog-Fenstern kann es Sinn machen, dass bei Beenden des Dialogs dasFenster nicht zerstort, sondern nur unsichtbar gemacht wird(setVisible(false) ).

↪→ Generelles Prinzip: immer zunachst einen top-level Container erzeugen.

• GUI ist aus Bausteinen aufgebaut: push buttons, scrollbars, pull-down menus, ...

• Jeder Baustein ist eine Komponente (Component ).

• Swing hat alle Komponenten von AWT und weitere.

• Swing-Komponenten beginnen mit ‘J’.

• Swing Komponenten sind “light-weight” (plattform-unabhangig).

• JComponent ist Unterklasse von awt.Component .

• JWindow , JFrame und JDialog sind top-level Komponenten. Typischerweiseverwendet man JFrame als Fenster- und JDialog als Dialogfenster-Klasse.JWindow ist ein Fenster ohne “Dekoration”.

• JPanel ist einn typischer Container (siehe unten).

• Weitere wichtige Komponenten sind JButton (ein push-button), JLabel(Display-Feld fur Text oder Graphik), JTextField (Darstellen und Editiereneiner Textzeile).

238 Informatik B • SS 02

Component Container

Window

JComponent

JButton

JLabel

JPanel

JTextFieldjava.awt javax.swing

Frame

Dialaog

JWindow

JFrame

JDialog

Abbildung 62: Wichtige Swing und AWT Komponenten

17.2.2 Properties

• Fur jede Component kann ihr Aussehenund Verhalten angepasst werden(customization).

• Dies geschieht durch die Spezifikation von Werten fur die Properties einerKomponente.

• Properties werden uber Accesor-Methoden abgefragt und gesetzt: get prop () ,set prop () .Beispiel: setVisible(true) .

• Fur Properties mit Typ boolean wird anstelle von get is verwendet:isVisible() liefert true oder false .

17.2.3 Container

• Komponenten mussen innerhalb eines Container gepackt werden.

• Ein Container ist eine Component , die andere Component s enthalten kann.

• Alle speziellen Container sind Unterklassen von awt.Container .

• Typische Container: Fenster und Dialog-Boxen.

• Haufig werden Container in andere Container verschachtelt.

• Achtung: JFrame , JWindow und JDialog konnen nur als “aussertster”Container verwendet werden! (siehe unten)

• Manche Container stellen Information auf spezielle Weise dar, manche habenRestriktionen bzgl. Zahl und Art der Komponenten, die sie enthalten konnen,manche sind generisch (beliebig konfigurierbar).

Informatik B • SS 02 239

http://java.sun.com/docs/books/tutorial/uiswing/components/components_pics.

html

Abbildung 63: Beispiele fur Komponenten

240 Informatik B • SS 02

• Mit der Window-Methode pack() wird ein Fenster ge-rendert (rendering), alsoin eine graphische Darstellung gebracht. Dabei wird die Große des Fensters – inAbhangigkeit vom Layout der Unter-Komponenten – ermittelt.

• Jedes Fenster ist mit einem LayoutManager (ein Interface in java.awt )verbunden. Dieser wird mit pack() aktiviert.

• Typische Layout-Manager sind BorderLayout (Unterteilung eines Containersin funf Bereiche, siehe unten) oder ScrollPaneLayout (Default furJScrollPane ).

• Typische Schritte zum Erzeugen einer GUI:

1. Erzeugung der Container

2. Erzeugen der Components

3. Hinzufugen der Components zum Container ↪→ add()

JFrame frame = new JFrame("HelloWorldSwing"); // Containerfinal JLabel label = new JLabel("Hello World"); // Componentframe.getContentPane().add(label);

• Spezielles Verhalten der top-level Container JFrame , JWindow , JDialog :

– Wenn solche Container erzeugt werden, erzeugen diese automatisch eineUnterklasse JRootPane , die eine Unterklasse von JComponent ist unddas Interface RootPaneContainer implementiert.

– Alle Komponenten werden in JRootPane eingefugt. Die MethodegetContentPane() liefert denjenigen Container, in den dieKomponenten eingefugt werden sollen.

17.2.4 Layout Management

• JFrame und JDialog sind generische Komponenten. Sie benutzen JPanel alsdefault content pane und spezifizieren kein vordefiniertes Layout derKomponenten.

• Hier muss ein LayoutManager definiert werden, um die Komponenten imContainer anzuordnen.

• Default-Layout ist vorgegeben (d.h. entsprechendes Objekt existiert). Z.B. furJFrame : BorderLayout .

• BorderLayout erlaubt bis zu 5 Komponenten mit den Positionen North, South,East, West, Center.

import java.awt.*;import javax.swing.*;

public class BorderWindow extends JFrame {

Informatik B • SS 02 241

public BorderWindow() {Container contentPane = getContentPane();//Use the content pane’s default BorderLayout.//contentPane.setLayout(new BorderLayout()); //unnecessary

contentPane.add(new JButton("Button 1 (NORTH)"),BorderLayout.NORTH);

contentPane.add(new JButton("2 (CENTER)"),BorderLayout.CENTER);

contentPane.add(new JButton("Button 3 (WEST)"),BorderLayout.WEST);

contentPane.add(new JButton("Long-Named Button 4 (SOUTH)"),BorderLayout.SOUTH);

contentPane.add(new JButton("Button 5 (EAST)"),BorderLayout.EAST);

}

public static void main(String args[]) {BorderWindow window = new BorderWindow();window.setTitle("BorderLayout");window.pack();window.setVisible(true);

}}

17.2.5 Anmerkungen

• Bei der Gestaltung der Oberflache ist es meist sinnvoll, sich an bereitseingefuhrte Standards zu halten (z.B. bei der Menu-Organisation, Anordnung,Aussehen): Benutzer haben sich bereits an eingefuhrte Oberflachen gewohnt(Adaptationseffekte), auch wenn diese ergonomisch keineswegs optimal sind.↪→ principle of least astonishment

• Es ist kein guter Stil, eine schicke Oberflache allein zu verkaufen (d.h. mit “niy”hinter allen interessanten Menupunkten und einigen Standardalgorithmen hinter

242 Informatik B • SS 02

den anderen Menupunkten).

• Software-Ergonomie ist ein wichtiges Forschungsgebiet, zu demKognitionswissenschaftler viel beitragen konnen.

• Empirische Studien von grundlegenden psychophysischen Faktoren (Kontrast,Grosse, Farbe von Schrift) bis zur Nutzerfuhrung.

• Eine noch so schicke GUI bringt gar nichts, wenn dahinter nicht sorgfaltigerCode steht! (“aussen GUI innen pfui”).

• Fur die Entwicklung komplexer Projekte kann es jedoch sinnvoll sein, vorab oderparallel zum Code bereits die Oberflache zu entwerfen, um einen Uberblick uberalle gewunschten Funktionalitaten und deren Abhangigkeiten zu bekommen.

17.3 Event-Handling

• Bisher: Hubsche Oberflachen, die aber nichts tun.

• GUI-Komponenten sollen auf Benutzer-Eingaben reagieren konnen.

• Event: Nutzeraktion, wie Mausklick auf Button oder Tastatureingabe.

• Objekte, die auf Event reagieren. ↪→ event listener

17.3.1 Event-Objekte

• Basis-Klasse: java.util.EventObjectSwing: javax.swing.event -Paket enthalt Unterklassen von EventObjectund AWTEvent.

• EventObject -Methode getSource() : liefert Objekt, das den Event ausgelosthat

• AWTEvent-Methode getID() : Unterscheidung von verschiedenen Events einerKlasse

• WindowEvent -Methode: getNewState() liefert den neuen Zustand einesFensters ( NORMAL, ICONIFIED, MAXIMIZED_VERT ...)

• Typische Event-Klassen: WindowEvent , MouseEvent

17.3.2 Event Listener

• Ein Objekt, das einen Event erzeugt heisst event source.

• Ein Objekt, das auf einen Event reagieren soll heisst event listener.

• Event Source Objekte halten eine Liste von listeners , die informiert (notified)werden wollen und bietet Methoden zum Einfugen und Loschen vonListener -Objekten.

Informatik B • SS 02 243

• Alle Komponenten sind Event-Sources und definieren entsprechende add()und remove() Methoden, die per Konvention mit Listener enden. z.B.addWindowListener() , addActionListener()

• Zu jeder Art von Event Objekt existiert ein korrespondierender Event Listener,z.B. ActionListener .

• Alle Listener erweitern das Marker-Interface java.util.EventListener .

• Vordefinierte Listener wie ActionListener sind selbst Interfaces und gebeneine Methode actionPerformed() vor.

• Event-Adapter konnen alternativ verwendet werden: statt alle Methoden einesListenerInterfaces zu implementieren kann eine Unterklasse zu einerentsprechenden Adapterklasseerzeugt werden, in der dann die gewunschte(n)Methode(n) uberschieben wird.Beispiel: Realisieren eines WindowListener uber einen WindowAdapter(siehe unten)

17.3.3 Event Handling mit Inneren Klassen

• Um uber einen Event informiert zu werden, muss ein entsprechendesEventListener -Interface implementiert werden.

• Manchmal kann dies direkt in der Haupt-Klasse der Applikation geschehen.

• Typisch ist, anonyme innere Klassen zu verwenden. (Listener waren dieHauptmotivation fur Innere Klassen)

// create window listener for window close clickaddWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e)

{System.exit(0);}});

/* JFC in a Nutshell, Flanagan */import java.awt.*; // AWT classesimport javax.swing.*; // Swing components and classesimport javax.swing.border.*; // Borders for Swing componentsimport java.awt.event.*; // Basic event handling

public class DisplayMessage {public static void main(String[] args) {

/** Step 1: Create the components*/

JLabel msgLabel = new JLabel(); // Component to display the questionJButton yesButton = new JButton(); // Button for an affirmative responseJButton noButton = new JButton(); // Button for a negative response

/*

244 Informatik B • SS 02

* Step 2: Set properties of the components*/

msgLabel.setText(args[0]); // The msg to displaymsgLabel.setBorder(new EmptyBorder(10,10,10,10)); // A 10-pixel marginyesButton.setText((args.length >= 2)?args[1]:"Yes"); // Text for YesnoButton.setText((args.length >= 3)?args[2]:"No"); // for no button

/** Step 3: Create containers to hold the components*/

JFrame win = new JFrame("Message"); // The main application windowJPanel buttonbox = new JPanel(); // A container for the two buttons

/** Step 4: Specify LayoutManagers to arrange components in the containers*/

win.getContentPane().setLayout(new BorderLayout()); // layout on bordersbuttonbox.setLayout(new FlowLayout()); // layout left-to-right

/** Step 5: Add components to containers, with optional layout constraints*/

buttonbox.add(yesButton); // add yes button to the panelbuttonbox.add(noButton); // add no button to the panel

// add JLabel to window, telling the BorderLayout to put it in the middlewin.getContentPane().add(msgLabel, "Center");

// add panel to window, telling the BorderLayout to put it at the bottomwin.getContentPane().add(buttonbox, "South");

/** Step 6: Arrange to handle events in the user interface.*/

yesButton.addActionListener(new ActionListener() { // Note: inner class// This method is called when the Yes button is clicked.public void actionPerformed(ActionEvent e) { System.exit(0); }

});

noButton.addActionListener(new ActionListener() { // Note: inner class// This method is called when the No button is clicked.public void actionPerformed(ActionEvent e) { System.exit(1); }

});

/** Step 7: Display the GUI to the user*/

win.pack(); // Set the size of the window based its children’s sizes.

Informatik B • SS 02 245

win.show(); // Make the window visible.}

}

17.4 Applets

• Mini-Applikation, die uber Netz von einer (untrusted) Quelle geladen werdenkann, und die in einem Web-Browser oder einer andere Applet-ViewerAnwendung ausgefuhrt werden kann.

• Machtige Moglichkeit, um Java Programme an Endbenutzer zu liefern.

• Gerade die Applets machten Java popular.

17.4.1 Unterschiede zwischen Applets und Applications

• Ein Applet hat keine main() Methode.

• Ein Applet wird nicht uber die Kommandozeile aufgerufen. Es ist in einHTML-File – <APPLET>-tag – eingebettet und erhalt seine Argumente uber <PARAM> tags im HTML-File.

• Applets unterliegen einigen Sicherheitsbeschrankungen, die verhindern sollen,dass auf dem Host unsichere und moglicherweise bosartige Applets ausgefuhrtwerden.

17.4.2 Schreiben von Applets

• Unterklasse von java.applet.Applet (Unterklasse vonjava.awt.Component <-- java.awt.Panel ) und Uberschreiben vonStandard-Methoden.(Alternativ JApplet )

• Applets haben keine Kontrolle uber den Execution-Thread (anders alsProgramme mit main() ). Deshalb durfen sie keine zeitaufwendigenBerechnungen durchfuhren – ausser sie erzeugen ihren eigenen Thread.

Auswahl von Methoden der Applet -Klasse:

246 Informatik B • SS 02

• init() : Wird beim Laden des Applets ausgefuhrt – anstelle eines Konstruktors.Hier werden typischerweise GUI-Komponenten erzeugt.

• destroy() : Gegenstuck zu init() : Applet wird aus dem Browser entferntund sollte alle Resourcen freigeben.

• start() : Wird aufgerufen, wenn das Applet sichtbar wird.

• stop() : Temporares nicht-sichtbar machen, stoppen derAnimation/Berechnung.

• getImage() : Laden eines Image-Files vom Netz.

• getCodeBase() : URL, von der das Applet-Klassen-File geladen wurde.

Auswahl von Methoden der Component -Klasse:

• paint() : Zeichne Dich selbst als wichtigste Methode.

17.4.3 Beispiel

/* JFC in a Nutshell, Flanagan */import java.applet.*;import java.awt.*;

public class MessageApplet extends Applet {protected String message; // The text to displayprotected Font font; // The font to display it in// One-time initialization for the appletpublic void init() {

message = this.getParameter("message");font = new Font("Helvetica", Font.BOLD, 48);

}

// Draw the applet whenever necessary.public void paint(Graphics g) {

// The pink ovalg.setColor(Color.pink);g.fillOval(10, 10, 330, 100);

// The red outline. The browser may not support Java2D, so we// try to simulate a 4-pixel wide line by drawing four ovals.g.setColor(Color.red);g.drawOval(10,10, 330, 100);g.drawOval(9, 9, 332, 102);g.drawOval(8, 8, 334, 104);g.drawOval(7, 7, 336, 106);

// The textg.setColor(Color.black);g.setFont(font);

Informatik B • SS 02 247

g.drawString(message, 40, 75);}

}

HTML-File:

<APPLET code="MessageApplet.class" width=350 height=125><PARAM name="message" value="Hello World">

</APPLET>

Aufruf:> appletviewer MessageApplet.html

17.5 GUIs und Threads

• Jede GUI-Applikation hat einen event dispatch thread: Thread, der daraufwartet, dass Ereignisse eintreten und diese an die entsprechendenEvent-Handler ausliefert.

• Alle event listener Methoden werden vom event dispatch thread aufgerufen(invoke).↪→ alle GUI Manipulationen, die uber event listener ausgefuhrt werden, sindsicher.

• actionPerformed() und paint() werdem im event-dispatching threadausgefuhrt.So wird beispielsweise wahrend eine actionPerformed() Methodeausgefuhrt wird, die GUI “eingefroren” (kein re-paint, keine Reaktion aufMaus-Klicks, ...)

248 Informatik B • SS 02

• Swing Komponenten sind nicht thread-safe: Es muss darauf geachtet werden,dass nur der event-dispatch thread auf solche Komponenten zugreift.

• Ubliche Losung: “Single-Thread Rule”: Wenn eine Swing-Komponente realisiertwurde, sollte der gesamte Code, der diese Komponenten beeinflusst oder vonihr abhangt im event dispatch thread ausgefuhrt werden.

• Code in Event-Handlern sollte schnell ausgefuhrt werden (sonst schlechtePerformanz)

17.6 Beans

• Bean: Wiederverwendbare Software-Komponente, die in einem Builder-Toolvisuell manipuliert werden kann.Beispiel: BDK (Java Beans Development Kit).

• Typisch fur graphische Benutzeroberflachen.

• Schreiben von Beans: z.B. neue graphische Komponentensollten uber Properties konfigurierbar sein und entsprechende get - undset -Methoden anbieten.

• Nutzen von Beans: Zusammenstecken und Konfigurieren von Komponenten undmit Code verbinden.

18 Ausblick: Verteilte Systeme

19 Andere Objekt-Orientierte Sprachen