• Keine Ergebnisse gefunden

Informatik B Objekt-orientierte Programmierung in Java

N/A
N/A
Protected

Academic year: 2021

Aktie "Informatik B Objekt-orientierte Programmierung in Java"

Copied!
274
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Informatik B

Objekt-orientierte Programmierung in Java

Sommersemester 2003

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/b03/

(2)

Fachbereich 6, Mathematik/Informatik Universit ¨at Osnabr ¨uck

Albrechtstrasse 28, D-49076 Osnabr ¨uck Raum 31/318

Tel.: 0541/969-2558

schmid@informatik.uni-osnabrueck.de http://www.inf.uos.de/schmid/

Dies ist eine ¨uberarbeitete Version der Skripts vom SS 2001 und SS 2002. Vielen Dank an Elmar Ludwig f ¨ur kritische Durchsicht, Korrekturvorschl ¨age, Anregungen und Diskussionen.

(3)

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 ‘Nebenl ¨aufigkeit’:

Doug Lea, Concurrent Programming in Java. Design Principles and Patterns, 2nd Edition, 1999, Sun Books.

Lehrbuch, das den Stoff von ‘Algorithmen’ abdeckt mit Programmen in Pseudo-Java (eher prozeduraler Code):

Sara Baase, Allen van Gelder, Computer Algorithms – Introduction to Design and Analysis, 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 the Internet, 2nd Edition, 1997, Addison-Wesley. (auch in deutscher ¨Ubersetzung erh ¨altlich) Ken Arnold, James Gosling, The Java Programming Language, 3rd Edition, Addison-Wesley.

(auch in deutscher ¨Ubersetzung erh ¨altlich)

(4)

J. R. Anderson, Kognitive Psychologie, 3. Auflage, 2001, Spektrum. (Hierarchisches semantisches Ged ¨achtnis)

R. G. Herrtwich und G. Hommel, Nebenl ¨aufige Programme, 2. Auflage, Springer, 1994.

Atsushi Igarashi, Benjamin Pierce and Philip Wadler, Featherweight Java: A Minimal Core Calculus 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 in Information and Computation as of November 24, 2000.

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

A. T. Schreiner, Vorlesungsskript Programming with Java 2, Universit ¨at Osnabr ¨uck und Rochester Institute of Technology.http://www.cs.rit.edu/˜ats/java-2000-1/

Sperschneider und Hammer, 1996, Theoretische Informatik. Eine problemorientierte Einf ¨uhrung. Springer.

Oliver Vornberger und Olaf M ¨uller, Skript Informatik A.

(5)

1 Einf ¨uhrung: Programmier-Paradigmen und -Sprachen 1

1.1 Entwicklung von Paradigmen und Sprachen . . . 1

1.1.1 Uberblick . . . .¨ 1

1.1.2 Entwicklung von Hochsprachen . . . 1

1.1.3 Motivation: Kenntnis mehrere Paradigmen . . . 3

1.2 Prozeduren und Parameter ¨ubergabe-Mechanismen . . . 4

1.2.1 Programmstruktur bei imperativen Sprachen . . . 4

1.2.2 Prozeduren . . . 4

1.2.3 Parameter ¨ubergabe-Methoden . . . 6

1.2.4 Call-by-Value versus Call-by-Reference . . . 7

1.2.5 Call-by-Value versus Call-by-Name . . . 7

1.2.6 Call-by-value in Java . . . 8

1.3 Sprach-Implementierung . . . 10

1.4 Syntaktische Struktur . . . 12

1.4.1 Formale Sprachen . . . 12

1.4.2 BNF und EBNF . . . 13

1.5 Semantik und Pragmatik . . . 15

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

2.1.1 Eigenschaften Objekt-Orientierter Sprachen . . . 17

2.1.2 Prinzipien der Objekt-Orientierten Programmierung . . . 17

2.2 Die Sprache Java . . . 18

2.2.1 Entstehungsgeschichte . . . 18

2.2.2 Java Buzzwords . . . 19

2.2.3 Sprache, Virtuelle Maschine, Plattform . . . 19

2.3 Das 8-Damen Problem Imperativ und Objekt-Orientiert . . . 21

2.3.1 Problemstellung . . . 21

2.3.2 Identifikation von Schlagstellungen . . . 22

2.3.3 Imperative L ¨osung . . . 23

2.3.4 Objekt-Orientierte L ¨osung . . . 24

3 Klassen und ihre Komponenten 28 3.1 Klassen in Java . . . 28

3.2 Members: Felder, Methoden, Klassen . . . 28

3.3 Beispielcode ‘Circle’ . . . 29

3.4 Klassen- und Instanz-Komponenten . . . 29

3.4.1 Klassen-Felder . . . 29

3.4.2 Klassen-Methoden . . . 30

3.4.3 Instanz-Felder . . . 30

3.4.4 Erzeugung und Initialisierung von Objekten . . . 31

3.4.5 Instanz-Methoden . . . 31

3.4.6 Funktionsweise von Instanz-Methoden: ‘this’ . . . 32

3.4.7 Instanz- oder Klassen-Methode? . . . 32

3.5 Referenztypen . . . 33

3.5.1 Kopieren von Objekten (und Arrays) . . . 34

(6)

3.7 Dokumentation mit ‘javadoc’ . . . 37

3.8 Packages und Namespace . . . 40

3.8.1 Java API . . . 40

3.8.2 Packages und Namespaces in Java . . . 41

3.8.3 Namens-Kollisionen . . . 42

3.8.4 Verhaltens ¨anderungen . . . 43

4 Konstruktoren und Vererbung 45 4.1 Konstruktoren . . . 45

4.1.1 Definition von Konstruktoren . . . 45

4.1.2 Definition mehrerer Konstruktoren . . . 46

4.2 Defaults und Initialisierung f ¨ur Felder . . . 46

4.2.1 Defaults . . . 46

4.2.2 Initialisierung von Instanz-Feldern: Konstruktoren . . . 47

4.2.3 Initialisierung von Klassen-Feldern: Initialisierungs-Bl ¨ocke . . . 48

4.3 Zerst ¨oren und Finalisieren von Objekten . . . 49

4.3.1 Garbage Collection . . . 49

4.3.2 Anmerkung: Finalization . . . 49

4.4 Unterklassen und Vererbung . . . 50

4.4.1 Exkurs: Hierarchische Semantische Netze . . . 50

4.4.2 Erweiterung von ‘Circle’ . . . 52

4.4.3 Erweiterung einer Klasse . . . 52

4.5 Kapslung und Zugriffskontrolle . . . 53

4.5.1 Zugriffs-Kontrolle . . . 54

4.5.2 Vier Ebenen von Zugriffsrechten . . . 54

4.5.3 Zugriffs-Kontrolle und Vererbung . . . 55

4.5.4 Daumenregeln f ¨ur Sichtbarkeits-Modifikatoren . . . 56

4.5.5 Daten-Zugriffs-Methoden . . . 56

5 Klassenabh ¨angigkeiten 58 5.1 Klassenhierarchie . . . 58

5.1.1 Finale Klassen . . . 58

5.1.2 Die Klasse ‘Object’ . . . 58

5.1.3 Klasse ‘String’ . . . 58

5.1.4 Hierarchische Klassenstruktur . . . 59

5.2 Erg ¨anzung: Konstruktoren . . . 61

5.2.1 Unterklassen-Konstruktoren . . . 61

5.2.2 Default-Konstruktoren . . . 61

5.2.3 Konstruktor-Verkettung . . . 62

5.3 Vererbung: Shadowing und Overriding . . . 62

5.3.1 Verdecken von Feldern der Oberklasse . . . 62

5.3.2 Shadowing von Klassen-Feldern . . . 63

5.3.3 Uberschreiben von Instanz-Methoden der Oberklasse . . . .¨ 64

5.3.4 Uberschreiben vs. Verdecken . . . .¨ 64

5.3.5 Dynamisches ‘Method Lookup’ . . . 65

5.3.6 ‘Final’ Methoden und Statisches ‘Method Lookup’ . . . 65

(7)

5.4 Overloading und Polymorphismus . . . 66

5.4.1 Operator-Overloading . . . 66

5.4.2 Operator-Overloading in Java . . . 67

5.4.3 Method-Overloading in Java . . . 68

5.4.4 Polymorphismus . . . 69

5.4.5 Casting und Polymorphismus . . . 69

5.4.6 Casting vs. Parameterisierte Klassen . . . 70

6 Exceptions 72 6.1 Fehler und Ausnahmen . . . 72

6.2 Vorteile von Exceptions . . . 73

6.2.1 Separierung von Code und Fehlerbehandlung . . . 73

6.2.2 Propagierung von Exceptions . . . 74

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

6.4 Spezifikation von Exceptions – ‘throws’ . . . 79

6.5 Vererbung und ‘throws’ . . . 79

6.5.1 Gruppierung von Fehler-Typen . . . 80

6.6 Definition eigener Exception-Klassen und Ausl ¨osen von Exceptions . . . 81

6.7 Exkurs: UML . . . 82

6.7.1 Klassendiagramme in UML . . . 82

6.7.2 Klassen-/ Unterklassenbeziehungen in UML . . . 83

6.7.3 Assoziationen . . . 84

6.7.4 Kommentare und Annotierung in UML . . . 85

6.7.5 UML-Tools . . . 85

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

7 Input/Output 90 7.1 Ein-/Ausgabe-Str ¨ome . . . 90

7.1.1 Klassenstruktur in ‘java.io’ . . . 90

7.1.2 Character und Byte Str ¨ome . . . 91

7.1.3 Wichtige Reader- und Writer-Klassen . . . 93

7.2 Datei-Str ¨ome . . . 94

7.3 Puffern von Daten . . . 95

7.4 Filter-Str ¨ome . . . 96

7.5 Standard-Ein- und Ausgabe . . . 98

7.6 IO-Exceptions . . . 99

7.7 RandomAccess . . . 99

7.8 Weitere Aspekte von I/O . . . 100

7.8.1 Tokenizer . . . 100

7.8.2 Serializable, Externalizable . . . 101

7.8.3 Pipe-Str ¨ome . . . 101

8 Vererbung und Typsicherheit 102 8.1 Formale Modelle f ¨ur Programmiersprachen . . . 102

8.2 Featherweight Java . . . 103

8.2.1 Programmbeispiel . . . 104

8.2.2 Syntax f ¨ur FJ . . . 105

(8)

8.3 Typisierung und Reduktion in FJ . . . 108

8.3.1 Typisierungsregeln . . . 108

8.3.2 Reduktionsregeln . . . 108

8.3.3 Veranschaulichung . . . 110

9 Abstrakte Klassen und Interfaces 113 9.1 Abstrakte Klassen und Methoden . . . 113

9.2 Interfaces . . . 114

9.2.1 Implementation eines Interfaces . . . 115

9.2.2 Interfaces und Konstanten . . . 116

9.2.3 Benutzung von Interfaces . . . 116

9.2.4 Interface vs. Abstrakte Klasse . . . 117

9.2.5 Implementation mehrerer Interfaces und Erweitern von Interfaces . . . 118

9.2.6 Marker-Interfaces . . . 120

9.3 Das Enumeration-Interface . . . 120

10 Innere Klassen 123 10.1 Member Classes . . . 123

10.1.1 Anschauliches Beispiel . . . 123

10.1.2 Beispiel ‘Enumerator’ . . . 124

10.1.3 Eigenschaften von Member-Klassen . . . 125

10.1.4 Implementation von Member-Klassen . . . 126

10.1.5 Member-Klassen und Vererbung . . . 127

10.2 Static Member Classes . . . 128

10.2.1 Anschauliches Beispiel . . . 128

10.2.2 Eigenschaften von Static Member Classes . . . 129

10.2.3 Implementation von statischen Member-Klassen . . . 130

10.3 Lokale Klassen . . . 130

10.3.1 Anschauliches Beispiel . . . 130

10.3.2 Beispiel: ‘Enumerator’ als lokale Klasse . . . 131

10.3.3 Eigenschaften Lokaler Klassen . . . 132

10.3.4 Geltungsbereich Lokaler Klassen . . . 133

10.4 Anonyme Klassen . . . 135

10.4.1 Beispiel: ‘Enumerator’ als anonyme Klasse . . . 135

10.4.2 Eigenschaften von Anonymen Klassen . . . 135

10.4.3 Implementation von Lokalen und Anonymen Klassen . . . 136

10.4.4 Adapter-Klassen als Anonyme Klassen . . . 136

10.4.5 Anwendung und Konventionen . . . 137

10.5 Zusammenfassung . . . 137

10.6 Beispiel-Code ‘Enumeration’ . . . 138

10.7 Adapter-Patterns und Java Adapter-Klassen . . . 140

10.8 Innere Klassen und Lexical Closures . . . 141

10.8.1 Code as Data . . . 142

10.8.2 Adder-Beispiel . . . 142

(9)

11.1 Abstrakte Datentypen . . . 143

11.1.1 Grundlagen . . . 143

11.1.2 Funktionalit ¨aten von Collections . . . 143

11.2 Implementation von Collections . . . 144

11.3 Implementation mit Array . . . 145

11.3.1 MyCollection/Array . . . 145

11.3.2 Erl ¨auterungen zu ‘MyCollection’ . . . 147

11.3.3 Test-Protokoll f ¨ur ‘MyCollection’ . . . 147

11.3.4 Bag/Array . . . 148

11.3.5 Erl ¨auterungen zu ‘Bag’ . . . 149

11.3.6 Set/Array . . . 149

11.3.7 Erl ¨auterungen zu Set . . . 150

11.3.8 Test-Protokoll f ¨ur ‘Set’ . . . 151

11.3.9 EquivalenceSet/Array . . . 151

11.3.10Erl ¨auterungen zu ‘EquivalenceSet’ . . . 152

11.3.11Test-Protokoll f ¨ur ‘EquivalenceSet’ . . . 152

11.4 Implementation mit Offener Hash-Tabelle . . . 153

11.4.1 Array versus Hash-Tabelle . . . 153

11.4.2 MyCollection/Hash . . . 153

11.4.3 Erl ¨auterungen zu ‘MyCollection’ . . . 156

11.4.4 Bag/Hash . . . 156

11.4.5 Set/Hash . . . 157

11.5 ADT-Test . . . 157

11.5.1 Anforderungen an ‘Test’ . . . 157

11.5.2 Test/ADT . . . 158

11.5.3 Erl ¨auterungen zu ‘Test’ . . . 160

11.6 Implementation mit Liste . . . 161

11.6.1 Dynamische Datenstrukturen . . . 161

11.6.2 Bag/List . . . 163

11.6.3 Erl ¨auterungen zu ‘Bag’ . . . 165

11.6.4 Unterklasse ‘Set’ . . . 166

11.6.5 Unterklasse ‘EquivalenceSet’ . . . 166

11.7 Implementation mit Suchbaum . . . 167

11.7.1 Suchb ¨aume . . . 167

11.7.2 Set/Tree . . . 168

11.7.3 Erl ¨auterungen zu ‘Set’ . . . 172

11.8 Visitor . . . 174

11.8.1 Konzept eines Visitor . . . 174

11.8.2 ‘Visitor’, ‘Visitable’/ADT . . . 175

11.8.3 Suchbaum mit Visitor . . . 176

11.9 Java Collection Classes . . . 176

11.9.1 Grundstruktur . . . 176

11.9.2 Illustration . . . 177

(10)

12.2 Die Klassen ‘Class’, ‘Method’, ‘Field’ und ‘Constructor’ . . . 180

12.3 Inspektion von Klassen . . . 181

12.3.1 Abruf eines ‘Class’ Objekts . . . 181

12.3.2 Abruf des Klassen-Namens eines Objekts . . . 182

12.3.3 Abruf von Klassen-Modifikatoren . . . 183

12.3.4 Abruf von Oberklassen . . . 183

12.3.5 Abruf des implementierten Interfaces einer Klasse . . . 184

12.3.6 Interface oder Klasse? . . . 184

12.3.7 Abruf von Klassen-Feldern . . . 185

12.3.8 Abruf von Klassen-Konstruktoren . . . 186

12.3.9 Abruf von Methoden-Information . . . 186

12.4 Manipulation von Objekten zur Laufzeit . . . 188

12.4.1 Dynamische Erzeugung von Objekten . . . 188

12.4.2 Exceptions beim dynamischen Erzeugen von Objekten . . . 188

12.4.3 Dynamische Erzeugung mit Konstruktor-Argumenten . . . 189

12.4.4 Abruf und Belegung von Feldern . . . 190

12.4.5 Method Invocation . . . 190

12.5 Bemerkungen . . . 191

13 Multi-Threading – Grundlagen der Nebenl ¨aufigkeit 193 13.1 Sequentialit ¨at, Determinismus, Determiniertheit . . . 193

13.1.1 Nebenl ¨aufigkeit . . . 193

13.1.2 Nicht-Determinismus . . . 194

13.1.3 Nicht-Determiniertheit . . . 194

13.1.4 Verzahnung . . . 195

13.2 Nebenl ¨aufigkeit in Java: Threads . . . 195

13.2.1 Definition von Threads . . . 196

13.2.2 Die Klasse Thread . . . 196

13.2.3 Einfaches Beispiel: ‘ThreadDemo’ . . . 197

13.2.4 Erl ¨auterungen zu ‘ThreadDemo’ . . . 199

13.2.5 Zust ¨ande von Threads . . . 200

13.3 Kooperierende und Konkurrierende Prozesse . . . 200

13.3.1 Kooperierende Prozesse . . . 200

13.3.2 Konkurrierende Prozesse . . . 201

13.4 Synchronisation . . . 203

13.5 Monitore in Java . . . 203

13.5.1 Synchronized . . . 203

13.5.2 Funktion von ‘synchronized’ . . . 205

13.5.3 Warten auf Ereignisse mit Monitoren . . . 205

13.6 Beispiel: Produzent/Konsument . . . 206

14 Multi-Threading: Semaphoren und Deadlocks 209 14.1 Semaphoren . . . 209

14.1.1 Konzept . . . 209

14.1.2 Klasse ‘Semaphore’ . . . 209

14.1.3 Einseitige und Mehrseitige Synchronisation . . . 210

(11)

14.2 Conditional Critical Regions . . . 212

14.2.1 Monitore, CCRs, Semaphoren . . . 213

14.3 Deadlocks . . . 213

14.3.1 L ¨osung mit Semaphoren . . . 213

14.3.2 Dining Philosophers – L ¨osung mit globaler Kontrolle . . . 214

14.3.3 Dining Philosophers – Bedingter Zugriff auf Gabel . . . 217

14.3.4 Deadlocks durch falsche Anordnung . . . 219

14.4 Threads: Erg ¨anzungen . . . 220

14.5 Pipe-Str ¨ome . . . 221

15 Regul ¨are Ausdr ¨ucke und Pattern-Matching 225 15.1 String Pattern-Matching . . . 225

15.1.1 Motivation . . . 225

15.1.2 Straightforward L ¨osung . . . 225

15.1.3 String-Matching mit endlichen Automaten . . . 225

15.1.4 Der Knuth-Morris-Pratt (KPM) Algorithmus . . . 227

15.1.5 Pattern-Matching mit Regul ¨aren Ausdr ¨ucken . . . 229

15.2 Java 1.4 ‘regex’ . . . 230

15.2.1 Konstruktion regul ¨arer Ausdr ¨ucke . . . 230

15.2.2 Die Pattern-Klasse . . . 231

15.2.3 Die Matcher-Klasse . . . 231

15.2.4 Beispiel: Suche und Ersetze . . . 231

16 Assertions 234 16.1 Zusicherungskalk ¨ul . . . 234

16.2 Die ‘assert’-Anweisung . . . 235

17 Ausblick: GUIs und Event Handling 236 17.1 Java Foundation Classes . . . 236

17.2 Swing-Komponenten . . . 236

17.2.1 Erstes Beispiel ‘HelloWorldSwing’ . . . 236

17.2.2 Properties . . . 238

17.2.3 Container . . . 238

17.2.4 Layout Management . . . 240

17.2.5 Anmerkungen . . . 241

17.3 Event-Handling . . . 242

17.3.1 Event-Objekte . . . 242

17.3.2 Event Listener . . . 242

17.3.3 Event Handling mit Inneren Klassen . . . 243

17.4 Applets . . . 245

17.4.1 Unterschiede zwischen Applets und Applications . . . 245

17.4.2 Schreiben von Applets . . . 245

17.4.3 Beispiel . . . 246

17.5 GUIs und Threads . . . 247

17.6 Beans . . . 248

(12)

18.2 Grundlagen f ¨ur Kommunikation im Netz . . . 249

18.2.1 Open System Interconncetion (OSI) Model . . . 249

18.2.2 TCP und UDP . . . 250

18.2.3 Ports . . . 251

18.2.4 Networking Klassen in Java . . . 251

18.3 Die Klasse ‘URL’ . . . 251

18.3.1 Was ist eine URL? . . . 251

18.3.2 Nutzen der URL Klasse . . . 252

18.3.3 Beispiel: URLConnection . . . 253

18.4 Sockets f ¨ur Client/Server Kommunikation . . . 254

18.4.1 Grundidee der Client/Server Kommunikation . . . 254

18.4.2 Sockets in Java . . . 255

18.4.3 Beispiel ‘KnockKnockServer’ . . . 255

18.5 Sicherheit . . . 258

19 Andere Objekt-Orientierte Sprachen 259 19.1 Das 8-Damen Problem Revisited . . . 259

19.2 L ¨osung in Smalltalk . . . 259

19.3 L ¨osung in Objective-C . . . 260

19.4 L ¨osung in C++ . . . 261

(13)

1 Einf ¨uhrung: 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 j ¨ungste Paradigma (80er Jahre).

Jedem Paradigma lassen sich konkrete Programmiersprachen zuordnen.

Java ist eine relativ junge Sprache, die das objekt-orientierte Paradigma unterst ¨utzt (1995).

Imperative/Prozedurale Sprachen (Fortran, Pascal, Modula, C): Zuweisung von Werten 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 von Objekten, die miteinander interagieren.

Is a programming language a tool for instructing machines? A means for communicating between programmers? A vehicle for expressing high-level designs? A notation for algorithms? A way of expressing relationships between concepts? A tool for experimentation? A means for controlling computerized devices? My conclusion is that a general-purpose

programming language must be all of those to serve its diverse set of users. The only thing a language cannot be – and survive – is be a mere collection 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 einen wesentlichen Fortschritt: Lesbarkeit, Fehlerpr ¨ufung, Maschinenunabh ¨angigkeit, Bibliotheken.

strukturierte Programmierung (Dijkstra): Zerlegung eines Programms (Prozeduren, Abstrakte Datentypen, Module)

(14)

Fortran

Algol−58

Algol−60 Cobol

Simula I

Simula−67 Algol−68

C

Modula−2 Fortran−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 1957

1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995

Pascal

IMPERATIV OBJEKTORIENTIERT FUNKTIONAL LOGISCH

Abbildung 1: Entwicklung von h¨oheren Programmiersprachen

Hochsprachen werden entweder von einem Compiler in Maschinencode

¨ubersetzt oder ¨uber einen Interpreter ausgef ¨uhrt. Dazwischen stehen just-in-time Compiler, bei denen Teile des Programms erst w ¨ahrend der Ausf ¨uhrung ¨ubersetzt werden.

(“vierte Generation”: anwendungsspezifische Sprachen wie SQL, Mathematica) Funktionale und logische Sprachen werden gemeinsam auch alsdeklarative Sprachen bezeichnet (“f ¨unfte Generation”, KI-Sprachen).

Eine Programmiersprache ist eine formale Sprachemit Syntax (Grammatik, die beschreibt, wie die Symbole der Sprache kombiniert werden d ¨urfen), Semantik (Bedeutung der Sprachkonstrukte, ihr Laufzeitverhalten), und Pragmatik

(Verwendung von Sprachmerkmalen; Sprachimplementation)

Sprachen sind sich mehr oder weniger ¨ahnlich. Sprachen innerhalb desselben Programmierparadigmas basieren auf ¨ahnlichen Grundstrukturen.

Nat ¨urliche Sprachen – Deutsch, Englisch, Hopi-Indianisch, Japanisch,

Esperanto – fallen in verschiedene Sprachfamilien. Indogermanische Sprachen basieren auf anderen Konzepten als indianische Sprachen und damit sind

andere Vorstellungen von der Welt verbunden (z. B. Zeit als Pfeil versus Zyklus).

(15)

1.1.3 Motivation: Kenntnis mehrere Paradigmen

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

Wittgenstein)

Gr ¨unde, warum man mehrere Paradigmen/Sprachen kennen sollte:

Gr¨oßeres Repertoire an Ausdrucksm ¨oglichkeiten

Sprache beschr ¨ankt nicht nur was wir formulieren, sondern auch, was wir denken k ¨onnen(Whorf, Language, Thought, and Reality, 1956)

Die Sprache, in der Programme entwickelt werden, beschr ¨ankt die m ¨oglichen Kontrollstrukturen, Datenstrukturen und Abstraktionen, die verwendet werden k ¨onnen. Damit ist auch die Bandbreite der realisierbaren Algorithmen beschr ¨ankt.

Zum Teil k ¨onnen Konzepte einer Sprachklasse in einer anderen simuliert werden. Aber: Es ist immer besser, die Konzepte der Sprache, in der man arbeitet, voll auszunutzen, als nicht gut unterst ¨utzte Konzepte zu simulieren (weniger elegant, weniger effizient).

Hintergrund f ¨ur geeignete Sprachwahl

Die Kenntnis einer gr ¨oßeren Menge von Sprachen aus verschiedenen Paradigmen erlaubt es, f ¨ur ein gegebenes Problem die geignetste Sprache zu w ¨ahlen.

Bessere Voraussetzung um neue Sprachen zu lernen

Programmierer mit wenig formaler Ausbildung lernen h ¨aufig nur ein oder zwei Sprachen. Ist die Ausbildung zudem an der Syntax der Sprache und nicht an den Konzepten orientiert, ist es nur schwer m ¨oglich, sich schnell in neue Sprachen einzuarbeiten.

Kenntnis des Vokabulars und der Konzepte von Programmiersprachen ist Voraussetzung, um Sprachdokumentationen verstehen zu k ¨onnen.

Verst¨andnis von Implementations-Details

Wenn man etwas dar ¨uber weiss, wie eine Sprache entworfen und implementiert ist, kann man die Sprache oft intelligenter, ihrem Design entsprechend, nutzen. Man wird ein besserer Programmierer, wenn man versteht, warum bestimmte Konstrukte in einer Sprache realisiert wurden und was die Konsequenzen davon sind.

Verst ¨andnis dar ¨uber, wie Programme ausgef ¨uhrt werden, kann die Fehlervermeidung, -erkennung und -beseitigung erleichtern und hilft oft, Programme effizienter zu realisieren.

(16)

Voraussetzung f ¨ur Sprachentwicklung

Die Entwicklung neuer Allzweck-Programmiersprachen kommt nicht allzu h ¨aufig vor, und es arbeitet nur eine relativ kleine Gruppe von Informatikern in der Sprachentwicklung.

Aber: Viele Programmierer werden ab und zu kleine Sprachen f ¨ur spezielle Anwendungen entwerfen.

Allgemeine Entwicklung von Programmiersprachen

Nicht immer ist die popul ¨arste Sprache die beste Sprache. Wenn

diejenigen, die sich f ¨ur die Verwendung einer Sprache entscheiden, besser informiert sind, k ¨onnen sich gute Sprachen vielleicht besser/schneller durchsetzen.

1.2 Prozeduren und Parameter ¨ubergabe-Mechanismen

1.2.1 Programmstruktur bei imperativen Sprachen

In objekt-orientierten Sprachen sind Klassen/Objekte die kleinsten autonomen Bausteine.

In imperativen Sprachen gliedert sich ein Programm dagegen in einen Deklarationsblock (Typdefinitionen, globale Variablen und

Konstanten),

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 Java sind Prozeduren benannt ( Rekursion als Kontrollstruktur m ¨oglich).

Prozeduren bestehen aus einem Kopf und einem Rumpf.

Der Kopf besteht aus einem Schl ¨usselwort (z.B.PROCEDURE), einem

benutzerdefinierten, m ¨oglichst vielsagenden Namen (z.B.ReadMaxIndex), einer Folge von (0 bis beliebig vielen) formalen Parametern, und m ¨oglicherweise einem Ergebnistyp (Funktion). (vgl. Java Methoden mit R ¨uckgabetyp bzw.

void).

Wie bei Java-Methoden k ¨onnen im Rumpf lokale Variablen und Konstanten deklariert werden. Die Berechnungsvorschrift wird als Folge von Anweisungen angegeben.

(17)

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 *) BEGIN

x:=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 *) BEGIN

WriteString(" "); (* 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 END

END WriteGGTs;

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

IF ReadMaxIndex(maxindex) THEN WriteGGTs(maxindex) ELSE

WriteString("falsche Eingabe");

WriteLn END

END ggt.

Abbildung 2: Modula-2 Programm zur Berechnung des ggT

(18)

1.2.3 Parameter ¨ubergabe-Methoden

Formale Parameter werden im Kopf einer Prozedur angegeben. Im Rumpf tauchen sie in Anweisungen auf.

Formale Parameter sind Platzhalter f ¨ur konkrete Parameter, die beim Prozeduraufruf ¨ubergeben werden.

Parameter ¨ubergabe meint das Matching der konkreten mit den formalen Parametern.

Es gibt verschiedene Parameter ¨ubergabe-Methoden:

– Call-by-value: Argumente werden zun ¨achst ausgewertet. Die resultierenden Werte werden dann ¨ubergeben. Zuweisungen an die Parameter innerhalb der Prozedur haben keine Auswirkung auf die im aufrufenden Kontext vorhandenen Variablen. (Man spricht auch von strict evaluation.)

Beim AufrufggT(line, columnn)in der ProzedurWriteGGTswerden zun ¨achstlineundcolumndurch die aktuellen Werte dieser Variablen ersetzt. Mit diesen Werten werden dann die Parameter vonggT–arg1, arg2– initialisiert.

– Call-by-reference: Die Referenz (Adresse) der Argument-Variablen wird an die Prozedur ¨ubergeben. Ausf ¨uhrung der Prozedur kann Seiteneffekte auf die Werte der Argumente im aufrufenden Kontext haben.

Im Modula-2-Programm in Abb. 2 istmaxindex ein call-by-reference Parameter.maxindexwird in der ProzedurReadMaxIndexbelegt. Wird die ProdzedurWriteGGTsaufgerufen, so hatmaxindexden in

ReadMaxIndexermitteltend Wert.

– Call-by-name: Argumentausdr ¨ucke werden unausgewertet (als Referenz auf Code, der den Wert des Arguments liefert, zusammen mit einer

Umgebung f ¨ur die Werte von freien Variablen) ¨ubergeben. (lazy evaluation) Um Mehrfachauswertung zu vermeiden, wird ¨ublicherweise mit

Graphreduktionsmethoden gearbeitet (call-by-need).

Call-by-name wurde im Rahmen von Algol-60 entwickelt und wird heute vor allem bei funktionalen Sprachen verwendet. Vorteile: Termination bei

unendlichen Datenstrukturen (lazy lists) und Rekursion.

(19)

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;

BEGIN a := 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 vonzero(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 vonzero(sqr(sqr(sqr(2))))mit call-by-name:

direkt R ¨uckgabe von 0.

(20)

Aber (ohne Graphreduktion) resultiert unn ¨otige Mehrfachberechnung:

sqr(sqr(sqr(2)))

...

1.2.6 Call-by-value in Java

In Sprachen wie Modula und ! existieren sowohl call-by-value als auch call-by-reference als Parameter ¨ubergabe-Mechanismen.

Call-by-reference macht auch dann Sinn, wenn die Parameterwerte nicht innnerhalb der Prozedur ge ¨andert werden sollen: Speicherersparnis und Effizienz (z.B. f ¨ur die ¨Ubergabe von Arrays entf ¨allt Kopieren)

In Java existiert call-by-value als einziger Parameter ¨ubergabe-Mechanismus.

Meist liest man Aussagen wie “primitive types are passed by value, but objects are passed by reference”, die Verwirrung stiften k ¨onnen.

Auch wenn Objekte nat ¨urlich als Referenzen ¨ubergeben werden, ist der Parameter ¨ubergabe-Mechanismus call-by-value!

Das ProgrammPassByValue“missbraucht” die KlasseButtonaus java.awtetwas: genutzt wird nur das Feldlabel.

// 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 value Button 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 well int i = 5;

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

methodZ(i);

System.out.println("Back in main");

(21)

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

System.exit(0);

}

//the reference to an object is passed by value public 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 to y.setLabel("BBB");

System.out.println("The value of y’s label is " + y.getLabel());

//make y reference a different object - doesn’t affect variable b y = 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 b y.setLabel("DDD");

System.out.println("The value of y’s label is " + y.getLabel());

}

//primitives are passed by value as well public 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 main j = 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

(22)

Button Object b

y

Button Object b

Button Object Another y

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

1.3 Sprach-Implementierung

EinProgramm(Code, Quellcode) wird geschrieben, um Aufgaben automatisch von einem Rechner ausf ¨uhren zu lassen.

Ublicherweise wird ein Programm gestartet, erh ¨alt eine Eingabe, f ¨uhrt¨

Berechnungen in Abh ¨angigkeit von dieser Eingabe durch, liefert eine Ausgabe und wird beendet. (Programmausf ¨uhrung)

DieLaufzeit des Programms meint die Zeit vom Aufruf bis zur Termination; die Compilezeitmeint die Zeit, w ¨ahrend das Programm in Maschinen- oder

Zwischencode ¨uberf ¨uhrt wird.

In anderem Zusammenhang meint Laufzeit auch die Zeitdauer, die zur Ausf ¨uhrung eines Programms ben ¨otigt wird: Diese ist abh ¨angig von der Maschine und insbesondere von der Aufwandsklasse der zugrundeliegenden Algorithmen. (Die Komplexit ¨at von Problemen, die gel ¨ost werden sollen, bedingt die untere Schranke des Aufwands von Algorithmen. Thema in der Vorlesung

“Theoretische Informatik”)

EinCompiler ¨ubersetzt ein Programm in eine Ausgabesprache (h ¨aufig Maschinencode). Beispiele f ¨ur Compilersprachen sind C und Pascal. (siehe Abb. 5)

EinInterpreterist eine Maschine auf h ¨oherer Ebene, die das Programm direkt ausf ¨uhrt. Beispiele f ¨ur Interpretersprachen sind Common Lisp und Prolog.

(siehe Abb. 5)

Alternativ gibt es hybride Implementationssysteme: Das Programm wird zun ¨achst in einen Zwischencode (Bytecode) ¨ubersetzt, der auf beliebige Maschinen portierbar ist, f ¨ur die ein entsprechender Bytecode-Interpreter und dazugeh ¨origes Laufzeitsystem existiert. Beispielsweise erzeugt der

(23)

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

ÜBERSETZZEITLAUFZEIT

Maschinencode Maschine Eingabe

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

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

Arbeitsschritte eines Compilers:

Lexikalische Analyse: Zerlegung des Programmtextes in lexikalische Einheiten (Reservierte Worte, Operatoren, Identifier; Kommentare werden ignoriert)

Syntaktische Analyse (Parsierung): Erzeugung eines Parse-Baums, der die syntaktische Struktur des Programms repr ¨asentiert.

Semantische Analyse: ¨ublicherweise Typisierung

Zwischencode-Erzeugung (wenn ohne Optimierungsoption, z. B.

Assembler)

Optimierung (optional): Methoden der Programmtransformation, partielle Evaluation (Ersetzen von Ausdr ¨ucken durch ihr Ergebnis)

Codegenerierung: ¨aquivalentes Maschinencode-Programm

Symboltabelle: Datenbasis f ¨ur die Compilierung, enth ¨alt insbesondere Typen und Eigenschaften der benutzergenerierten Namen im Programm.

Vor der Ausf ¨uhrung m ¨ussen noch die entsprechenden Programme des Betriebssystems und eventuell Bibliotheksfunktionen mit dem

Maschinenprogramm verbunden werden (linking, Einf ¨ugen der entsprechenden Adressen in das Maschinencode-Programm).

Ausf ¨uhrung: In fetch-execute-Zyklen: Jede Maschineninstruktion muss vom Speicher in den Prozessor ¨ubertragen werden und Ergebnisse/Verweise

(24)

m ¨ussen in den Speicher zur ¨uckgeschrieben werden. (von-Neumann Flaschenhals)

1.4 Syntaktische Struktur

1.4.1 Formale Sprachen

Die Syntax einer Sprache legt fest, wie einzelne Symbole zu gr ¨oßeren Strukturen zusammengef ¨ugt werden d ¨urfen.

Die Syntax einer Sprache wird – f ¨ur nat ¨urliche wie f ¨ur formale Sprachen – durch eine Grammatik beschrieben: mit

als Menge der Nonterminal-Symbole als Menge der Terminalsymbole

als Menge der Grammatikregeln (Produktionen) und als Startsymbol.

Beispiel (einfacher Ausschnitt des Englischen)

! "#$%&')(&*"+-,.0/1+-2 #&#(&304)( 656 " mit :

7

8 (noun phrase)

7

:9; (verbal phrase)

$% (determiner)

')(&<9*"+-,9=/1+=2 # (noun)

#(&>9=4( &5 (verb)

Es k ¨onnen syntaktisch korrekte (aber nicht unbedingt semantisch sinnnvolle) S ¨atze abgeleitet werden, wie “the mouse eats the cat”.

Beispiel: ?A@BC> "D=EFHG6 " mit :

E6@I9JG#C

@

GK9JG-

C

E9E3

beschreibt eine einfache Sprache ¨uber dem Alphabet =EFHG .

Mit den Regeln aus kann eine unendliche Menge von Worten generiert werden, die zu dieser Sprache geh ¨oren.

F ¨ur nat ¨urliche Sprachen geben Grammatiken meist an, wie korrekte S ¨atze aus Worten geformt werden. F ¨ur Programmiersprachen geben Grammatiken an, wie Programme als wohlgeformte Ausdr ¨ucke ¨uber Schl ¨usselw ¨ortern und

Bezeichnern konstruiert werden. Eine formale Sprache wird als die Menge der wohlgeformten Worte ¨uber einem endlichen Alphabet definiert.

Worte, die zu obiger Sprache geh ¨oren, sind 01, 10, 0101, 0110, 1010, 1001. Die Konstruktion der Wortmenge kann mit einem Ableitungsbaum dargestellt

werden (siehe Abb. 6).

(25)

S

1B

01S

0101S 0110S 1001S 1010S

010A 011B 100A 101B

0A

10S

01 10

0101 0110 1001 1010

Abbildung 6: Ableitungsbaum f¨ur die einfache regul¨are Sprache EFG GHE

Die Sprache ist regul¨arund kann durch den regul ¨aren Ausdruck EFG G#E

dargestellt werden. bezeichnet ,

bezeichnet die positive H ¨ulle (Menge aller Konkatenationen von Elementen aus ohne das leere Wort), bezeichnet die Kleene’sche H ¨ulle.)

Regul ¨are Sprachen sind die einfachsten Sprachen in der sogenanntenChomsky Hierarchie. Sie k ¨onnen durch endliche Automaten erkannt werden.

Programmiersprachen sind im Wesentlichenn kontextfreie Sprachen.

Kontextfreie Sprachen folgen in der Chomsky-Hierarchie auf die regul ¨aren.

W ¨ahrend Grammatikregeln f ¨ur regul ¨are Sprachen links- bzw. rechts-linear sind ( (J bzw. ( ), sind bei kontextfreien Sprachen beliebige

Kombinationen aus Terminal- und Nonterminalsymbolen erlaubt.

Beispiel: J E3 G& EFG beschreibt die SpracheE FG , also1E -en gefolgt von genauso vielen G -en.

Die Kenntnis formaler Sprachen ist wichtig f ¨ur die Implementierung von Programmiersprachen. Das Sprachdesign (die Grammatik) bedingt wie

aufwendig 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 ::= K ¨orper.

Nichtterminale werden in spitzen Klammern dargestellt, dadurch k ¨onnen auch ganze W ¨orter statt nur einzelne Symbole als Nonterminale verwendet werden.

Alternative rechte Seiten werden durch einen senkrechten Strich getrennt dargestellt.

(26)

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 haben den geringsten Vorrang.

In der EBNF sind zus ¨atzlich folgende Abk ¨urzungen eingef ¨uhrt: eckige Klammern ([ ]) umschliessen Symbolfolgen, die null oder einmal auftreten d ¨urfen;

geschweifte Klammern (7 ) umschliessen Symbolfolgen, die beliebig oft (auch null-mal) vorkommen d ¨urfen.

Anschaulich stellt man BNF durchSyntaxdiagrammedar.

Java in EBNF findet sich unter: http:

//cui.unige.ch/db-research/Enseignement/analyseinfo/JAVA/

Beispiele sind in Abb. 7 angegeben. (Hier werden Terminalsymbole in Anf ¨uhrungszeichen angegeben und Nonterminale erscheinen ohne spitze Klammern.)

Die eindeutige und vollst ¨andige Beschreibung der Syntax einer

(27)

else S2 S

E2 then S1

if

E1 then

S

if if

else S2

E1 then

S

S

E2 then S1

if

Abbildung 8: ‘Danglinge-else’ Uneindeutigkeit

Programmiersprache ist wichtig f ¨ur den Programmierer, um syntaktisch korrekte Programme zu schreiben, und Grundlage f ¨ur den Parser.

Ein Parser ist einAkzeptor f ¨ur einen Programmtext. Ein syntaktisch korrektes Programm wird ein einen Syntaxbaum ¨uberf ¨uhrt. Ein guter Parser gibt

informative Fehlermeldungen, falls das Programm nicht der Grammatik der Programmiersprache gen ¨ugt.

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

Wenn Uneindeutigkeiten existieren, werden sie durch Konventionen aufgel ¨ost.

Beispiel: “dangling-else ambiguity”

$% #

entspricht den Alternativen:

$%

$% -

Zu welchem if geh ¨ort das else?

if E1 then if E2 then S1 else S2 (Parse-B ¨aume siehe Abb. 8)

Typische Aufl ¨osung: Matche else mit dem am n ¨achsten stehenden noch ungematchten if. Die Kenntnis entsprechender Konventionen sind Voraussetzung f ¨ur die Vermeidung von Programmierfehlern!

1.5 Semantik und Pragmatik

Die formale Beschreibung der Syntax einer Programmiersprache ist relativ leicht nachvollziehbar.

Ublicherweise verbinden wir durch die Wahl der Schl ¨usselworte bereits eine¨ (intuitive und nicht immer zutreffende) Bedeutung mit den Sprachkonstrukten.

Aber: Dem Parser ist es v ¨ollig egal, ob im Programm “for” oder “bla” steht, solange er die entsprechende Regel in der Grammatik finden kann!

Es ist w ¨unschenswert, dass die Semantik einer Sprache genauso eindeutig und pr ¨azise beschrieben wird wie die Syntax.

(28)

Nur f ¨ur wenige Sprachen ist jedoch eine formale Semantik angegeben (z.B. f ¨ur die funktionale Sprache ML). Meistens (z.B. bei Java) wird die Bedeutung der Sprachkonstrukte informell nat ¨urlichsprachig beschrieben.

F ¨ur voll durchformalisierte Sprachen ist es m ¨oglich, Korrektheitsbeweise

wenigstens zum Teil automatisch durchzuf ¨uhren (Spezifikationssprachen wie ).

Verschiedene M ¨oglichkeiten, die Semantik einer Sprache formal anzugeben:

(siehe Vorlesung “Theoretische Informatik”, Thema Algebraische Spezifikation) Operationale Semantik: Regeln, nach denen Ausdr ¨ucke ausgewertet

werden (Reduktionssemantik).

Denotationale Semantik: Interpretation der Sprachkonstrukte in eine

“bekannte” Sprache (z.B. Algebra).

Axiomatische Semantik: Angabe von Gesetzen und Regeln (Hoare Kalk ¨ul).

Sp ¨ater wird f ¨ur einen kleinen Ausschnitt von Java (“Featherweight Java”) die formale Semantik dargestellt. Beweis von Typsicherheit

Die Pragmatik einer Sprache beschreibt, wie die Konstrukte einer Sprache sinnvoll eingesetzt werden.

(Entscheidung, ob eine pre-check-loop (while) oder eine post-check-loop (do-while) verwendet werden soll; Entscheidung zwischen Schleife und rekursiver L ¨osung.)

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

(29)

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 “m ¨achtige Daten”. Sie halten Daten und k ¨onnen Operationen auf ihren eigenen Daten ausf ¨uhren. Der “Datentyp” eines Objekts ist die Klasse mit der es erzeugt wurde.

Beispiel: Objekt circlevom TypCirclekann seinen Fl ¨acheninhalt berechnen.

Anmerkung: In Java ist im Gegensatz zu Smalltalk nicht alles ein Objekt (primitive Datentypen).

Ein Programm ist eine Menge interagierender Objekte: Ein Objekt kann Botschaften an ein anderes Objekt schicken, z.B. eine Aufforderung, eine bestimmte Methode auszuf ¨uhren.

Objekte k¨onnen zu komplexen Objekten kombiniert werden: Komplexe Objekte k ¨onnen aus einfachen Bausteinen aufgebaut werden, indem Objekte

Referenzen auf andere Objekte enthalten.

Alle Objekte eines Typs k¨onnen dieselben Botschaften erhalten: Dies wird vor allem im Hinblick auf Klassenhierarchien interessant. Jedescircle-Objekt kann alle Methoden ausf ¨uhren, die in derCircleKlasse definiert sind. Ist Circleein speziellerShape, so k ¨onnen auch (nicht- ¨uberschriebene) Shape-Methoden ausgef ¨uhrt werden.

2.1.2 Prinzipien der Objekt-Orientierten Programmierung

Zwei wesentliche Prinzipien der objekt-orientierten Programmierung sind

Kapslung(Encapsulation) und

Wiederverwendbarkeit(reuse).

Zur Kapslung geh ¨ort die Organisation von Daten und Methoden in Klassen sowie das Verstecken von Implementierungsdetails(information hiding).

Kapslung ist in mehrfacher Hinsicht guter Programmierstil:

Das Problem wird in kleinere, unabh ¨angige Komponenten gegliedert und ist damit leichter zu ¨uberschauen, leichter zu testen und weniger fehleranf ¨allig.

Das Verstecken von Implementationsdetails erlaubt eine bessere

Austausch von Code. Beispielsweise ist es notwendig zu wissen, dass die eine KlasseTree eine Methodeinsertanbietet, aber nicht, wieinsert genau realisiert ist (z.B. wie gew ¨ahrleistet wird, dass der Baum

ausgewogen ist).

(30)

Schr ¨ankt man zudem die Zugriffsrechte f ¨ur Felder ein (z.B. private Felder mit public Zugriffsmethoden) kann man unerw ¨unscht Seiteneffekte

vermeiden, wie etwa, dass ein zu einer anderen Klasse geh ¨origes Objekt ein Feld unkontrolliert ¨andert und m ¨oglicherweise Inkonsistenzen erzeugt.

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

Wiederverwendbarkeit ist m ¨oglich, weil Klassen unabh ¨angig von konkreten Daten definierbar sind. Aussderdem k ¨onnen bereits definierte Klassen durch Vererbungf ¨ur spezielle Bed ¨urfnisse angepasst werden. Generell sollte Code so geschrieben und dokumentiert werden, dass die Funktionalit ¨at der Klasse transparent ist und so Wiederverwendbarkeit (in eigenen Projekten oder Nutzung durch andere) erleichtert wird.

Java bietet eine Menge vordefinierter Klassen an (Java APIs). Es ist guter Stil, diese (gut getesteten, bew ¨ahrten) 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 urspr ¨unglich im Rahmen von Lisp entwickelt wurden. (Guy Steele, der aus dem Bereich Common Lisp bekannt ist, ist bei Sun mitverantwortlich f ¨ur die Entwicklung der Java Sprachspezifikation!)

Ziel: Entwicklung einer Hochsprache f ¨ur hybride Systeme im Consumer-Electronic Bereich: Steuerung von Waschmaschinen, Telefonanlagen, ... ( urspr ¨unglicher Name “Oak”)

Boom des WWW 1993 Einsatz f ¨ur Internet-Anwendungen

Java-Applets: kleine Programme, die in HTML-Seiten eingebunden werden k ¨onnen (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) bezeichnen Versionen mit vielen neuen Features; Java 1.1, 1.2, 1.3, 1.4 bezeichnet Versionen mit einigen neuen Features; von Java 1.2 zu 1.3 vor allem

Geschwindigkeitsverbesserungen; Java 1.1.3 und andere dreistellige Nummern bezeichnen in kleineren Details verschiedene Implementierungen einer Version (“minor releases”).

(31)

Tabelle 1: Java Versionen Version # Klassen # Pakete Ersch. Anmerkungen

1.0 212 8 Jan. 1996

1.1 504 23 Feb. 1997

1.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 2977 135 Feb. 2002 (1.4.0)

2.2.2 Java Buzzwords

Portabel: JVM (virtuelle Maschine ist bew ¨ahrtes Prinzip); alle Datentypen sind unabh ¨angig von der Implementierung festgelegt (Standards)

Objekt-Orientiert: Kapslung in Klassen, Vererbung

Multithreaded: Zerlegung in einzelne “Prozesse” (Threads), die unabh ¨angig voneinander ablaufen k ¨onnen

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

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

Sicher: Plattform erlaubt Laden von unbekanntem Code, der in einer sicheren Umgebung abl ¨auft (kein Lesen und Schreiben von Festplatte, ...)

Dynamisch, Erweiterbar: Organisation des Programmcodes in Klassen, in verschiedenen 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:*.classDatei(en)

Das Kommando javacerlaubt verschiedene Optionen, wie:

-classpath path: Liste von Verzeichnissen, in denen nach weiteren im Quellcode benutzten Klassen gesucht wird. (default: aktuelles Verzeichnis)

-d directory: Verzeichnis, in dem die erzeugten class-Dateien abgelegt werden . (default: Verzeichnis der*.javaDateien)

(32)

-verbose: Ausgaben des Compilers

In einer Datei*.javak ¨onnen mehrere top-level Klassen definiert werden.

Maximal eine davon darfpublicsein.

F ¨ur jede der Klassen wird bei ¨Ubersetzung eine eigene*.classDatei erzeugt.

Java Virtual Machine (JVM):

Kann in Hardware oder Software realisiert sein ( ¨ublicherw. in Software) Interpretation und Ausf ¨uhrung des Byte-Codes; JVM f ¨ur Solaris, Microsoft

Windows, Linux, ...

Interpretersprachen sind meist langsam, ¨ubliche Technik just-in-time Compilierung, Java: Byte-Code wird in die Maschinensprache der gegebenen Plattform ¨ubersetzt (gute Ausf ¨uhrungsgeschwindigkeit f ¨ur Code, der mehrfach ausgef ¨uhrt wird)

Ausf ¨uhrung des Bytecodes Klassenname.class mit java Klassenname.

Die entsprechende Klasse muss eine Methodemain()mit folgender Signatur enthalten:public static void main(String[] args).

Diese Methode ist der Einstiegspunkt ins Programm: hier beginnt der Interpreter die Ausf ¨uhrung. Das Programm l ¨auft so lange, bis die main Methode (und evtl. erzeugte Threads) verlassen werden.

Das Kommando javaerlaubt verschiedene Optionen, wie:

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

-Dpropertyname=value: Setzt eine Property mit Namen propertyname auf den Wert value. Im Java-Programm k ¨onnen Properties dann abgefragt werden.

Hinter dem Klassennamen k ¨onnen Daten angegeben werden, die an String[] argsweitergegeben werden.

Java Plattform:

Vordefinierte Menge von Java Klassen, die auf jeder Java Installation vorhanden sind und von allen Java Programmen genutzt werden k ¨onnen Klassen sind in Paketen organisiert (Input/Output, Graphik,

Netzwerkfunktionen, ...)

Auch Java Runtime Environment oder Java APIs (Application Programming Interface) genannt.

(33)

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 Dame eine andere schlagen kann.

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

L ¨osung(en) f ¨ur das 4-Damen Problem:

1 2 3 4

2 1

4 3

2

4 3

1

1 2 3 4

Allgemein: Problem ( Damen auf Brett) Keine L ¨osung f ¨ur .

Standard-Beispiel f ¨ur generate and test Algorithmen (backtracking) Aufwand:

naiv: 8 aus 64 (Binomialkoeffizient ¨uber )

5

5-5

f ¨ur : 4.426.165.368

in jeder Spalte nur eine Dame:

f ¨ur : 16.777.216

in keine Spalte die gleiche Position:

f ¨ur : 40320

Problem mit exponentieller Komplexit ¨at!

Es kann keinen vollst ¨andigen Algorithmus geben, der das Problem effizient l ¨ost.

Verwendung von heuristischen Suchverfahren bzw.

Constraint-Erf ¨ullungstechniken (K ¨unstliche Intelligenz).

Komplexit ¨at von Problemen wird in der Vorlesung Theoretische Informatik behandelt

Aktuelle Literatur zum -Damen Problem:

http://www.liacs.nl/˜kosters/nqueens.html

(34)

2

aufw.

abw.

4 3

1

1 2 3 4

testRow testColumn colDif upRowDif downRowDif testRow - row row - testRow

1 1 -2 -2 2

1 2 -1 -2 2

1 3 0 -2 2

1 4 1 -2 2

. . . .

4 1 -2 1 -1

4 2 -1 1 -1

4 3 0 1 -1

4 4 1 1 -1

Abbildung 9: Bedrohte Diagonalen Sequenz der Anzahl von L ¨osungen:

1,0,0,2,10,4,40,92,352,724,2680,14200,73712,365596,2279184, 14772512,95815104,666090624,4968057848,39029188884, 314666222712,2691008701644,24233937684440

eine kompakte Formel wurde bisher nicht gefunden (siehe

http://mathworld.wolfram.com/QueensProblem.html) 2.3.2 Identifikation von Schlagstellungen

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

die Zeile row

die Aufw ¨artsdiagonale (testColumn column) (testRow - row) die Abw ¨artsdiagonale (testColumn column) (row testRow) Erl ¨auterung: Diagonalen haben eine Steigung von G (aufw ¨arts) bzw. G (abw ¨arts). Das heisst, Spaltendifferenz (Waagerechte) und Zeilendifferenz (Senkrechte) sind identisch.

Beispiel f ¨ur row 3 und column 3 in Abb. 9 Bedrohung auf Diagonalen existiert also, wenn:

row (testColumn column) testrow oder row (testColumn column) testrow

(35)

Da beidesmal die Spaltendifferenz ben ¨otigt wird, kann diese auch vorab berechnet werden.

siehe Methode predecCanAttack()

Die von einer Dame bedrohten Positionen k ¨onnen global in entsprechende boolesche Arrays eingetragen werden. Alternativ zum Eintragen und

Durchmustern der Arrays k ¨onnen die bedrohten Stellungen auch jeweils f ¨ur jede Dame gepr ¨uft werden.

2.3.3 Imperative L¨osung

Im folgenden geben wir Programme zum Finden einer g ¨ultigen L ¨osung an.

(Alternativ: Finden aller g ¨ultigen L ¨osungen )

Die Anzahl von Queens (MAX) wird als Property ¨uber die Option vonjava gesetzt. Default ist 8.

Globale Kontrolle:In dermain()Methode wird ein Arrayqueens[]

spaltenweise mit einer legalen Zeilenposition f ¨ur die aktuelle Dame belegt.

Existiert f ¨ur eine Dame keine legale Position wird die bisherige L ¨osung zur ¨uckgenommen (die Vorg ¨angerdame, evtl. deren Vorg ¨anger, etc.) backtracking

public class QueensIM {

final static int MAX = Integer.getInteger("MAX", 8).intValue();

// Current row for queens at columns 0..MAX-1

final 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 function static 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 position static boolean predecCanAttack(int row, int column,

int testRow, int testColumn) { // Case 1: current Queen can attack

int columnDifference = testColumn - column;

if ((row == testRow) || // same row

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

(36)

// 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 ok return false;

}

// Prints the position of all queens via loop through the array static 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 conflict public 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 queen advance(i); // advance current queen one row

System.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 index

i--; // backtrack

} else i++;

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

} }

2.3.4 Objekt-Orientierte L ¨osung

Statt einer Klasse mit der Kontrolle in dermain()Methode wird nun eine KlasseQueendefiniert: Jede Dame kennt ihre eigene Position und kann sich selbst verschieben.

Dazu existiert eine Dame, die ihre direkte Nachbarin kennt, als Unterklasse von Queen. Sie kann pr ¨ufen, ob sie mit dieser in Konflikt steht, sowie diese

“anschubsen”.

(37)

public class QueensOO {

// Number of Queens set as property

public 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 unchangable protected final int column;

// Initializes a new Queen object.

public Queen (int c) {

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

}

// A single Queen is always at a conflict free position.

public boolean findSolution() { return true;

}

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

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

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

}

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

// current Queen can attack

(38)

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 Queen public void printSolution() {

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

} }

class NeighborQueen extends Queen { // data fields

// immediate left neighbor of a Queen protected final Queen neighbor;

// Initializes a new NeighborQueen object public 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 predecessors public void printSolution() {

neighbor.printSolution();

super.printSolution();

} }

Abbildung

Abbildung 1: Entwicklung von h¨oheren Programmiersprachen
Abbildung 4: Call-by-Value in Java (siehe Klasse PassByValue)
tabelle Semantische Analyse Zwischencode−ErzeugungSyntaxanalyse (Optimierung)CompilerÜBERSETZZEIT LAUFZEIT MaschinencodeMaschineEingabe
Abbildung 6: Ableitungsbaum f¨ur die einfache regul¨are Sprache  EFG  GHE
+7

Referenzen

ÄHNLICHE DOKUMENTE

If a run-time value is a reference that is not null, it refers to an object or array that has a class, and that class will necessarily be compatible with the compile-time type..

§9: An interface declaration introduces a new reference type whose members are classes, interfaces, constants and abstract methods.. ] classes can implement it by

§8.1.3: The optional extends clause in a class declaration specifies the direct superclass of the current class.. A class is said to be a direct subclass of the class

⇒ Ben¨ otigte Konversion wird als Property exp_conv festgehalten. 3 Typcheck stellt sicher: Zur Laufzeit wird erlaubter Wert

• Virtuelle Tabelle enth¨ alt Zeiger auf Funktionen. • (Parametertypen sind ausgelassen, um sp¨ ater Warnungen

] The value of a class instance creation expression is a reference to the newly created object of the specified class.. : Instanziierung besteht eigentlich aus

public void shapeChange(Drawing list, Shape obj) { DefaultListModel m = (DefaultListModel)getModel();. int i

• Korrektheit eine Anweisung: Wenn vor Ausf¨ uhrung der Anweisung die Vorbedingung galt, dann muß die Anweisung die Nachbedinung sicherstellen. • Vorbedingung = Voraussetzung f¨