Upload
alphaprime
View
81
Download
0
Embed Size (px)
Citation preview
5
Ziele der Vorlesung Programmierung
Kontext: Programmierung im Software-Entwicklungsprozess
Grundlegende objektorientierte Konzepte
Programmieren in Java
Neugier auf weiterführende Java-Themen
6
Anforderungen an die Beteiligten
Dozent:Vermitteln des Stoffes in angemessenem TempoGratwanderung zwischen Breite und TiefeAusgleich der unterschiedlichen VorkenntnisseBlick über den Vorlesungstellerrand
Übungsorganisatoren / Tutoren:Vertiefen der Vorlesungsinhalte durch ÜbungenEinführung in die praktische Nutzung einerProgrammierspracheLernhilfen und zusätzliche Herausforderungen
7
Anforderungen an die Beteiligten
Studierende:eigenständige NachbearbeitungAuseinandersetzung mit Primär- und SekundärliteraturTeilnahme an der Vorlesung und an den ÜbungenÜberwinden der Praxisschwelle
vorbelastete Studierende (also die, die meinen sie könnten Javaund/oder programmieren):darauf achten, dass der geeignete Einsprungpunkt nichtverpasst wird!
8
Hinweise zum Feedback
Mehrfache Abfrage Ihres Feedbacks und direkte Veröffentlichungder Ergebnisse
Versuch der Umsetzung der erkanntenVerbesserungsmaßnahmen
Interaktives Feedback jederzeit willkommen!
9
Hinweise zu MaterialienFolienskrip wird zur Verfügung gestellt, einige Teile werden in der
Vorlesung entwickelt!
Zu allen fehlenden Teilen wird auf Literatur verwiesen.
Folien sind Stichpunkte! Es gilt das gesprochene Wort!Übungenoptionale Abschnitte
Hilfreich: Anmerkungen in den Folien und handschriftlicheErgänzungen (-> aktive Teilnahme)
10
Literatur
• Originalliteratur von JavaSoft
http://www.javasoft.com/docs/index.html
• Sonstige Literatur
11
Literatur von JavaSoft
• The Java Tutorial– Als Online- und Downloadversion– Als Buchversion in deutsch und englisch (meist nicht so aktuell)– Sehr umfangreich, ausführliche Beschreibung vieler Aspekte der
Sprache und Einführung in den Umgang mit Klassenbibliotheken– Gesamtübersicht der Klassenbibliotheken liefert
"JDK 1.2 Documentation“/Java 2 SDK, SE v1.3 Documentation– Für exakte Syntaxdefinition der Sprache ist die "Java Language
Specification" gedacht.– Es ist kein Programmierlehrbuch.
12
Literatur von JavaSoft
• JDK 1.2 /Java 2 SDK, SE v1.3 Documentation– Als Online- und Downloadversion– Gesamtbeschreibung der Klassenbibliothek– Als Nachschlagewerk gedacht, kein Tutorial
• Java Language Specification– Als Online- und Downloadversion– Komplette Beschreibung der Syntax– Sehr schwer zu lesen– Syntaktische Feinheiten, die im Tutorial nicht deutlich werden
13
Literatur von JavaSoft
• Java Virtual Machine Specification– Spezifikation der virtuellen Maschine– Nur für Leute gedacht, die selbst Java-Compiler schreiben wollen– Wichtig, um offenen Standard zu gewährleisten (im Gegensatz zu vielen
Microsoft-Produkten)
• Java Developer Connection– http://www.javasoft.com/jdc– Kostenlose Anmeldung erforderlich– Viele Informationen über neueste Entwicklungen– Downloadmöglichkeit von Beta-Versionen
14
Sonstige Literatur
• "Einführung in die objektorientierte Programmierung mit Java"– Autoren: E.-E. Doberkat / S. Dißmann– Erschienen 1998 im Oldenbourg Verlag, München, ISBN 3-486-24786-7– Programmierlehrbuch, beschreibt verschiedene Programmiertechniken,
Begleitung zur Vorlesung an der Universität Dortmund
• "Java 1.1 lernen"– Autor: Guido Krüger– Erschienen bei Addison-Wesley-Longman 1997– Einführungsbuch, gut für erste Schritte– Keine erschöpfende Behandlung vieler Themen, nur erster Überblick– Nicht als Nachschlagewerk zu empfehlen
Inde
rU
ni-B
iblio
thek
verf
ügba
r!
15
Sonstige Literatur
• ”Thinking in Java”– Autor: Bruce Eckel– http://www..eckelobjects.com/javabook.html
16
Sonstige Literatur
• "Java in a nutshell"– Autor: David Flanagan, deutsche Übersetzung: Peter Klicman– Erschienen bei O'Reilly 1998– Lehrbuch für den Fortgeschritten– gut geeignet für C/C++ - Programmierer– Erschöpfende Klassenübersicht– Wichtige Details für die Praxis
• "Foundations of Computer Science”– Autor: Alfred V. Aho, Jeffrey D. Ullman– Erschienen bei W.H. Freeman and Company 1995– Grundlegende Konzepte und Datenstrukturen
17
Sonstige Literatur
• "Fundamentals of Software Engineering"– Autor: Carlo Ghezzi, Mehdi Jazayeri, Dino Mandrioli– Erschienen bei Prentice-Hall, 1991– guter Überblick über Software-Technologie und die Einbettung der
Programmierung
18
Gliederung der Vorlesung1 Vorwort und Zielsetzung2 Einordnung der Vorlesung “Programmierung”
2.1 Kontext Informatik2.2 Kontext Software-Entwicklung
3 Objektorientierte Analyse und objektorientierter Entwurf4 Grundbegriffe zu Programmiersprachen5 Java als objektorientierte Programmiersprache6 Ein erstes Java-Beispiel
19
Gliederung der Vorlesung
7 Java-Syntaxkonstrukte
7.1 Primitive Datentypen, Literale und Variablen7.2 Aufruf von Objekten, einfacher Nachrichtenaustausch7.3 Operatoren, Ausdrücke, Zuweisungen7.4 Anweisungen
8 Programmierkonventionen und Dokumentation9 Rekursive Methoden
10 Innere Klassen11 Elementare Java-Klassen
11.1 String11.2 Felder11.3 Object
20
Gliederung der Vorlesung12 Ähnliche Objekte (Vererbung)13 Schnittstellen (Interfaces)14 Ausnahmen (Exceptions)15 Pakete und Zugriffskontrolle16 Überblick über Java-Klassenbibliotheken17 Dynamische Datenstrukturen, ihre Anwendung und ihre
Realisierung mit Java17.1 Listen17.2 Bäume17.3 Graphen17.4 Schlangen17.5 Stapel17.6 Mengen
21
Gliederung der Vorlesung18 Ein- und Ausgabe (java.io)19 Graphische Oberflächen (java.awt, java.swing)20 Applets (java.applet)21Threads22 Rückblick, Ausblick, Fazit Kapitel 2
Einordnung der Vorlesung Programmierung
Kapitel 2.1
Kontext Informatik
24
Kontext Informatik
Informatik:keine Naturwissenschaft(noch?) keine Ingenieurwissenschaft
weil• bewährte Abstraktionen / Lösungsmuster fehlen• nicht einheitlich bezeichnet und verwendet werden• zuverlässige Planungen der Erstellung von Lösungen kaum möglich
sind
25
Aufteilung Informatik
Theoretische Informatik : allgemeingültige Berechnungsmodelle,Gesetzmäßigkeiten, zunächst: anwendungsunabhängig
Praktische Informatik : Anwendung der Ergebnisse undErkenntnisse der theoretischen Informatik auf Probleme derNutzbarmachung von Rechnern, Bau von Compilern, Entwurfvon Spezifikationssprachen
Angewandte Informatik : Anwendung der Ergebnisse dertheoretischen und praktischen Informatik zum Zweck derLösung real existierender Probleme, Ziel: Wirtschaftlichkeit
26
Kontext Informatik
Modellbildung und Abstraktion als durchgängig verwendetePrinzipien in der Informatik, z.B:
– von der realen Welt zur Beschreibung der relevanten Teile– von realen Problemen zu Entwürfen– von Entwürfen zu Programmen
Hierbei die immer gleiche Frage:Was gehört ins Modell?Was wird wegabstrahiert?
27
Kontext Informatik
Wahl der richtigen Abstraktion oft schon entscheidend fürden Erfolg der Entwicklung vonDatenverarbeitungslösungen!
Eine der wesentlichen Abstraktionen manifestiert sich inProgrammen. Hierin spiegelt sich die Entscheidung, bestimmteMerkmale der realen Welt als für den Problembereichaufzufassen und diese in bestimmter Weise abzubilden.
28
Kontext Informatik
Die Vorlesung „Programmierung“ beschäftigt sich mit der Frage,wie das Ergebnis der Abbildung (Programme) aussehen sollte.Hierbei wird angenommen, dass Klassen und Objekte diegrundlegenden Konstrukte sind, um Programme zurepräsentieren / zu strukturieren.
In der Vorlesung „Programmierung“ wird genau eine Sprache zurFormulierung von Programmen vermittelt. Diese Sprache heißtJava. Java ist objektorientiert.
Kapitel 2.2
Kontext Software-Entwicklung
30
Kontext Software-Entwicklung
Obwohl eine hohe volkswirtschaftliche und betriebswirtschaftlicheAbhängigkeit von Software besteht
– komplexe Software in allen Bereichen des Lebens– eingebettete Software in PKWs, Haushaltsgeräten– Steuerung in der Verkehrs- und Energietechnik– admininistrative Geschäftsprozesse in fast allen Unternehmen– Software-Kosten als substantieller Anteil in vielen IT-Etats (häufig:
Wartung)– Einfluß auf fast alle Innovationen
ist die Entwicklung von Software nach wie vor mit hohen Risikenbehaftet.
31
Anzahl Function Points Früher als geplant Termingerecht Verspätet Abgebrochen1 FP 14,86 % 83,16 % 1,92 % 0,25 %
10 FP 11,08 % 81,25 % 5,67 % 2,00 %100 FP 6,06 % 74,77 % 11,83 % 7,33 %
1.000 FP 1,24 % 60,76 % 17,67 % 20,33 %10.000 FP 0,14 % 28,03 % 23,83 % 48,00 %
100.000 FP 0,00 % 13,67 % 21,33 % 65,00 %Durchschnitt 5,53 % 56,94 % 13,71 % 23,82 %
Quelle: C. Jones, Large Software System Failures and Successes,in: American Programmer, Vol. 9, No. 5, September 1996
Abbruchrate von Software-Entwicklungsprojekten
32
Ursachen der Unzuverlässigkeit von Software-Entwicklung nach [CKI88]
B. Curtis, H. Krasner, N. Iscoe, A Field Study of the Software Design Process for Large Systems,Communications of the ACM, November 1988, Vol. 31, No. 11, pp 1268 - 1287
Thin Spread of Application Domain KnowledgeProjekte in neuer BrancheTechnologiezentriertheit
Fluctuating and Conflicting RequirementsMarktverschiedene Kunden
ErkenntnisprozesseMißverständnisse
Communication and Coordination Breakdownsunterschiedliche Vorstellungen und ZielsetzungenInkongruenzen zwischen Kompetenz und VerantwortungKapitulation
33
Aspekte der Software-EntwicklungUnter Software-Entwicklung verstehen wir das Zusammenspiel
der folgenden vier Bereiche:
Projektmanagement :Kosten, Zeit, Personal
Qualitätsmanagement :Übereinstimmung mit den Anforderungen
Konfigurationsmanagement :Verwalten aller Bestandteile einerDatenverarbeitungslösungen und ihrer Versionen
Software-Erstellung:Erstellen aller Modelle (z.B. Programme)
34
Prinzipien des SWE
Prinzip: Grundsatz, den man seinem Handeln zugrundelegtTechnik: Vorschrift zur Durchführung einer Tätigkeit (Was ist wie zu tun?)
Methode: Planmäßig anwendbare, begründete Technik zur Erreichung vorgegebenerZiele (Was ist wie und unter welchen Rahmenbedingungen zu tun, so daß eingutes Ergebnis erreicht wird?)
Werkzeuge: Rechnerunterstützung für Techniken und MethodenSprache: syntaktische Regeln zur Unterstützung einer Methode oder Technik. Eine
Sprache besteht aus ihrer Syntax und ihrer Semantik:
formale Sprachen haben eine formale Syntax- und Semantikdefinition (Aussagenlogik,Prädikatenlogik)
semiformale Sprachen haben eine formale Syntax, aber keine klar definierte Semantik(SADT, UML)
informale Sprachen haben weder eine formale Syntax noch eine formale Semantik(Deutsch, Englisch)
35
Prinzipien des SWE
Prinzipien
Methoden(Techniken)
Sprachen
Werkzeuge
Dekomposition
OO / funktional
UML/SADT
OTW/PRADOS
36
Prinzip Striktheit und Formalität
strikte Anforderungsdefinitionstrikte Dokumentation des Software-Prozesses und seiner
Ergebnissestrikter Entwurfstrikte Spezifikation aller Dokumenteformale Beschreibung an kritischen Stellen
kritisch für das Verständniskritisch im Hinblick auf spätere Änderbarkeitkritisch im Hinblick auf das Schadenspotential von Mißverständnissen
37
(separation of concerns / Unterteilung in Aspekte)
Beispiele von AspektenFunktionalität
RobustheitPerformanz und RessourcenverbrauchOrganisation der Software-Entwicklung
Konfigurations-Managementund viele andere concerns Striktheit und Formalität
Abhängigkeit zwischen AspektenPerformanz und DatenintegritätFunktionalität und Zielplattform
Prinzip Strukturierung
38
Arten der Unterteilung
zeitliche Unterteilung: Anforderungsanalyse / Entwurf / Programmierung / Testqualitative Unterteilung: Effizienz / Robustheit / Korrektheit
perspektivische Unterteilung: Verwendung von Datenstrukturen / Datenfluß /Kontrollfluß
Dekomposition (Unterteilung in Bestandteile): Komponente 1, Komponente 2
Prinzip Strukturierung
39
Dekomposition Komposition
Legende
Komponente /Modul
A
B
A ruft B auf
Prinzip Strukturierung
40
Trennung von wichtigen und unwichtigen Merkmalen„Unterschlagung“ / „Wegabstraktion“ der unwichtigen und Betonung der
wichtigen zum Zweck der Konzentration auf das WesentlicheGängige Abstraktionen
die Signatur einer Operation abstrahiert von der Realisierung der Operation
die Konstrukte einer Programmiersprache abstrahieren von Prozessorendetailsein Datenflußdiagramm abstrahiert von den Aufrufstrukturen zwischen Komponenten
Prinzip Abstraktion
41
Wichtigkeit und Unwichtigkeit ist relativ zum Zweck der Abstraktion
Realität Modell
verkürzendeEigenschaften
erweiterndeEigenschaften
Erde Landkarte
Verkürzende Eigenschaften im Modell „Landkarte“:
• Wassertemperatur• Fauna / Flora
Erweiternde Eigenschaften:
• Längen- und Breitengrade
Prinzip Abstraktion
42
Software ist Gegenstand von Änderungen. Ursachen fürÄnderungen:
Beseitigung von Fehlern (korrektive Wartung)Verbesserung nicht funktionaler Eigenschaften (perfektive Wartung)Erweiterung der Funktionalität wegen sich ändernder
Rahmenbedingungen (adaptive Wartung)Erweiterung der Funktionalität wegen Erkenntnisgewinn während der
Entwicklung
Prinzip Annahme der Änderungsnotwendigkeit
43
unklareAnforderungen
Software1.Version
geklärteAnforderungenan die Software
Software2. Version
weiter geklärteAnforderungenan die Software
Software-Prozeß
. . .
Software-Prozeß ist kein typischer Fertigungsprozeß !
Software-Prozeß
Prinzip Annahme der ÄnderungsnotwendigkeitPrinzip Annahme der Änderungsnotwendigkeit
44
Aktivitäten der Software-Entwicklung
In der Software-Erstellung gibt es eine Vielzahl von Aktivitäten, zuden wichtigsten gehören:
AnforderungsanalyseSpezifikationEntwurfProgrammierungTestenInbetriebnahme
A software engineer must of course be agood programmer, be well-versed indata structures and algorithms, and befluent in one or more programminglanguages. ... The software engineermust be familiar with several designapproaches, be able to translate vaguerequirements and desires into precisespecifications, and be able to conversewith the user of a system in terms ofthe application rather than in‚computerese‘.Ghezzi,Jazayeri,Mandrioli 1991, vgl.Literaturliste
45
Programmierung
Programmierung:Verwendung einer Programmiersprache, um Anforderungen,Spezifikationen, Entwürfe in maschinenausführbare Form zuformulieren.Um genau zu sein: um eine Form zu erreichen, dieautomatisch in eine maschinenausführbare Form übersetztwerden kann.
46
Objektorientierte Software-Erstellung
• Drei Aktivitäten auf der Grundlage der gleichenGrundkonstrukte:– Objektorientierte Analyse (OOA)– Objektorientiertes Design (OOD)– Objektorientierte Programmierung (OOP)
• Analyse / Design wird durch objektorientierteModellierungssprachen unterstützt– OMT (Object Modeling Technique)– UML (Unified Modeling Language)
=> siehe http://www.rational.com
• Programmierung mit objektorientierter Programmiersprache– Smalltalk, C++, Objective C, Java, Classic Ada, Delphi, Eiffel, Beta
• hohes Wiederverwendungspotential
47
Kapitel 3
Objektorientierte Analyse und Designvgl separate pdf-Datei
Kapitel 4
Grundbegriffe zu Programmiersprachen
49
Programmiersprache
Die Syntax einer Programmiersprache legt fest, welchen AufbauProgramme haben.
Lexikalische Ebene: wie werden aus Zeichen Wörtergebildet?
Syntaktische Ebene: wie werden aus Wörtern Sätzegebildet?
Die Syntax wird durch eine Grammatik festgelegt.
50
Programmiersprache
Eine Grammatik ist gegeben durch ein Viertupel (S, T, N, P) mit:S ist ein Startsymbol
T ist eine Menge von TerminalsymbolenN ist eine Menge von NichtterminalsymbolenP ist eine Menge von Produktionen / Ableitungsregeln
51
Programmiersprache
Terminalsymbole beschreiben Symbole, die in den Sätzen derSprache vorkommen.
Nicht-Terminalsymbole kommen nicht in den Sätzen der Sprachevor. Sie werden gebraucht, um die Anwendung derAbleitungsregeln zu koordinieren.
Das Startsymbol ist ein ausgezeichnete Nicht-Terminalsymbol.Es legt fest, mit welcher Ableitungsregel begonnen wird, um zueinem syntaktisch korrekten Satz der Sprache zu kommen.
Die Ableitungsregeln legen fest, wie eine Sequenz von Nicht-Terminal- und Terminalsymbolen durch eine Folge andererTerminalsymbole und Nicht-Terminalsymbole ersetzt werdenkann.
52
Programmiersprache
Beispiel einer Produktion:einfacher-deutscher-Satz = Subjekt Prädikat Objekt {adverbiale-Bestimmung}Subjekt = Nomen | PersonalpronomenPersonalpronomen = Ich | Du | ...
{} steht für 0 bis n-fache Formulierung[] steht für Optionalität (0 oder einfaches Vorkommen)| trennt Varianten voneinanderfett: Terminalsymbole,kursiv: Nicht-Terminalsymbole
53
ProgrammierspracheWie ändert sich die Grammatik, wenn immer mindestens eine adverbiale
Bestimmung vorkommen muß?
Wie ändert sich die Grammatik, wenn ich zwischen adverbialen Bestimmungendes Ortes, der Zeit und der Art unterscheiden möchte?
54
Beispiel einer Produktion:ClassDeclaration = {ClassModifier} class Identifier [extends SuperClass][implements Interfaces] {FieldDeclarations}
Beispiel einer Grammatik:
Grammatik völlig-simpel = ( START, {(,),+,1,leer }, {S,START},{START = S | leer ,
S = S+S | 1 | (S)} )Prüfung, ob der Satz (1+1) +1 in der Sprache völlig-simpel gültig ist:
START -> S -> S+S
Programmiersprache
(S) -> S+S1
1 1
55
ProgrammierspracheWelche Sprache wird durch die folgende Grammatik erzeugt?
Grammatik unklar = ( S, {a,b,c}, {S,A,B},{S = abc,
S = aAbc,Ab = bA,Ac = Bbcc,bB = Bb,aB = aaA,aB = aa} )
56
Programmiersprache
L(G) = {anbncn | n ≥ 1}, wobei L(G) die Menge der Sätze bezeichnet, die sichgemäß der Grammatik G erzeugen lassen.
57
ProgrammierspracheBeweis von L(G) = {anbncn | n ≥ 1}:
Induktionsanfang:Jede Ableitung beginnt mit der Anwendung der ersten oder zweiten Ableitung.
Die erste liefert direkt abc (gehört zur Sprache).
58
S = abc, S = aAbc, Ab = bA, Ac = Bbcc, bB = Bb, aB = aaA, aB = aa
Induktionsschritt:Nun betrachten wir den Satz: D = aiAbici mit i ≥ 1.Annahme: Von diesem Satz aus erreichen wir nur Sätze in der
angenommenen Sprache.Beweis: Erst mal muß i-mal die Ableitung Ab = bA angewendet werden,
denn nur so wandert das A nach rechts.
Ergebnis: aibiAci
Danach kann nur die Ableitung Ac = Bbcc angewendet werden.
Ergebnis: aibiBbccci-1 = aibiBbc i+1
Danach kann nur noch i-mal bB = Bb angewendet werden.
Ergebnis: aiBbi+1ci+1
Aus diesem Satz ergibt sich nun entweder:
ai+1bi+1ci+1 (gemäß aB = aa)
oder ai+1Abi+1ci+1 (gemäß aB = aaA)
59
ProgrammierspracheFazit:
Also enthält L(G) genau die betrachteten Wörter (genau deshalb, weil es imInduktionsschritt keine weiteren Möglichkeiten der Anwendung vonAbleitungen gab!)
Bemerkung: Die betrachtete Sprache ist eine der typischen kontextsensitivenSprachen!
Um zu verstehen, daß der Kontext nötig ist, möge man versuchen die gleicheSprache mit einer kontextfreien Grammatik zu erzeugen.
60
Programmiersprache
Wenn auf der linken Seite aller Produktionen nur jeweils einNicht-Terminalsymbol steht, dann heißt die Grammatikkontextfrei.
Das bedeutet: die Ersetzung eines Nicht-Terminalsymbolen hängtnicht davon ab, in welchem Kontext das Nicht-Terminalsymbolen vorkommt.
Java-Grammatik: www1.arcs.ac.at/users/mt/java/java-syntax.html#Number
61
Syntax-Beispiele Java
ClassDeclaration ={ClassModifier}class Identifier[extends SuperClass][implements Interfaces]{ FieldDeclarations }
FieldDeclarations ={FieldDeclaration}
FieldDeclaration =[DocComment] MethodDeclaration[DocComment] abstract
InterfaceMethodDeclaration[DocComment] native
NativeMethodDeclaration[DocComment]
ConstructorDeclaration[DocComment] VarDeclarationStaticInitializer ;
62
Syntax-Beispiele Java
MethodDeclaration ={MethodModifier}ResultType Declarator ( [
ParameterList ] )[ throws Exceptions ]Block
MethodModifier =public | protected | privatestaticfinal | synchronized
ConstructorDeclaration =ConstructorModifierClassName ( [ ParameterList ] )[ throws Exceptions ]ConstructorBody
63
Programmiersprache
Die Semantik einer Programmiersprache legt fest, was diesyntaktisch korrekten Sätze der Sprache bedeuten.
Die Semantik kann durch die Abbildung auf ein mathematischesModell definiert werden (zum Beispiel auf Aussagen- oderPrädikatenlogik).
Üblicherweise wird die Semantik einer Programmiersprachejedoch operational festgelegt. Das heißt, die Bedeutung einesSatzes wird durch das Verhalten des Programms (das diesemSatz entspricht) auf einer Referenzmaschine definiert.
64
Übersicht über die Entwicklung vonProgrammiersprachen
Maschinensprache001001
AssemblerBspe: RS600-Assembler
Konstrukte: MV, ADD, GET)
Imperative / Prozedurale SprachenBspe: Fortran, Cobol, Algol, PL1, Ada, C
Prozeduren, while, case, if
Logische SprachenBsp: Prolog
Konstrukte: Fakten, Regeln
Objektorientierte SprachenBspe: C++, Smalltalk, Eiffel, Java
Funktionale SprachenBspe: LISP, ML, MirandaKonstrukte: Funktionen
Vorgängerbeziehung
Zeit
Kapitel 5
Java als objektorientierte Programmiersprache
66
Charakterisierung / Vergleich
• Java ist aus einem Projekt entstanden, Software fürelektronische Geräte zu entwickeln
• Daraus entstanden Anforderungen, die von Sun formuliertwurden
• Sun wirbt heute damit, dass Java diese Anforderungen erfüllt• Werbung und Wirklichkeit sind jedoch nicht deckungsgleich
=> Charakterisierungen von Java sind diskussionsbedürftig
67
Einfach
• Sun: Java ist einfach– Design nahe an C++, um Umstieg zu erleichtern– Selten benutzte und schwer verständliche Eigenschaften aus C++
wurden beseitigt• Überladen von Operatoren
• Mehrfachvererbung
– Garbagecollection vereinfacht Umgang mit Objekten, Programmierermuß Speicher nicht selbst freigeben
• Diskussion– Mehrfachvererbung ist sicher überflüssig– Überladen von Operatoren kann Lesbarkeit von Programmen erhöhen– Java ist sehr mächtig, daher nicht schnell zu erlernen– Es ist einfach, verständlich zu programmieren
68
Objektorientiert
• Sun: Java ist objektorientiert– Objektorientierte Funktionalität realisiert– Beste Konzepte der Sprachen C++, Objective C, Eiffel und Smalltalk
• Diskussion– Ausgereifte Realisierung objektorientierte Eigenschaften ist eine Stärke
von Java
69
Verteilt
• Sun: Java ermöglicht verteilte Programmierung– Standardprotokolle, wie TCP/IP, HTTP und FTP werden angeboten– Zugriff auf Dateien über URL's genauso einfach, wie Zugriff auf lokale
Dateien
• Diskussion– Plattformspezifische Unterschiede zwischen Unix und Windows bereiten
jedoch Schwierigkeiten– Diese sind jedoch lösbar
70
Robust
• Sun: Java ist ideal für robuste Programmierung– Java ist streng getypt, im Gegensatz zu C++– Java hat kein Zeigermodell
=> keine Integer-Zeiger-Konvertierung– Garbagecollection
• Diskussion– Oben aufgeführte Schwachstellen in C++ sind in Java beseitigt
aber:– Klassenbibliotheken sind oft unausgereift
71
Sicher
• Sun: Java legt viel Wert auf Unterstützung sichererNetzwerkprogrammierung– Authentifizierungsalgorithmen basierend auf asymmetrischer
Kryptographie– Pointer-Semantik kann nicht manipuliert werden– Applets können durch Signierung Rechte erhalten
• Diskussion– Die amerikanische Exportpolitik verhindert leider den direkten Export
starker Verschlüsselungssoftware– Sicherheit eines Bytecode Verifyers nicht formal bewiesen, erfolgreiche
Einbrüche jedoch nicht bekannt
72
Architekturneutral / Portabel
• Sun: Java ermöglicht plattformunabhängige Software-Entwicklung– Bytecode kann überall interpretiert werden– AWT wird auf alle Plattformen abgebildet– Sprache plattformunabhängig definiert, z.B. ist "int " immer 32 Bit lang,
unabhängig von der Architektur
• Diskussion– Leider sind API-Fehler plattformabhängig
=> "Write once test everywhere" :-)– Portierung ist jedoch immer noch einfacher, als mit vielen anderen
Sprachen
73
Dynamisch
• Sun: Java ermöglicht dynamische Programmierung– Bibliotheken können im laufenden System ausgetauscht und aktualisiert
werden– Keine Neucompilierung nötig
74
Von C/C++ nicht übernommene Eigenschaften
• Kein Präprozessor– kein #define , #include oder typedef
=> Programmtext ist einfacher zu lesen
• Keine Structures und Unions– Klassen erfüllen gleichen Zweck
• Keine Funktionen– Reiner objektorientierter Ansatz– Es gibt aber Klassenmethoden, die ähnliche Funktionalität bieten
• Keine Mehrfachvererbung von Klassen– Mehrfachvererbung in Interfaces jedoch möglich
75
Von C/C++ nicht übernommene Eigenschaften
• Kein goto -Befehl– In strukturierter Programmierung nicht nötig– Multilevel-break und Multilevel-continue kann goto ersetzen
• Kein Überladen von Operatoren• Keine automatische Typwandlung mit Informationsverlust
– Expliziter Cast nötig
• Keine Zeiger– Arrrays und Strings sind Objekte– Objekte werden referenziert
76
Zusammenfassende Diskussion
• Es ist Sun gelungen, den Bereich der Entwicklung verteilterSoftware-Systeme mit Java zu besetzen
• Sun hat bei dem Vorhaben eine breite Industrieunterstützung• Entwicklungen von komplexen Software-Paketen kommt
aufgrund von Performance- und Stabilitätsproblemen etwaslangsamer voran
77
Die Java Welt
Java ist mehr als eine Programmiersprache ...
• objektorientierte Programmierung• plattformunabhängige Programme• Klassenbibliothek und Programmier-Schnittstellen
(Application Programming Interface API)• Entwicklung und Vertrieb durch Sun Microsystems
– Java Development Kit (JDK)/Software Development Kit (SDK)frei verfügbar
Überblick zu Java
78
Die Java Welt
• Entwicklung von Internet-Anwendungen• Entwicklung von verteilten Anwendungen• Java Applets
– integriert in WWW-Seiten– verbreitet über das Internet
• Java Applikationen– entworfen, um als separate Prozesse in einer Laufzeit-Umgebung auf
beliebiger Plattform zu laufen– kann auch über das Internet vertrieben werden
Überblick zu Java
79
Übersetzen des Programmtexts
• Aus Java-Programmtext erzeugt der Java-Compiler eine Java-Bytecode-Datei
• Auf dem Zielrechner interpretiert die Java Virtual Machine JVMdiesen Bytecode und führt das Programm aus– Geschwindigkeitsprobleme
Überblick zu Java
80
Vorteil: Plattformunabhängigkeit
• Compilierte Java Programme (d.h. Bytecode) laufen auf jederJVM-fähigen Plattform
Überblick zu Java
81
Bytecode / Class-Files
• Java wird vom Java Compiler zu einer fest definiertenZielsprache übersetzt
• Die Zielsprache ist der Bytecode– sie ist maschinenähnlich, hat z.B. Register– kann einfach interpretiert bzw. in Maschinencode anderer Plattformen
übersetzt werden
• Jede Java-Klasse wird separat übersetzt und– in separater Datei, dem Class-File gespeichert.– Das Format der Dateien wird Bytecode genannt.– Auch andere Sprachen lassen sich nach Bytecode übersetzen.
82
JDK / JRE• Java Development Kit (JDK)/Software Development Kit (SDK)
ist eine– kostenlose Software-Entwicklungsumgebung der Firma JavaSoft, um
Java-Programme zu entwickeln– Alle Entwicklungen sind mit JDK/SDK alleine möglich, kommerzielle
Tools können jedoch Entwicklung unterstützen:• Visual Age (IBM)• JBuilder (Inprise, Borland)• Visual J++ (Microsoft)• Java Workshop / Studio (Sun)
– Darf nicht ohne Lizenzgebühren weiterverkauft werden
• Java Runtime Environment (JRE) ist eine– Untermenge des JDK/SDK, die benötigt wird, um Java-Applikationen
laufen zu lassen– Darf ohne Lizenzgebühren eigenen Produkten beigefügt werden
83
Virtual Machine / JIT-Compiler
• Virtual Machine ist der Teil des JRE, der benötigt wird, umBytecode zu interpretieren
• Classfiles werden nur bei Bedarf geladen und– entweder interpretiert– oder vor Verwendung "just in time" in die Maschinensprache der
Zielplattform übersetzt
• JIT-Compiler (Just-In-Time-Compiler) ist ein Compiler, derKlassen nur bei Bedarf zur Ausführungszeit übersetzt– Es gibt in der Regel Geschwindigkeitsvorteile im Vergleich zur
Interpretation
84
Java Virtual Machine (JVM)
• Bestandteile:– Byte Code Loader– Byte Code Verifier– Byte Code Interpreter
Überblick zu Java
85
Java Applikationen vs. Java Applets
• Java Applets– laufen innerhalb der JVM eines Webbrowsers– haben eigene, festgelegte Zeichenfläche im Webbrowser
• Java Applikationen– eigenständige Applikationen– laufen innerhalb der JVM– werden auf der Befehlszeilenebene oder als Windows-Applikation
gestartet
• Programmieren in Java für beide identisch
Überblick zu Java
86
Zusammenfassung
• Applets / Applikationen
• Java Development Kit (JDK)/Software Development Kit (SDK)• Compiler
• Java Runtime Environment (JRE)• Java Virtual Machine (JVM)• Interpreter, Just-in-time-Compiler (JIT)• Bytecode, Class-Files
• Webbrowser• Plattformunabhängigkeit
Überblick zu Java
Kapitel 6
Ein erstes Java-Beispiel
88
Klassen: Gleichartige Objekte Klassen in Java
public class Girokonto {
private int kontostand; // in Pfennigen gerechnet
public Girokonto() {
kontostand = 0;
}
/* Einzahlen und Abheben */
public void zahle ( int pfennige){
kontostand = kontostand + pfennige;
}
public int holeKontostand() {
return (kontostand);
}
}
Modifier class Klassenname {
Attribut-Deklarationen
Methoden
}
// Kommentar
/* Kommentar */
89
Von Klassen zu Objekten
• Exemplare aus einer Klassen-Schablone:
– ErzeugenGirokonto einKonto= new Girokonto();
– Löschen: wenn nirgendwo mehr benutzt (automatische Garbage-Collection)
– Zustand eines Objekts verändern (→ Attribute)Nachrichten an ein Objekt senden (→ Methoden)
Klassen in Java
Klasse ObjName =
new Klasse(Typ1 name1, ...)
Girokonto
Kontostand (in Pfennigen)
•Ein-/Auszahlen•Kontostand abfragen
Objekt
Objekt
Objekt
Objekt
90
Attribute Klassen in Java
• Teile des Gesamtzustands eines Objekts
private int kontostand;private Girokonto meinKonto;
• Verändern von Attributenkontostand = kontostand + pfennige;
• Einkapseln von Attributen (→ Ziel: möglichst alle Attribute einkapseln)– privat d.h. nur innerhalb des Objekts sichtbar (private)
– öffentlich d.h. auch außerhalb des Objekts sichtbar (public)
Modifier Datentyp attributname
91
Methoden (1/2) Klassen in Java
• Teile des möglichen Verhaltens eines Objekts(d.h. Nachrichten, die vom Objekt verarbeitet werden können)
public void zahle ( int pfennige){
kontostand = kontostand + pfennige;
}
public int holeKontostand() {
return (kontostand);
}
Modifier Rückgabetyp Methodenname (Typ1 ParamName1,Typ2 Param...){
Liste von Anweisungen;
[ return (Rückgabewert) ]
}
Spezieller Rückgabewert: void
92
Methoden (2/2) Klassen in Java
• Aufruf von Methoden eines Objektes (Punkt-Notation,qualifizierter Zugriff)
konto.holeKontostand();
konto.zahle(+100);
• Übergeben von Parametern– statt komplette Objekte zu übergeben, nur Zeiger darauf („by reference“)– bei einfachen Datentypen als Wert kopiert („by value“)
• Einkapseln von Methoden– privat, d.h. nur als interne Hilfs-Methode zugreifbar (private)
– öffentlich, d.h. extern sichtbar (public)
93
• Einsprungpunkt bei "Ausführen" einer Applikation– Übergeben von Argumenten aus der Kommandozeile möglich– für Testen von Klassen-Implementierungen geeignet
public class TestGirokonto {
...
public static void main(String[] args) {
... // Hier Code zum Testen einfügen
}
...
}
Spezielle Methode "main" Klassen in Java
94
Hilfsklasse „Bildschirm“
• Benutzereingaben und Bildschirmausgaben später detaillierter,im Augenblick genügt Anwendersicht: "Welche Methoden gibt es?"
– komfortable Ausgabe auf den BildschirmBildschirm.gibAus (text)
– komfortable Eingabe eines Textes von Tastatureingabetext = Bildschirm.gibEin()
– Warten auf TastendruckBildschirm.warteAufTastendruck()
95
Motivation• Klasse erweitern um Attribute, Methoden• Erzeugen von Objekten und Nachrichtenaustausch (Methoden) zwischen Objekten
Aufgaben• Ergänzen Sie die Klasse "Girokonto":
– zum Sperren eines Kontos: boolesches Attribut istGesperrt mit denMethoden void sperre(), void entsperre() und boolean istGesperrt()
– zum Überschreiben des aktuellen Kontostandes mit einem übergebenen Betragdie Methode setzeKontostand()
• Testen der Klasse "Girokonto" (siehe: Methode "main" in der Klasse "TestGirokonto" )
– Erzeugen eines Girokonto-Objekts– Nacheinander Einzahlen von 100 Pfennigen, Abheben von 20 Pfennigen und
Einzahlen von 30 Pfennigen– Anschließend Kontostand ausgeben
Übung: Attribute und Methoden
96
Übung: Attribute und Methoden
Lösung 1:public class Girokonto {
...
private boolean istGesperrt;...
public void sperre() {
istGesperrt=true;
}
public void entsperre(){
istGesperrt=false;
}
public boolean istGesperrt (){
return (istGesperrt);
}...
}
97
Übung: Attribute und Methoden
Lösung 2:public class TestGirokonto {
public static void main(String[] args) {
// erzeuge neues Konto
Girokonto konto = new Girokonto();
// führe Transaktionen durch
konto.zahle(+100);
konto.zahle(+30);
konto.zahle(-20);
// gib Kontostand aus
int aktuellerStand = konto.holeKontostand();
Bildschirm.gibAus(aktuellerStand);
}
}
Klasse „Bildschirm“
Einsprung von der Kommando-zeile [optional für jede Klasse]
98
Zusammenfassung
• Programm = Mehrere Objekte, die Nachrichten austauschen
• Klassen: Schablonen für Objekte– Attribute, Methoden
• Objekte– Erzeugen
• Nachrichtenaustausch– Aufruf von Methoden eines Objektes (Punkt-Notation)
z.B. konto.holeKontostand()
Kapitel 7
Java-Syntaxkonstrukte7.1 Primitive Datentypen, Literale und Variablen7.2 Aufruf von Objekten, einfacher Nachrichtenaustausch7.3 Operatoren, Ausdrücke, Zuweisungen7.4 Anweisungen
Kapitel 7.1
Primitive Datentypen, Literale und Variablen
101
Primitive Datentypen
Ganze Zahlen:byte , short , int , long
Fließkommazahlen:float , double
Andere Typen:char , boolean
Keine primitiven Datentypen:String , Arrays (auch von einfachen Typen), Klassen allgemein
102
Primitive Datentypen: ganze Zahlen
• 2er Komplement Datentypen• vorzeichenbehaftet• feste Größe, unabhängig von Maschinenwortgröße
• Vergleich C/C++: (short : 16 Bit, long : 32 Bitint : Maschinenwortlänge)
Typ Größe Wertebereich
byte 8 Bit (1 Byte) -27 ... 0 ... (27-1)
short 16 Bit (2 Byte) -215 ... 0 ... (215-1)
int 32 Bit (4 Byte) -231 ... 0 ... (231-1)
long 64 Bit (8 Byte) -263 ... 0 ... (263-1)
103
2er Komplement (Hier 8 Bit)
• Höherwertige Bitsstehen links
• HöchstwertigesBit istVorzeichenbit
Bit Nummer7 6 5 4 3 2 1 0
Dezimalwert
0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 1 10 0 0 0 0 0 1 0 20 0 0 0 0 0 1 1 30 0 0 0 0 1 0 0 40 1 1 1 1 1 1 1 1271 0 0 0 0 0 0 0 -1281 0 0 0 0 0 0 1 -1271 1 1 1 1 1 1 0 -21 1 1 1 1 1 1 1 -1
Vorzeichenbit
104
Primitive Datentypen: Fließkommazahlen
• Fließkommazahlen nach IEEE 745• Mantisse und Exponent definiert Wert• Unendlich ist ein definierter Wert
(POSITIVE_INFINITY und NEGATIVE_INFINITY )• NaN (Not a number) ist ein definierter Wert
Typ Größe Wertebereich Genauigkeit
float 32 Bit (4 Byte) +/- 3.4*1038 ca. 7 Dezimalst.
double 64 Bit (8 Byte) +/- 1.8*10308 ca. 15.5 Dezimalst.
105
IEEE 745 Standard
Fließkommazahlen nach IEEE 745 setzen sich zusammen aus:• Sign-Bit S (1 Bit)• Exponent E (8 Bit für float und 11 Bit für double )• Mantisse M (23 Bit für float und 52 Bit für double )
Sind in E alle Bits gefüllt, ist dies ein reservierter Zustandum Unendlich und NaN darstellen zu können
106
Primitive Datentypen: boolean
• boolean kennt nur zwei Werte, true und false
• Sämtliche boolsche Logik in Java wird mit dem Datentypboolean realisiert. Mißbrauch von Integertypen für boolscheAusdrücke, wie in C und C++ üblich, ist in Java nichtvorgesehen.
• boolean benötigt 1 Byte (=8 Bit) Speicher. Dies liegt nicht ander Java-Sprachsyntax, sondern am Mapping auf die VirtualMachine, die keine 1-Bit-Datentypen kennt.
107
Primitive Datentypen: Zeichen
• char ist ein 16-Bit-Zeichen nach dem Unicode-Standard
• Untere 7 Bit (128 Zeichen) von Unicode sind ASCII-kompatibel(bzgl. ASCII nach ANSI X3.4)
• Sonstige Bits werden benötigt um internationale Zeichensätzeabbilden zu können.
• Verantwortlich ist das Unicode Consortium(http://www.unicode.org)
108
Klasse String
• Zeichenketten werden durch Objekte der Klasse Stringdargestellt
• allgemeine Objekte und Klassen werden später gründlicheruntersucht
• String ist jedoch besondere Klasse, da Literale (konstanteZeichenketten) und Operatoren (+ zur Konkatenation) definiertsind
• Anders als in C/C++ sind Strings keine Zeiger auf char bzw.Array von char , in Java gibt es keine Zeiger und Arrays sindgesonderte Konstruktionen, die nichts mit der Klasse Stringzu tun haben
109
Anwendungsbereich Java-Datentyp Beispiel
• Logik boolean true und false
• Buchstaben char z.B. ´a´,´b´,´c ´ ...
• Ganze Zahlen byte ( 8 Bit) z.B. -13 , -1 , 0,1short (16 Bit)
int (32 Bit)
long (64 Bit)
• Fließkomma float (32 Bit) z.B. -3.3e-22f ,double (64 Bit) z.B. 3.4E32
Primitive Datentypen in Java
110
Literale
• Literale sind konstante Zahlen, Zeichen bzw. Zeichenketten,die zur Initialisierung von Datentypen verwendet werden
• Jedes Literal hat einen eindeutigen Typ, bei Zuweisungen mußauf Typkonsistenz geachtet werden.
• Literale existieren für die einfachen Datentypenint , long , float , double , char und booleansowie für die Klasse String .
111
Literale: Wahrheitswerte
• Für den primitiven Datentyp boolean gibt es die Literaletrue und false .
112
Literale: ganze Zahlen
• Ganze Zahlen lassen sich einfach durch den Dezimalwertdarstellen (z.B. 0, 20 , 4332 , etc.)
• Ein Vorzeichen kann der Zahl vorangestellt werden(z. B. -323, +4238 )
• Durch vorangestelltes "0x " lassen sich Zahlen durch ihreHexadezimalwerte definieren. Die Buchstaben A bis F könnenhier sowohl klein, als auch groß geschrieben werden (z. B.0x3AF , 0xfff178 )
• Durch eine vorangestelle Null "0" werden Zahlen imOktalsystem definiert (z. B. 04123 , 01114 )
113
Literale: ganze Zahlen
• Standardmäßig sind Ganzzahlkonstanten vom Typ int ,long -Konstanten werden durch ein Anfügen des BuchstabensL bzw. l erzeugt (z. B. 0L , 100000000000L )Achtung: l ist leicht mit 1 zu verwechseln, daher sollte Lbenutzt werden
• Für die Datentypen byte und short existieren keine eigenenLiterale, es dürfen int -Literale verwendet werden, sofern derWert klein genug ist
114
Literale: Fließkommazahlen
• Fließkommazahlen bestehen aus einer Mantisse und einemoptionalen Exponenten (zur Basis 10).
• Der Exponent wird durch ein "E" bzw. "e" von der Mantissegetrennt. (10E3 entspricht z. B. dem Wert von 1000)
• Sowohl Mantisse als auch Exponent könnenvorzeichenbehaftet sein (z. B. -10E8 , +3e-4 )
• Die Mantisse darf auch als Dezimalbruchdarstellunggeschrieben werden (z. B. -5.334E+27 )
115
Literale: Fließkommazahlen
• float -Typen lassen sich durch ein angefügtes f bzw. Fdefinieren. (z. B. 7f , 3.8F )
• double -Typen lassen sich durch ein angefügtes d bzw. Ddefinieren. (z. B. 121D, 1.4E7d )
• Fließkommazahlen lassen sich als solche von ganzen Zahlenunterscheiden, wenn eine der folgenden Eigenschaften erfülltist:a) Es existiert ein Exponent (z.B. 1E3)b) Die Mantisse enthält den Dezimalpunkt (z. B. 3.0 )c) f , F, d oder D beendet das Literal
• Ist ein Fließkommaliteral nicht durch f bzw. F spezifiziert, hates den Typ double
116
Literale: Zeichen
• Zeichen (char -Literale) werden durch einfacheAnführungsstriche definiert. (z. B. 'a' , '#' , '=' )
• Für Sonderzeichen gibt es Escape-Sequenzen, die durcheinen Backslash "\ " eingeleitet werden. (z. B. '\n' )
• Hierbei bedeutet:'\b' : backspace BS (Zeichen zurück) (ASCII: 8)'\t' : horizontal tab HT (horizontaler Tabulator) (ASCII: 9)'\n' : line feed LF (Zeilenvorschub) (ASCII: 10)'\f' : form feed FF (Seitenvorschub) (ASCII: 12)'\r' : carriage return CR (Wagenrücklauf) (ASCII: 13)'\”' : double quote (doppeltes Anführungszeichen)'\'' : single quote (einfaches Anführungszeichen)'\\' : backslash (Rückwärts-Schrägstrich)
117
Literale: Zeichen
• In einer Escape-Sequenz kann auch direkt der ASCII-Wert alsOktalzahl angegeben werden (z. B. '\17' , oder '\3' )
• Durch '\uxxxx' wird der Wert als Unicode-Sequenzangegeben, wobei für jedes x eine Hexadezimalzifferangegeben werden muß. (z. B. '\0022' entspricht '\"' )
• Achtung: die Unicode-Escape-Sequenzen werden in einersehr frühen Phase des Compilers ausgewertet.Ein Zeilenvorschub als Unicode-Escape-Sequenz wird dahergenauso behandelt wie eine neue Zeile im Editor.
118
String-Literale
• Strings sind Verkettungen von Zeichen.• String -Literale werden durch doppelte Anführungszeichen
gekennzeichnet• Alle Zeichen lassen sich analog den char -Literalen
konstruieren.• Beispiele für String -Literale:
"Begrenzung durch Anführungszeichen""Das ist ein Text\nmit Zeilenvorschub"
119
Variablen
• Variablen dienen dazu, Werte von speziellen Datentypen zuspeichern und zu verarbeiten, die gespeicherten Werte könnenwährend der Ausführung eines Programms geändert werden;sie sind halt variabel.
• Die Werte, die eine Variable annehmen kann, sind durch ihrenTyp festgelegt.
• Als erster Schritt muß eine Variable dem Compiler bekanntgemacht werden, diesen Vorgang nennt man Deklaration
• Dann muß ein Anfangswert (initialer Wert) zugewiesen, diesenVorgang nennt man Initialisierung
• Verkürzend können beide Aktionen auch in einer Zeile erledigtwerden.
120
Variablen
• Ohne Deklaration kann keine Variable initialisiert werden• Ohne Initialisierung kann keine Variable weiterverarbeitet
werden (z. B. in Ausdrücken)
121
• Speicherung von Werten– Variablenname und Datentyp– bei Initialisierungen müssen beide Seiten zuweisungskompatibel sein
...
int kontostand;
oder:int kontostand = 0;
...
kontostand = kontostand + pfBetrag;
Variablen
Deklaration [mit Initialisierung]Datentyp Variablenname [= Wert]
122
Variablennamen
• Variablennamen (sowie alle Bezeichner in Java) sind case-sensitive , also man unterscheidet zwischen Groß- undKleinschreibung
• Variablennamen beginnen stets mit Buchstaben (JavaLetter),dann können Buchstaben oder Zahlen folgen.Der Unterstrich "_" gehört aus historischen Gründen auch zuden Buchstaben, kommt aber in der offiziellenNamenskonvention nicht vor, sollte daher nicht verwendetwerden.
123
Deklaration
• Variablen werden durch den Typ gefolgt von demVariablennamen deklariert
• Mehrere Variablennamen können durch Kommata getrenntaufgeführt werden, sie sind dann vom gleichen Typ
• Deklarationen sind Anweisungen, die mit Semikolonabgeschlossen werden
Beispiel:int anzahlPersonen;
long millisekundenSeitGeburt;
float größeInCm, gewichtInKg;
String name, wohnort;
124
Initialisierung
• Initialisierungen werden mit Hilfe des Gleich-Operatorsrealisiert, der rechte Wert wird dem linken zugewiesen.
• Initialisierungen sind Ausdrücke, die mit einem Semikolonabgeschlossen werden
• Bei Initialisierungen müssen beide Seiten den gleichen Typhaben
Beispiel:anzahlPersonen = 20;
milliSekundenSeitGeburt = 568000000000L;
größeInCm = 185F;
name = "Hans Mustermann";
125
Type Casting
• Datentypen byte und short haben keine eigenen Literale• Es muß das Literal von int genommen werden und der Wert
nach byte bzw. short gewandelt werden (casting)
• Dies geschieht durch vorangestellte runde Klammern (Cast-Operator)
Beispiel:byte alterInJahren;
alterInJahren = (byte)18;
126
Deklaration / Initialisierung in einer Zeile
• Deklarationen und Initialisierungen können in einer Zeileerfolgen
• Auch hier lassen sich mehrere Deklarationen vom gleichen Typdurch Kommata voneinander trennen
Beispiel:float größeInCm = 185, gewichtInKg = 79;
String name="Hans Mustermann";
127
Zusammenfassung
• primitive Datentypen– boolean, char, byte, short, int, long, float, double
• Literale– Wahrheitswerte, ganze Zahlen, Fließkommazahlen, Zeichen, String-Literale
• Variablen– Namen
– Deklaration– Initialisierung
Kapitel 7.2
Aufruf von Objekten, einfacher Nachrichtenaustausch
129
Aufruf von Objekten
• Konstruktoren: Aktivitäten bei Objekterzeugung• Referenzen als Verweise auf Objekte• Garbage Collection• Übergabe von Parametern an Methoden• Klassenattribute / Klassenmethoden• Namensraum
– Überladen von Methoden– Überdecken von Attributen
• Vertiefung OO-Programm = Mehrere Objekte + Nachrichtenaustausch– Aufgaben verteilen („Spezialisten“)
130
Konstruktor
• Methode, die automatisch bei Erzeugung eines Objektesaufgerufen wird
• Wird in der Regel benutzt, um Attribute zu initialisieren• Dadurch charakterisiert, daß der Methodenname mit dem
Klassennamen übereinstimmt• Konstruktoren besitzen keinen Rückgabewert (auch nicht
void )
• Überladen von Konstruktoren ist möglich
131
Konstruktoren Aufruf von Objekten
• Methoden für das Durchführen von Arbeiten direkt bei der Objekt-Erzeugung:– Methodenname = Klassenname– Folge von Anweisungen, die abzuarbeiten sind– kein Rückgabewert
class Girokonto {...public Girokonto() {
kontostand = 0;
...
}
}
132
Konstruktor
• Argumente der Konstruktormethode werden beiObjekterzeugung durchnew Klassenname ( Argument1 , Argument2 , ...)an den Konstruktor übergeben
• Ohne Angabe eines Konstruktors ist nur der leere Konstruktorohne Argumente definiert
• Ist ein (nicht leerer) Konstruktor definiert, muß der leereKonstruktor explizit definiert werden, um noch benutzt werdenzu dürfen
133
Referenzen auf Objekte
• Bei primitiven Datentypen enthält eine Variable direkt denInhalt (z. B. einen Int-Zahlenwert)
• Bei Objekten von Klassen symbolisiert die Variable nur eineReferenz (einen Verweis) auf das Objekt
• Es können auch mehrere Referenzen auf ein Objekt zeigen• Ein Referenz kann auch leer sein, null ist das Schlüsselwort
für die leere Referenz
Beispiel:Girokont o k = null;
134
Referenzen auf Objekte
• Mit dem ==-Operator kann man zwei Referenzen aufGleichheit testen:
Beispiel:Girokonto k1 = new Girokonto();
...
Girokonto k2 = k1;
...
if (k1 == k2)
System.out.println( ”k1 und k2 verweisen aufdasselbe Objekt");
135
Referenzen auf Objekte
• Mit dem ==-Operator kann man ebenso abfragen, ob eineReferenz leer ist:
Beispiel:Girokonto k;
...
if (k == null)
System.out.println(”k ist leere Referenz");
136
Garbage Collection
• Ist die letzte Referenz auf ein Objekt verschwunden da– die Referenzen den Gültigkeitsbereich verlassen haben, oder da– null -Referenzen zugeweisen wurden
wird das Objekt der Garbage Collection zugeführt=> es sind keine free - oder delete -Methoden nötig
• Dies funktioniert auch, falls sich Objekte gegenseitig nochzyklisch referenzieren
• MitSystem.gc();
wird eine Empfehlung an die Garbage Collection ausgegeben,aktiv zu werden, in der Regel ist dies aber nicht nötig
137
Klassenattribute und -methoden
Attribute und Methoden gehören zu Objekten (also Instanzen)einer Klasse
Aber: es gibt Klassenattribute und -methoden, die nicht zuInstanzen (also Objekten) gehören, sondern zu den Klassenselbst
138
Klassenvariablen
• Attribute, die für jedes Objekt neue Instanzen bilden, heißenInstanzvariablen (Standardfall)
• Werden Attribute mit static gekennzeichnet, handelt es sichum Klassenvariablen , die für die gesamte Klasse nur eineInstanz besitzen
• Klassenvariablen existieren auch ohne die Existenz einesObjektes. Auf sie kann durch Klassenname. Attributnamezugegriffen werden.
139
Klassenmethoden
• Methoden, die ausschließlich auf Klassenvariablenzurückgreifen, dürfen mit static gekennzeichnet werden, sieheißen Klassenmethoden . Klassenmethoden dürfen auch nurKlassenmethoden benutzen
• Klassenmethoden können auch ohne Existenz eines Objektesmit Klassenname.Methodenname( ...) aufgerufen werden.
• Die main() -Methode ist eine Klassenmethode, da zu Beginnnoch keine Objekte erzeugt wurden
140
Beispielclass Demo {
int a;static int b;
public static void main(String[] args) {
a = 1; // nicht erlaubtb = 1; // erlaubttest(); // nicht erlaubtnew Demo().test(); // erlaubttest2(); // erlaubtnew Demo().test2();// erlaubt
}
void test() {a = 2; // erlaubtb = 2; // erlaubt
}
static void test2() {b = 3;
}}
...Demo d = new Demo();d.a = 1; // erlaubtd.b = 1; // erlaubtDemo.a = 1; // nicht erlaubtDemo.b = 1; // erlaubtDemo.test(); // nicht erlaubtDemo.test2(); // erlaubt
...
141
Überladen von Methoden Aufruf von Objekten
Wunsch für Methoden/Attribute: Gleiche Namen für gleiche Zwecke– z.B. Girokonto erzeugen ohne/mit einem initialem Kontostand
• Benutzt werden sollen Methoden mit gleichen Namen• Problem: Wie diese Methoden auseinanderhalten?• Idee: unterscheide anhand Parameter-Typen:
Methoden gleichen Namens müssen sich also im Typ von mindestenseinem Parameter oder in der Anzahl der Parameter unterscheiden
zahle ( int betrag)zahle ( int betrag, String verwendungszweck)
142
Überladen von Methoden
• Unterschiedliche Methoden müssen sich im Methodennamenoder in der Übergabeparameterliste (oder in beidem)unterscheiden
• Hat eine Klasse mehrere Methoden mit identischem Namennennt man diese Methode überladen
• In unterschiedlichen Klassen dürfen auch Methoden mitidentischem Namen und identischen Übergabeparameterlistendeklariert werden
143
Überdecken von Attributen Aufruf von Objekten
• Verwenden von Variablen mit bereits benutzten Namen• Zugreifen auf überdeckte Attribute über this
public class Girokonto {
private int kontostand; // in Pfennigen gerechnet
...
public void setzeKontostand( int kontostand) {this .kontostand = kontostand;
}
...
}
144
Zugriff auf überdeckte Attribute
• Variablendeklarationen in Klassenmethoden überdecken dieAttribute der Klasse
• Die Attribute sind nur überdeckt, nicht überschrieben• Auf Attribute der Klasse kann dann über das Schlüsselwort
this zugegriffen werden• this ist eine Referenz auf das zur Methode zugehörende
Objekt
145
Übung: Überladen von Konstruktoren, Methoden
Lernziele:
• Erweitern einer Klasse um Attribute und Methoden• Übersicht behalten durch sinnvolles, sparsames Vergeben von Methodennamen
(Namen mehrfach in einer Klasse vergeben)
Aufgabe:
• Implementieren Sie eine zweite Konstruktor-Methode für die Klasse „Girokonto“. Siesoll es ermöglichen, daß schon bei der Erzeugung eines Girokonto-Exemplars einWert für den initialen Kontostand übergeben werden kann. Welchen Namen mußdiese Methode tragen? Der übergebene Parameter soll kontostand heißen. Esgibt in der Klasse "Girokonto" bereits ein Attribut mit diesem Namen.Stellt dies ein Problem dar?
146
Übung: Überladen
Lösungsmuster:– Konstruktor-Methode -> Name identisch mit Klassenname– Überdecken des Namens kontostand (als Attributname und Variablenname)
public class Girokonto {...
public Girokonto( int kontostand) {this .kontostand = kontostand;
}...
}
Aufruf von Objekten
147
Zusammenspiel zwischen Objekten
• In einem OO-System kooperieren Objekte, umgemeinsam eine Aufgabe zu lösen
• Jede Klasse kann etwas besonders gut (Spezialist)– z.B. Klasse "Girokonto" für Umgang mit Girokonten
• Beim Erstellen eines OO-Systems müssen Spezialistenausgemacht werden– z.B. Erweiterung um Währungsrechnen
Aufruf von Objekten
148
Übung: Zusammenspiel von Objekten
Motivation:• Zusammenspiel mehrerer Objekte, Überladen von Namen
• Weg von Anforderungstext zu einer neuen Klasse• Ändern einer bestehenden Klasse
Aufgabe:• Entwerfen und implementieren Sie eine neue Klasse „Waehrungsrechner“ für das
Umrechnen von EuroCent in Pfennige (100 EuroCent ≈ 200 Pfennige)– Überlegen Sie, ob diese Klasse Attribute besitzen muß? Welche könnte sie besitzen?– Ergänzen Sie eine Methode "int wandeleInPfennig (int eurocent)"
und eine Methode "int wandeleInEuroCent (int pfennige)“.
• Die Klasse "Girokonto" soll angepaßt werden:– Einem Girokonto-Objekt soll beim Erzeugen stets ein "individueller" Währungsrechner
übergeben werden können, der für Konvertierungen benutzt wird.– Verstecken Sie nach außen, daß der Kontostand intern stets in EuroCent gespeichert wird
und jede andere Währung konvertiert wird („Information-Hiding“).
Aufruf von Objekten
149
Übung: Zusammenspiel von Objekten
Lösung:
public class Waehrungsrechner {
private int euroFaktor;
public Waehrungsrechner(){
euroFaktor = 2;
}
public int wandeleInEuroCent ( int pfennige){
int euroCent = pfennige / euroFaktor;
return (euroCent);
}
public int wandeleInPfennig ( int euroCent){
int pfennige = euroCent * euroFaktor;
return (pfennige);
}
} →
Aufruf von Objekten
150
Übung: Änderungen in „Girokonto“public class Girokonto {
private int kontostand = 0;
private Waehrungsrechner wr;
public Girokonto(Waehrungsrechner wr) {
this .wr = wr;
}
public Girokonto(Waehrungsrechner wr, int kontostand){
this .wr = wr;
// 1. Umrechnen des Betrags in EuroCent
int euroCent = wr.wandeleInEuroCent(kontostand);
// 2. Konstand aktualisieren
this .kontostand = euroCent;
}
→
Aufruf von Objekten
151
Übung: Änderungen in „Girokonto“public void zahle ( int pfennige){
// 1. Umrechnen des zahlbetrags in EuroCent
int euroCent = wr.wandeleInEuroCent(pfennige);
// 2. Konto aktualisieren
kontostand = kontostand + euroCent;
}
public int holeKontostand(){
// 1. Umrechnen des aktuellen Kontostandes in Pfennige
int pfennige = wr.wandeleInPfennig(kontostand);
// 2. Kontostand in Pfennigen zurückgeben
return (pfennige);
}
Aufruf von Objekten
152
Zusammenfassung
• Konstruktoren• Referenzen• Garbage Collection• Übergabe von Parametern an Methoden• Klassenattribute / Klassenmethoden• Namensraum
– Überladen von Methoden– Überdecken von Attributen
• Vertiefung OO-Programm=Mehrere Objekte + Nachrichtenaustausch– Aufgaben verteilen („Spezialisten“)– Klasse „Waehrungsrechner“
Aufruf von Objekten
Kapitel 7.3
Operatoren, Ausdrücke, Zuweisungen
154
Operatoren, Ausdrücke und Zuweisungen
• Ausdrücke sind mehrere durch Operatoren und Klammernverknüpfte Variablen oder Literale
Beispiel:5*a + 7*(3 - b)
ist ein (in diesem Fall arithmetischer) Ausdruck
• Ausdrücke haben Ergebnisse eines bestimmten Typs, diesesErgebnis kann einer Variablen zugewiesen werden.
Beispiel:c = 5*a + 7*(3-b);
155
Arithmetische Operatoren
• Arithmetische Operatoren: Bildung arithmetischer Ausdrücke
• Arithmetische Operatoren in Java:– Addition (+) und Subtraktion (- )– Multiplikation (* ) und Division (/ ) und– Restbildung („modulo“) (%)
• Zusätzlich:– einstellige Operatoren– Inkrement- und Dekrement-Operatoren mit Nebeneffekten
Programmkonstrukte
156
Arithmetische Operatoren Programmkonstrukte
Operator Bezeichnung Bedeutung+ Positives Vorzeichen +a ist synonym mit a- Negatives Vorzeichen -a kehrt das Vorzeichen um+ Summe a + b ergibt die Summe von a und b- Differenz a – b ergibt die Differenz von a und b* Produkt a * b ergibt das Produkt aus a und b/ Quotient a / b ergibt den Quotienten von a und b% Restwert a % bergibt den Restwert der Division von a durch b
++ Präinkrement ++a ergibt a+1 und erhöht a um 1++ Postinkrement a++ ergibt a und erhöht a um 1-- Prädekrement --a ergibt a–1 und verringert a um 1-- Postdekrement a-- ergibt a und verringert a um 1
In Java läßt sich dieser Operator sowohl auf ganze Zahlen als auch auf Fließkommazahlen anwenden!!
157
Postfix- und Präfix Increment und Decrement
• Inkrement- und Dekrementoperatoren erhöhen, bzw.erniedrigen eine Variable um 1, der Inhalt der Variable wirdzurückgegeben
• ++ ist der Inkrement- und -- der Dekrementoperator
• Steht der Operator vor der Variablen (Präfix), so wird dieVariable zuerst erhöht (bzw. erniedrigt) und dann das Ergebniszurückgegeben
• Steht der Operator hinter der Variablen (Postfix), so wird zuerstdas Ergebnis der Variablen zurückgegeben, bevor sie erhöht(bzw. erniedrigt) wird
158
Arithmetische Operatoren
• Präinkrement
int a = 5;int b = ++a; gleichbedeutend mit a = a + 1;
b = a;Ergebnis: a = 6
b = 6
• Postinkrement
int a = 5;int b = a++; gleichbedeutend mit b = a;
a = a + 1;Ergebnis: a = 6
b = 5
Programmkonstrukte
159
Arithmetische Operatoren ( +, - , * , / , %)
• Arithmetische Operatoren sind Infix-Operatoren• Es gibt Addition (+), Subtraktion (- ), Multiplikation (* ),
Division (/ ) und Modulo-Division (%)
• Modulo-Division bedeutet Divisionsrest, also11 / 3 = 3, Rest 2, damit ist 11 % 3gleich 2
• Arithmetische Operatoren lassen sich (auch in gemischterForm) auf Variablen und Ausdrücke der Typen char , byte ,int , long , float und double anwenden
• Divisionen durch Null sind nur für die Typen float unddouble direkt erlaubt, bei char , byte , int und long wirdeine Exception geworfen (später ausführlicher)
160
Ergebnistypen bei arithmetischen Operatoren
+ - */ %
char byte short int long float double
char int int int int long float double
byte int int int int long float double
short int int int int long float double
int int int int int long float double
long long long long long long float double
float float float float float float float double
double double double double double double double double
161
Ergebnistypen bei arithmetischen Operatoren
Beispiel:short a,b,c; // Deklaration
int d;
a=7; // Initialisierung
b=8;
c = a + b; // Zuweisung unzulässig
d = a + b; // Zuweisung zulässig
Fehlermeldung zur Compilezeit:Incompatible type for =. Explicit cast needed to convert
int to short.
c = a + b;
^
162
Implizite Typwandlungen
• Bei einer Zuweisung muß der Ergebnistyp des Ausdrucks mitdem der Variablen übereinstimmen, es sei denn, impliziteTypwandlungen sind erlaubt
• Implizite Typwandlungen sind in der Regel in Richtunggrößerer Typen erlaubt:
byte shortint long float double
char
• Achtung: Wandlung von long nach float eventuellverlustbehaftet
Hinweis: char nach short wäre prinzipiell verlustfrei möglich, ist aber dennoch unzulässig!
163
Implizite Typwandlungen
Beispiel:double a; // Deklarationen und Initialisierungen
double b=10.0;
int c=10;
a = c; // Zuweisung erlaubt, da Typwandlung
// implizit möglich
c = b; // Zuweisung nicht erlaubt
164
Explizite Typwandlungen (Cast)
• Explizite Typwandlungen sind durch Cast "( typ) " möglich.
Beispiel:double b=10.0;
int c;
c = (int)b; // Zuweisung erlaubt, da Typ gewandelt
• Typwandlungen sind in der Regel verlustbehaftet• Bei Verlusten weder Fehlermeldungen noch Warnungen zur
Laufzeit
165
Explizite Typwandlungen (Cast)
Beispiel: Typwandlung von short nach byte(hier ohne Verlust)
0000000000110001 (16 Bit, Wert entspricht 49)
...
00110001 ( 8 Bit, Wert entspricht 49)
1111111111110001 (16 Bit, Wert entspricht -15)
...
11110001 ( 8 Bit, Wert entspricht -15)
166
Explizite Typwandlungen (Cast)
Beispiel: Typwandlung von short nach byte(hier mit Verlust)
0000001000000010 (16 Bit, Wert entspricht 514)
...
00000010 ( 8 Bit, Wert entspricht 2)
Programm:shor t a = 514;
byte b = (byte)a; // Typwandlung von short nach byte
System.out.println(b);
Programmausgabe:
2
167
Vergleichsoperatoren
• Vergleichen von Ausdrücken
• Ergebnistyp stets boolean
• In Java:– Gleichheitstest (==), Ungleichheitstest (!= )– Größer (>), Kleiner (<)– Größer gleich (>=) und Kleiner gleich (<=)
Programmkonstrukte
168
Vergleichsoperatoren
• Achtung: Gleichheitstest (==) darf nicht mit Zuweisung (=)verwechselt werden
• Vergleich nicht für String geeignet
Programmkonstrukte
Operator Bezeichnung Bedeutung== Gleich a==b ergibt true , wenn a gleich b ist. Im Falle von
Referenztypen ist der Rückgabewert true , wennbeide Werte auf dasselbe Objekt zeigen.
!= Ungleich a!=b ergibt true , wenn a ungleich b ist. Im Falle vonReferenztypen ist der Rückgabewert true , wennbeide Werte auf unterschiedliche Objekte zeigen.
> Größer a > b ergibt true , wenn a größer b ist< Kleiner a < b ergibt true , wenn a kleiner b ist
>= Größer gleich a >= b ergibt true , wenn a größer oder gleich b ist<= Kleiner gleich a <= b ergibt true , wenn a kleiner oder gleich b ist
169
Vergleichsoperatoren Programmkonstrukte
• Veranschaulichung des Operators ==
– Beispiel:int a = 3;int b = 4;int c = 7;
a + b == c ergibt true
170
Zuweisungsoperatoren
• Setzen des Wertes einer Variablen
• = ist der Operator für die Standardzuweisung
• Es gibt viele Zuweisungen mit Nebeneffekten:+=, -= , *= , /= , %=, ^= , &=, |= , <<=, >>= und >>>
a += b bedeutet a = a + b;
a -= b bedeutet a = a - b;
a *= b bedeutet a = a * b;
Programmkonstrukte
171
Zuweisungsoperatoren Programmkonstrukte
Operator Bezeichnung Bedeutung= Einfache Zuweisung a = b weist a den Wert von b zu und liefert b als
Rückgabewert+= Additionszuweisung a += b weist a den Wert von a + b zu und liefert
a + b als Rückgabewert-= Subtraktionszuweisung a -= b weist a den Wert von a – b zu und liefert
a – b als Rückgabewert*= Multiplikationszuweisung a *= b weist a den Wert von a * b zu und liefert
a * b als Rückgabewert/= Divisionszuweisung a /= b weist a den Wert von a / b zu und liefert
a / b als Rückgabewert%= Modulozuweisung a %= bweist a den Wert von a % bzu und liefert
a % bals Rückgabewert&= UND-Zuweisung a &= b weist a den Wert von a & b zu und liefert
a & b als Rückgabewert|= ODER-Zuweisung a |= b weist a den Wert von a | b zu und liefert a
| b als Rückgabewert^= EXKLUSIV-ODER-Zu-
weisunga ^= b weist a den Wert von a ^ b zu und lieferta ^ b als Rückgabewert
172
Zuweisungsoperatoren Programmkonstrukte
• Veranschaulichung der Additionszuweisung
– Beispiel:int a = 3, b = 5;a += b; gleichbedeutend mit a = a + b;
ergibt: a = 8
173
Logische Operatoren
• Vergleichen boolescher Werte
• In Java:– mit Short-Circuit-Evaluation (SCE)
• UND (&&)
• ODER (|| )
– ohne Short-Circuit-Evalutation (Kurzschluß-Auswertung)• UND (&)
• ODER (| )
• Zusätzlich:– logisches NICHT (! )– EXKLUSIV-ODER (^ )
Programmkonstrukte
174
Logische Operatoren Programmkonstrukte
Operator Bezeichnung Bedeutung! Logisches NICHT !a ergibt false , wenn a wahr ist und true , wenn a
false ist&& UND mit SCE a && b ergibt true , wenn sowohl a als auch b wahr
sind. Ist a bereits falsch, so wird false zurückge-geben und b nicht mehr ausgewertet.
& UND ohne SCE a & b ergibt true , wenn sowohl a als auch b wahrsind. Beide Teilausdrücke werden ausgewertet.
|| ODER mit SCE a || b ergibt true , wenn mindestens einer derbeiden Ausdrücke a oder b wahr ist. Ist bereits a
wahr, so wird true zurückgegeben und b nicht mehrausgewertet.
| ODER ohne SCE a | b ergibt true , wenn mindestens einer derbeiden Ausdrücke a oder b wahr ist. Beide Teilaus-drücke werden ausgewertet.
^ EXKLUSIV-ODER a ^ b ergibt true , wenn beide Ausdrücke einenunterschiedlichen Wahrheitswert haben.
175
Logische Operatoren Programmkonstrukte
• Veranschaulichung der Operatoren || und &&
– Beispiel:int a = 3, b = 5, c = 5;
(a == b) || (b == c) ergibt true(a == b) && (b == c) ergibt false
&& false true
false false false
true false true
|| false true
false false true
true true true
176
Bitweise AND, OR, XOR
• Vergleich der einzelnen Bits zweier ganzer Zahlen
• Für alle ganzzahligen primitiven Datentypen
• Es gibt "bitweise und" bzw. AND (&), "bitweise inklusiv oder"bzw. OR (| ) und "bitweise exclusiv oder" bzw. XOR (^ )
• Für jede Position der Bitdarstellung der beiden Eingabezahlenwird ein Bit berechnet und in der Bitdarstellung derErgebniszahl an derselben Position abgelegt (siehe Beispiel)
177
Bitweise AND, OR, XOR
Beispiel:00000011 entspr. 3
00001001 entspr. 9
========
AND: 00000001 entspr. 1
OR: 00001011 entspr. 11
XOR: 00001010 entspr. 10
& 0 1
0 0 0
1 0 1
| 0 1
0 0 1
1 1 1
^ 0 1
0 0 1
1 1 0
Programm:byte a=3, b=9;
System.out.println(a & b);
System.out.println(a | b);
System.out.println(a ^ b);
178
Verschiebeoperatoren
• Durch Verschiebeoperatoren können Bitdarstellungen vonGanzzahldatentypen nach links, bzw. rechts verschobenwerden.
• Links vom Operator steht der zu verschiebende Wert undrechts die Anzahl der Bits, um die verschoben werden soll
• "<<" ist der Links-Shift-Operator und ">>" und ">>>" sindRechts-Shift-Operatoren
• Bei "<<" und ">>>" wird jeweils die Null nachgeschoben, bei">>" das Vorzeichenbit
• a << n entspricht einer Multiplikation mit 2n und a >>> nentspricht einer Division durch 2n.=> Geschwindigkeitsvorteile
179
String-Konkatenation
• Der +-Operator kann verwendet werden, um zwei Objekte derKlasse String zu verknüpfen
• Ist nur einer der Operanden ein Objekt der Klasse String, undein anderer ein primitiver Datentyp, wird letzterer nach Stringgewandelt
Beispiel:int alter = 27;
System.out.println("Alter : " + alte r + " Jahre");
Ausgabe:Alter: 27 Jahre
180
Unäre Operatoren
• Unäre Operatoren werden immer vor einen Ausdruck gestellt• Es gibt Plus- und Minusvorzeichen (+) und (- ), sowie
logische (! ) und bitweise (~) Verneinung.
• Vorzeichen und bitweise Verneinung werden fürGanzzahldatentypen verwendet, die logische Verneinung fürden Datentyp boolean
181
Bedingte Ausdrücke
• Mit bedingten Ausdrücken lassen sich Alternativen inAusdrücken beschreiben
• Sie werden in folgender Form benutzt:Ausdruck1 ? Ausdruck2 : Ausdruck3
• Ausdruck1 muß einen Wert vom Typ boolean haben
• Ausdruck2 und Ausdruck3 sind zwei Ausdrücke mit Wert vomgleichen Typ
• Ist Ausdruck1 gleich true , so wird Ausdruck2 ausgewertet,sonst Ausdruck3
182
Bedingte Ausdrücke
Beispiel 1:int alter = 17;
System.out.println(alter >= 18 ? "volljährig" :"nicht volljährig");
Ausgabe:nicht volljährig
Beispiel 2:int alter = 18;
double Mitgliedsbeitrag = alter >= 18 ? 200 : 100;
System.out.println("Mitgliedsbeitr.:" + Mitgliedsbeitrag);
Ausgabe:Mitgliedsbeitr.:200
183
Operator-Prioritäten
• Die Standard-Richtung für die Auswertung von Operatoren istvon links nach rechts
• Zuweisungsoperatoren werden von rechts nach linksausgewertet
• Operatoren unterliegen einer Prioritätenhierarchie, analog derPunkt- vor Strich-Regel, also der Ausdruck 5 + 3 * 3 + 1repräsentiert den Wert 15 , da die Multiplikation höhere Prioritäthat.
• Operatoren mit höchster Priorität werden zuerst ausgewertet• Durch Klammerung mit runden Klammern ( und ) kann die
vorgegebene Hierarchie überwunden werden
184
Operator-Prioritäten
Kategorie Operatoren
0 Zuweisung = += -= *= /= %= ^=&= |= <<= >>= >>>=
1 Bedingungsoperator ? :
2 logisches Oder ||
3 logisches Und &&
4 bitweise ink. Oder |
5 bitweise exkl. Oder ^
6 bitweise Und &
Niedrigste Priorität
185
Operator-Prioritäten
Kategorie Operatoren
7 Vergleichsop. == !=
8 Vergleichsop. < > <= >= instanceof
9 Verschiebeop. << >> >>>
10 additive Operatoren + -
11 multiplikative Op. * / %
12 Erzeugungs- oderTypumwandlungsop.
new (type) expr
186
Operator-Prioritäten
Kategorie Operatoren
13 unäre Operatoren ++expr -- expr +expr- expr ~ !
14 Postfix-Operatoren [] . expr++ expr--
Höchste Priorität
187
Operator-Prioritäten: Beispiele
int a, b=2;
a = b << 1 + 2;
• Addition hat höhere Priorität als Verschiebeoperatoren• Es wird daher zunächst 1+2 ausgewertet und der Wert von
b (2) dann um das Ergebnis (3) nach links verschoben, manerhält also 16 . Dieser Wert wird dann der Variablen azugewiesen, denn der Zuweisungsoperator hat die niedrigstePriorität
188
Operator-Prioritäten: Beispiele
int a, b=2;
a = (b << 1) + 2;
• Durch die Klammerung wird die Verschiebung zuerstdurchgeführt
• b um eins nach links verschoben ergibt 4. Dann wird 2aufaddiert und das Ergebnis (6) der Variablen a zugewiesen
189
Operator-Prioritäten: Beispiele
int a = 5, b;
a += b = 8;
• Auswertreihenfolge von links rechts nach links• Zunächst wird b die Zahl 8 zugewiesen, dann wird der neue
Wert von b auf a aufaddiert, a erhält also den Wert 13
(a += b) = 8;
• Fehler: Auswertreihenfolge läßt sich nicht verändern, dennAusdrücke dürfen nie links auf einer Zuweisung stehen
190
Zusammenfassung
• Operatoren– arithmetische Operatoren– Vergleichsoperatoren– Zuweisungsoperatoren
– logische Operatoren– bitweise Operatoren– Verschiebeoperatoren
– unäre Operatoren– bedingte Ausdrücke
• Prioritäten
• Typumwandlungen (Type Casting)– implizit / explizit
Programmkonstrukte
Kapitel 7.4
Anweisungen
192
Zur Einordnung
• Programme bestehen aus Klassen.• Eine der Klassen eines Programms hat eine Methode namens
„main“. Mit der wird die Ausführung begonnen.• Danach werden in der Regel Objekte erzeugt, die dann für
bestimmte Aufgaben zuständig sind.• Die Kommunikation zwischen den Objekten erfolgt über den
Aufruf von Methoden / das Versenden von Nachrichten.• Was innerhalb einer Methode passiert, wird durch
Anweisungen festgelegt. Grundbausteine der Anweisungenhaben wir bereits kennengelernt:– Literale und Variable– Operatoren
193
Zur Einordnung
• Der Algorithmus (also die Verarbeitungsvorschrift), der durcheine Methode realisiert wird, wird durch eine Menge vonAnweisungen beschrieben.
• Die Arten von Anweisungen, die hierfür verwendet werden,diskutieren wir im folgenden.
• Danach kennen wir dann alle Grundbestandteile von Java-Programmen.
194
Anweisungen
• Anweisungen (außer Blöcken) werden durch Semikolonvoneinander getrennt.
• Blöcke sind Sequenzen von Anweisungen, in der Regelgeklammert mit {}, sie werden nicht durch Semikolonvoneinander getrennt.
{
konto.zahle(+100);
konto.zahle(+30);
konto.zahle(-20);}
• Deklarationen bzw. Initialisierungen innerhalb von Blöcken sindnur innerhalb dieser gültig.
{Anweisung1;Anweisung2;...
}
195
Anweisungen
• Auch die bereits bekannten– Zuweisungen– Deklarationen und Initialisierungen
sind Anweisungen.
• “Einfache" Anweisungen werden der Reihenfolge nachabgearbeitet.
• Blöcke, Bedingungen, Schleifen und Sprünge sindAnweisungen, sie beeinflussen den Kontrollfluß. Siebeschreiben größere Strukturen als Ausdrücke, jedoch nicht sogroße wie Klassen.
196
Sichtbarkeit in Blöcken
• Da Deklarationen jenseits der äußeren Grenze eines Blocksnicht bekannt sind, stellt sich bei Attributen und Variablen, diein mehreren Blöcken namensgleich deklariert werden, dieFrage, auf welches Attribut durch einen Attributnamen Bezuggenommen wird.
• Der Zugriff auf die „falschen“ Attribute ist eine häufigeFehlerursache.
197
Sichtbarkeit in Blöcken
• Als generelle Regel der Sichtbarkeit läßt sich formulieren:– es wird zunächst im aktuellen (also inneren) Block nach dem Attribut
gesucht,– wird es dort nicht gefunden, wird schrittweise nach außen vorgedrungen
bis ein entsprechend benanntes Attribut gefunden wird.
• Besonders verwirrend kann dabei sein, daß Attribute undVariable erst ab der Deklarationsanweisung bekannt sind.
198
Variablen in Blöcken
• Im Block deklarierte Variablen sind nur im Block sichtbarpublic void zahle ( int betrag) {
int alterKontostand=kontostand;
{ // hier ist der alterKontostand sichtbar
int neuerKontostand = kontostand + 50000;...
// ab hier ist auch neuerKontostand sichtbar
Bildschirm.gibAus(neuerKontostand);
}
// neuerKontostand unsichtbar, alterKontostand sichtbar
int neuerKontostand = 1;
// ab hier dann die neue Variable neuerKontostand sichtbar
kontostand=kontostand + betrag;
}
Programmkonstrukte
199
Bedingtes Verzweigen (if-Anweisung)
• Bedingte Verzweigungen dienen zur Auswahl aus zweiAlternativen (siehe bedingte Ausdrücke)
if ( Ausdruck )
Anweisung1;else
Anweisung2;
• Ausdruck muß ein Wert vom Typ boolean haben• Anweisung1 wird ausgeführt, falls Ausdruck den Wert true
hat, sonst wird Anweisung2 ausgeführt.• Es wird zunächst Ausdruck ausgewertet. In Abhängigkeit vom
Ergebnis dann Anweisung1 oder Anweisung2.
200
Bedingtes Verzweigen (if-Anweisung)
• Der Teil else Anweisung2 ist optional. Liefert Ausdruck false,dann wird die if-Anweisung ohne weitere Ausführungverlassen.
• Unterscheidung zu Ausdruck1 ? Ausdruck2 : Ausdruck3:– bei der bedingten Verzweigung müssen Ausdruck2 und Ausdruck3 nicht
notwendigerweise ein Ergebnis des gleichen Typs liefern.
201
• Die if -Anweisung
if (kontostand < 0)Bildschirm.gibAus("Konto überzogen");
else
Bildschirm.gibAus("Geld vorhanden");
– else -Zweig ist optional
– ausdruck ist true → Ausführen von anweisungAfalse → Ausführen von anweisungB
Bedingtes Verzweigen Programmkonstrukte
if (ausdruck)anweisungA;
elseanweisungB;
ausdruck: boolean
202
Bedingtes Verzweigen
• Blöcke sind Anweisungen=> Mehrere Anweisungen lassen sich innerhalb der
if - oder else -Anweisung gruppieren
if (landeswährung == DM) {
neuerBetrag = betrag * 1.96;
System.out.println("Guthaben:" + neuerBetra g + " DM");
} else
System.out.println("Guthaben:" + betra g + " Euro");
203
Bedingtes Verzweigen
• Bedingte Verzweigungen sind selbst auch Anweisungen=> Schachtelung von if-Abfragen möglich
if (beruf == schüler)
System.out.println("Schülertarif");
else
if (beruf == rentner)
System.out.println("Rentnertarif");
else
System.out.println("Normaltarif");
Der zweite else -Zweig bezieht sich auf die zweite if -Abfrage
204
Bewachte Anweisungenswitch ( Ausdruck ) {
case Konstante1: Anweisungsfolge1;
case Konstante2: Anweisungsfolge2;
...
default: Anweisungefolge_n;
}
• Ausdruck ist vom Typ byte , short , int oder char
• Konstante_i sind Konstanten vom gleichen Typ wie Ausdruck• Anweisungsfolge_i sind Folgen von Anweisungen, die durch
Semikolon voneinander getrennt sind.
205
Bewachte Anweisungen
switch ( Ausdruck ) {
case Konstante1: Anweisungsfolge1;
case Konstante2: Anweisungsfolge2;
...
default: Anweisungefolge_n;
}
• Es wird zunächst Ausdruck ausgewertet.• Alle Anweisungen ab der ersten Konstante, welche gleich dem
Wert des Ausdrucks ist, werden abgearbeitet.
206
Bewachte Anweisungenswitch ( Ausdruck ) {
case Konstante1: Anweisungsfolge1;
case Konstante2: Anweisungsfolge2;
...
default: Anweisungefolge_n;
}
• Die Anweisungsfolge hinter default: wird auch abgearbeitet,falls keine Konstante gleich dem Wert von Ausdruck ist. Diedefault- Zeile ist optional.
• Beispiel 33
207
Bewachte Anweisungenswitch ( Ausdruck ) {
case Konstante1: Anweisungsfolge1;
case Konstante2: Anweisungsfolge2;
...
default: Anweisungefolge_n;
}
• Kommt die Anweisung break; in einer abzuarbeitendenAnweisungsfolge vor, so wird der gesamte von switchgefolgte Block verlassen.
208
Bewachte Anweisungen
• Die switch -Anweisung– default -Teil ist optional
int zensur = 2;switch (zensur) {
case 1:Bildschirm.gibAus("sehr gut");break ;
case 2:Bildschirm.gibAus("gut");break ;
...
default :Bildschirm.gibAus("das ist keine Zensur!");
}
Programmkonstrukte
switch (ausdruck){ case constant1:
anweisung1;
case constant2:
anweisung2;...default :
anweisung;}
ausdruck:byte , short , int , long , char
209
Schleifen
• Schleifen dienen dazu, die gleiche Anweisung mehrfachdurchlaufen zu können
• Diese Anweisung kann auch ein Block sein, also mehrereAnweisungen gruppieren.
• Es gibt Abbruch- bzw. Laufbedingungen für Schleifen• Es gibt 3 Schleifentypen:
while -Schleifen,do-while -Schleifen undfor -Schleifen
210
Schleifen
• Die while -Schleife– Die Laufbedingung Ausdruck ist vom Typ boolean
– Zunächst wird Ausdruck ausgewertet. Falls Ausdruck den Wert trueliefert, wird Anweisung abgearbeitet. Dies wiederholt sich solange, bisAusdruck den Wert false liefert
– Test vor Ausführung der Anweisungsfolge
int a=0;while (a < 100) {
Bildschirm.gibAus(a);a = a + 10;
};
Ausgabe: 0, 10, 20, ..., 90 (nicht mehr: 100)
BEISPIEL 34
Programmkonstrukte
while (ausdruck)anweisung;
ausdruck: boolean
211
Schleifen
• Die do-while -Schleife– Test nach Ausführung der Anweisungsfolge– also mindestens ein Durchlauf
int a=0;do {
Bildschirm.gibAus(a);a = a + 10;
} while (a < 100);
Ausgabe: 0, 10, 20, ..., 90, 100
Programmkonstrukte
doanweisung
while (ausdruck)
ausdruck: boolean
212
for -Schleifen (Zählschleifen)
for ( Initialisierungsliste; Ausdruck; Anweisungsliste)
Anweisung
• Initialisierungsliste ist eine Liste von Ausdrücken, die durchKommata getrennt sind. Sie wird als Initialisierung vor Eintrittin die Schleife abgearbeitet (nur einmal!). Typischerweiseweden hier Zählervariablen vereinbart.
• Ausdruck ist die Laufbedingung und muß daher einen Wertvom Typ boolean liefern. Ist das Ergebnis false , wirdabgebrochen, ansonsten wird als nächstes mit Anweisung derSchleifenrumpf abgearbeitet
213
for -Schleifen (Zählschleifen)
for ( Initialisierungsliste; Ausdruck; Anweisungsliste)
Anweisung
• Anweisungsliste ist eine Liste von Anweisungen, die durchKommata getrennt sind. Sie wird immer nach Anweisungausgeführt
• Nach der Auswertung von Ausdruck wird die Schleife dannfortgesetzt, wenn Ausdruck true liefert.
• Alle Anweisungen können optional weggelassen werden
214
Schleifen
• Die for -Schleife
int i;for (i=0; i<3; i++)
System .out.println(i);
– Ausgabe012
– Endlosschleifefor ( ; ; );
• BEISPIEL 36
Programmkonstrukte
for (init; test; update)anweisung;
test: boolean
215
Markierte Anweisungen
• Eine Anweisung läßt sich durch einen Namen markieren:
Markierung : Anweisung
• Markierung ist ein Bezeichner
Ist Anweisung aus mehreren Anweisungen zusammengesetzt,es ist also zum Beispiel ein Block oder eine Schleife, so gilt:
• Mit "break Markierung" wird Anweisung abgebrochen und mitdem unmittelbar auf Anweisung folgenden fortgefahren
• Mit "continue Markierung" wird Anweisung abgebrochen undvon Beginn an neu gestartet
216
Markierte Anweisungen
Markierung : Anweisung
• Markierung ist nur innerhalb der markierten Anweisung (Block,Schleife o. ä.) sichtbar
• Innerhalb von Bedingungs- und Zählschleifen kann break undcontinue ohne Markierung verwendet werden. Hier wird dieinnerste umgebene Schleife als markiert betrachtet.
• Sprunganweisungen sind in der Regel ein Anzeichenschlechter Strukturierung, sie sollten vermieden werden.
• Immerhin gibt es keine allgemeine Sprunganweisung (goto)!• BEISPIEL 38
217
Markierte AnweisungenBeispiel:
marke1: for (i=1; i<6; i++) {
marke2: for (j=1; j<4; j++) {
System.out.println( i + " / " + j);
if (i == 2)
break marke2; // Äquiv zu
if (i == 4) // break;
continue marke1;
}
System.out.println("=====");
}
Ausgabe:1 / 11 / 21 / 3=====2 / 1=====3 / 13 / 23 / 3=====4 / 15 / 15 / 25 / 3=====
218
Sichtbarkeit
Hier ist a sichtbar
Hier ist test sichtbar
Hier ist b sichtbar
Hier ist c sichtbar
Hier ist d sichtbar
{...
int a;
test : for (a=0; a<100; a++) {
int b;
for (int c=0; c<a; c++) {
System.out.println(a*c);
}
}
int d=7;
System.out.println(a*d);
}
219
Zusammenfassung
• Anweisungen– elementare Anweisungen– Blöcke
– if
– switch
• Schleifen– while
– do-while
– for
• Markierte Anweisungen• Sichtbarkeit
Programmkonstrukte
Programmierkonventionen und Dokumentation
Kapitel 8
221
Programmierkonventionen
• Warum Programmierkonventionen (Code Conventions)?– Nur wenig Software wird ausschließlich vom originalen Autor gewartet– Programmierkonventionen erleichtern Lesbarkeit und Verständlichkeit– selbst geringe Verbesserungen der Wartbarkeit rechtfertigen
Anstrengungen in der Entwicklung
222
Ausblick in die Wartung
Folgende Gegenstände der Wartung können unterschiedenwerden:Beseitigung von Fehlern, die den Software-Einsatz behindern:– echte Entwicklungsfehler– in der Wartung eingefügte Fehler– Sicherstellung der nicht-funktionalen Anforderungen nach
AuslieferungÄnderungen der Umweltbedingungen (Hardware, Fremdsoftware,
Organisation)– Jahr 2000 / EURO– gesetzliche Änderungen– neue Basissystemeneue Anforderungen (die Kenntnis einer Version weckt neue
Anforderungen!)
223
Ein Ausblick in die Wartung
Lehman‘s Law of Uncertainty and Lehman‘s Law of IncreasingSoftware Entropy bedeuten, daß Änderungen während undnach der Entwicklung unvermeidlich sind.
Law of Uncertainty: Software ändert sich während ihresganzen Lebenszyklus. Genauere Angaben zumGegenstand der Änderungen sind nicht vorhersehbar.
Law of Increasing Software Entropy: Änderungen einerSoftware machen ihre Struktur in der Regelunverständlicher. Die innere Struktur einer Software gehtmit fortschreitender Software-Lebenszeit verloren
224
Ausblick in die Wartung
Das Verhältnis von Entwicklungsaufwänden zuWartungsaufwänden wird in der Literatur in einem Bereichzwischen 1:4 und 1:2 angegeben. Das bedeutet, daßzwischen 20% und 33% der gesamten Kosten auf dieEntwicklung entfallen und daß zwischen 80% und 67% aufdie Wartung entfallen!
Deshalb: Programmierkonventionen als eine Maßnahme derVerbesserung der Wartbarkeit!Andere Maßnahmen: Dokumentierte Ergebnisse von OOAund OOD, Verzicht auch Trick-Programmierung
225
Programmierkonventionen
• Wie sollen sie eingesetzt werden?– Die offizielle Konventionen sollten als Basis dienen– Sie funktionieren nur, wenn sie von jedem eingehalten werden– Es kann projektspezifische Erweiterungen geben
226
Datei-Organisation
• Keine Dateien mit mehr als 2000 Zeilen• Abschnitte sollten durch Leerzeilen getrennt werden• Jede Datei sollte nur eine öffentliche Klasse bzw. ein
öffentliches Interface besitzen• Öffentliche Klasse / Interface ist am Dateianfang zu finden• Datei hat vorgegebene Aufteilung:
– Anfangskommentare– Package und Import-Statements– Klassen- und Interface-Deklarationen
227
Ordnung innerhalb einer Datei
Reihenfolge in einer Datei:• Anfangskommentare in C-Format:
/** Klassenname** Versionsinformation** Copyright-Vermerk*/
• Package- und Import-Statementspackage java.awt;
import java.awt.peer.CanvasPeer;
228
Ordnung innerhalb einer Datei
• Klassen- und Interfacedeklarationen in vorgegebenerReihenfolge:– Klassen / Interface - Kommentar (/** ... */ )– class oder interface Definition– Klassen / Interface - Implementierungskommentar, falls nötig (/* ... */ )– Klassenvariablendeklarationen (static )
– Instanzvariablendeklarationen– Konstruktoren– Methoden
(geordnet, also z.B. sollten öffentliche Klassen nicht zwischen privatenstehen)
229
Einrückungen
• Es werden 4 Zeichen eingerückt• Eine Zeile ist maximal 80 Zeichen breit• Regeln für Zeilenumbrüche:
– Umbruch auf höchstmöglicher Ebene– Umbruch vor Operatoren und nach Kommata– Gleiche Hierarchieebenen sollen möglichst in folgender Zeile
untereinanderstehen, falls nicht möglich, ist 8 Zeichen einzurückenz.B.:
var = funktion1(Ausdruck1,funktion2(Ausdruck2,
Ausdruck3));
230
Kommentare
• Block-Kommentare sollen mit führendem * in folgender Formgeschehen:/*
* Dies ist ein Kommentar.*/
• Einzeilenkommentare kommen vor dem entsprechendenProgrammcode mit zugehöriger Einrückung.Vor dem Kommentar steht eine Leerzeileif (Bedingung) {
/* Bedingung wird ausgewertet */...
}
231
Kommentare
• Zeilenendekommentare (// ) am Ende der Zeile solltengenügend eingerückt sein. Sie werden nicht für mehrzeiligeKommentare benutzt, es sei denn, Programmtext wirdauskommentiert
if (personImHaus == TRUE) {
return Zimmernummer; // Raum im Haus
} else {
return Adresse; // Privatadresse
}
232
Deklarationen
• Es sollte möglichst nur eine Deklaration pro Zeile erfolgenString name; // Vor- und Nachname
String straße; // Straße mit Hausnummer
und nichtString name, straße; // Möglichst vermeiden
• Auf keinen Fall dürfen Deklarationen unterschiedlichen Typs,oder Methoden- und Attributdeklarationen in einer Zeile stehenlong kundennummer, getKundennummer(); // Vermeiden
String name, namensliste[]; // Vermeiden
233
Deklarationen
• Deklarationen sollten immer am Anfang eines Blocks stehen• Mit Variablendeklarationen sollte nicht bis zur ersten
Benutzung gewartet werden• Lokale Variablen sollten, sofern möglich bei Deklaration auch
initialisiert werden• Überdeckungen von Variablen einer höheren Ebene sollten
vermieden werden:int zähler;...void funktion() {
if (Bedingung) {int zähler; // Vermeiden!
}}
234
Anweisungen
• Eine Zeile sollte nur einen Ausdruck enthalten:argv++; argc++; // Vermeiden!
• In Blöcken sollten öffnende Klammern am Zeilenende stehen• Struktur von if - und if-else -Anweisungen:
if (Bedingung) {Anweisungen;
}
if (Bedingung) {Anweisungen;
} else {Anweisungen;
}
if (Bedingung) {Anweisungen;
} else if (Bedingung) {Anweisungen;
} else if (Bedingung) {Anweisungen;
}
235
Namenskonventionen
• Klassennamen– Substantive, große Anfangsbuchstaben, ganze Worte, innere Worte
beginnen mit Großbuchstabenclass Datum;
class KundenListe;
• Interfacenamen– Analog zu Klassennamen
• Methodennamen– Verben, klein geschrieben, innere Worte beginnen mit Großbuchstabenint gibKundenListe();
236
Namenskonventionen
• Variablen / Attribute– am Wortanfang klein geschrieben, innere Worte beginnen mit
Großbuchstaben– Namen sollen selbsterklärend seinDatum meinGeburtsDatum = new Datum("1.1.1904");
– Temporäre Variablen dürfen mit einem Buchstaben benannt werdenhierbei gilt:
– i , j , k , mund n werden für Integerzahlen benutzt– c , d und e werden für Zeichen benutzt
• Konstanten– Konstanten werden komplett groß geschrieben, Worte durch "_"
voneinander getrenntint MINIMALE_BREITE = 10;
237
Sonstige Konventionen
• Klassen und Methoden sollten so privat wie möglich deklariertwerden
• Konstanten sollten über Namen in Programmcode eingebautwerden (bis auf bedeutungslose, wie -1 , 0, 1)
• Mehrfachzuweisungen sollten vermieden werdena = b = c; // Vermeiden!
• Klammerungen können selten benutzte Operatorprioritätenverdeutlichen
238
Dokumentation
• Es gibt 3 Sorten von Kommentaren:– // Rest der Zeile wird auskommentiert (C++-Methode)
– /** Ein gesamter Abschnitt wird kommentiert,* Achtung: Schachtelung von Kommentaren ist* nicht möglich (C-Methode)*/
– /*** Eine Klasse oder Methode wird kommentiert,* aus diesem Kommentar lassen sich automatisch* HTML-Dokumentationen erstellen*/
• Automatische Dokumentation geschieht mit Hilfe des Tools"javadoc " von JDK.
239
javadoc - Dokumentation
• /** */ - wird vor Klassen- und Interface-Deklarationen sowievor Methoden, Konstruktoren und Attributdeklarationenberücksichtigt
• Kommentar wird in HTML-Dokumentation von "javadoc "aufgenommen=> HTML-Tags im Kommentar sind erlaubt
• /** ist Kommentaranfang und */ ist Kommentarende• Innerhalb des Kommentars wird ein * am Zeilenanfang
ignoriert• Erster Satz des Kommentars ist gesonderter
Zusammenfassungssatz. (Punkt als Endmarkierung)
240
javadoc - Dokumentation
• Durch @-Zeichen innerhalb des Kommentars werden Tagseingefügt, um automatische Querreferenzen zu erzeugen:
• @see-Tag erzeugt allgemeine Querreferenz– Referenz zu anderer Klasse:
@see java.io.InputStream@see String
– Referenz zu einer Methode einer Klasse:@see String#equals
– Referenz zu anderer HTML-Datei:@see <a href="spec.html">Java Spec</a>
• @author -Tag um Autor zu kennzeichnen– @author Albert Einstein
– @author Albert Einstein, Max Born, Werner Heisenberg
241
javadoc - Dokumentation
• @version -Tag kennzeichnet Version– @version 1.01beta
• @param-Tag– Erklärung für Parameter in Methoden und Konstruktorendeklarationen:– @param Name Name der Person muß übergeben werden
• @return -Tag– Bedeutung des Rückgabeparameters
• @exception -Tag– Erklärung von Ausnahmen in Methoden und Konstruktordeklarationen:– @exception IndexOutOfBoundsException
Die Feldgrenze wird überschritten
• @deprecated -Tag (ab JDK 1.1)– Kennzeichnung veralteter Methoden
242
javadoc-Beispiel/* Copyright (c) 1999 by
* adesso-GmbH.* Dieser Kommentar soll nicht* mit aufgenommen werden*/
/*** Klasse, um Datum zu* erfassen.* @see java.util.Date* @version 0.9*/
public class Datum {private int jahr;private int monat;private int zag;
/*** Datum wird gesetzt.* Es wird deutsche Notation* erwartet.*/
void setzeDatum(String arg){...
}
/*** Wochentag wird berechnet.* Datum wird in deutscher* Notation zurückgegeben.*/
String Wochentag() {...
}}
Kapitel 9
Rekursive Methodennach Doberkat/Dißmann Kapitel 3
244
Struktur dieses Kapitels
Ein paar rekursive Methoden
Rekursives Sortieren am Beispiel Heapsort
Ein paar Überlegungen zur Überführung rekursiver in iterativeMethoden
245
Fakultäts-Methode
Die Fakultätsfunktion wird für positive ganzzahlige nfolgendermaßen definiert:
n! = 1, falls n = 1n * (n-1)!, sonst
Das läßt sich unmittelbar in einen Algorithmus umsetzen.
public double Fakultät (int n) { // Methodendeklaration
return ( n = 1 ? 1 : n*Fakultät(n-1));
}
{
246
Rekursive Fakultäts-Methode
Überlegung: Was passiert hier bei der Ausführung?
Beispiel: Fakultät(4)
Es wird der Namensraum für einen Methodenaufrufaufgebaut. Hierin ist der Parameter n = 4 bekannt.Beim Aufruf wird die Operation 4 * Fakultät(3) ausgewertet.
Hierzu wird der Namensraum für einen Methodenaufrufaufgebaut. Hierin ist der Parameter n = 3 bekannt.Beim Aufruf wird die Operation 3 * Fakultät(2) ausgewertet.
247
Rekursive Fakultäts-Methode
Beispiel: Fakultät(4) (Fortsetzung)Es wird der Namensraum für einen Methodenaufrufaufgebaut. Hierin ist der Parameter n = 2 bekannt.Beim Aufruf wird die Operation 2 * Fakultät(1) ausgewertet.
Hierzu wird der Namensraum für einen Methodenaufrufaufgebaut. Hierin ist der Parameter n = 1bekannt.Es wird das Ergebnis 1 zurückgeliefert.
2 * Fakultät(1) wird damit zu 2 * 1, das Ergebnis 2 wirdzurückgeliefert.
248
Rekursive Fakultäts-Methode
Beispiel: Fakultät(4) (Fortsetzung)
3 * Fakultät(2) wird damit zu 3 * 2, das Ergebnis 6 wirdzurückgeliefert.
4 * Fakultät(3) wird damit zu 4 * 6, das Ergebnis 24 wirdzurückgeliefert.
Dieses Beispiel zeigt, daß bei rekursiven Methode der Stapelzur Verwaltung der aktuellen Methodenaufrufe (kurz: Aufruf-
Stack) stark wachsen kann.
249
Rekursive Fakultäts-Methode
n=1 1
n=2 2
n=3 6
n=4 24
250
Iterative Fakultäts-Methode
Beispiel: Ausgabe der Fakultäten von 0! bis 10!
class Fakultaetsberechnung {
public static void main(String[] args) {
for (int i=0; i<=20; i++)
System.out.println(rechneFak(i));
}
static double rechneFak(int n) { // Methodendeklaration
double ergebnis = 1;
for (int i=1; i<=n; i++)
ergebnis *= i;
return ergebnis; // Rückgabe
}
}
251
Iterative Fakultäts-Methode
Bei der iterativen Version der Fakultäts-Methode wird nur eineMethode aufgerufen.
Die liefert als Ergebnis den Fakultätswert, ohne daß weitereMethodenaufrufe abgearbeitet werden müssen.
252
Rekursive Fibonacci-Methode
Beispiel: Fibonacci-Zahlen, positive, ganzzahlige Eingabe
public int fib(int n) {
if (n < 3)
return (1);
else
return (fib(n-1) + fib (n-2));
}
Ein Aufruf von fib führt zu zwei weiteren Aufrufen, dabeiwird der Parameter kontinuierlich kleiner.
Wie verhält sich hier der Aufruf-Stack?
253
Rekursion
• Ruft eine Anweisung innerhalb einer Methode die eigeneMethode auf, bezeichnet man dies als rekursiven Aufruf .
• Die Methode wird rekursive Methode genannt.• Bei einem rekursiven Aufruf einer Methode erhalten alle lokal
definierten Variablen einen neuen, unabhängigenNamensraum. Für die ausführende Maschine istbedeutungslos, ob es sich um einen rekursiven Aufruf handelt!
• Rekursive Implementierungen sind oft einfacher zu verstehen,als iterative Implementierungen (vgl. Fakultät, Fibonacci).
• Iterative sind hingegen in der Regel performanter.
254
Rekursion
Für die Definition einer rekursiven Methode werden benötigt:• Eine Beschreibung, wie sich der Wert eines »größeren«
Objekts aus den Werten für »kleinere« Objekte ergibt.• Eine Terminierungsbedingung : Ist diese Bedingung erfüllt, so
muß angegeben werden, wie sich der Wert berechnen läßt,ohne noch einmal auf die rekursive Methode zuzugreifen.
• Jeder Aufruf einer rekursiven Methode muß im Verlauf derAuswertung direkt (also im Aufruf selbst) oder indirekt (also imRahmen weiterer rekursiver Aufrufe) dieTerminierungsbedingung erreichen.
255
Rekursive Datenstrukturen
Rekursion ist nicht nur ein wichtiges Hilfsmittel für dieFormulierung von Algorithmen, sondern auch für dieFormulierung von Datenstrukturen.
Beispiele:Eine Liste ist ein Einzelelement gefolgt von einer Liste oder dieleere Liste.Eine Menge ist leer oder eine einelementige Menge vereinigtmit einer Menge.Oder Bäume (dazu im folgenden mehr).
256
Rekursion - Bäume
Nicht-rekursive Definition von Bäumen:
Ein Baum B besteht aus Knoten V und Kanten E, also B = (V,E).Knoten tragen Information, sie sind über Kanten miteinanderverbunden, also E = V x V.
Kanten eines Baumes sind gerichtet, sie sind also ein Paar vonKnoten (v1,v2). In einer Kante e = (v1,v2) wird v1 derVaterknoten und v2 der Sohnknoten von e genannt.
257
Rekursion - Bäume
Im Unterschied zu den allgemeineren Graphen sind Bäumehierarchisch, das heißt, es gibt keine zyklischen Verbindungenzwischen Knotenmengen.
∀∀∀∀ e = (v1,v2) ∈∈∈∈ E :¬ ( ∃∃∃∃ i ∈∈∈∈ ΝΝΝΝ, i ≥≥≥≥ 2 ∧∧∧∧ v21, ..., v2i ∈∈∈∈ V | v21 = v2, v2i = v1,
(v21,v22), ..., (v2i,v1) ∈∈∈∈ E)
Ein Binärbaum (auch binärer Baum) ist dann ein Baum, in demjeder Knoten maximal zwei Sohnknoten hat, d.h.
∀∀∀∀ v ∈∈∈∈ V : | { v i ∈∈∈∈ V | (v,v i) ∈∈∈∈ E } | ≤≤≤≤ 2
258
Rekursion - Bäume
Rekursive Definition von binären Bäumen:Die Grundstruktur eines Baumes läßt sich leicht rekursiv
definieren:Ein binärer Baum ist entweder leer oder er hat die folgendeForm:
w
B1 B2wobei w ein Knoten und B1, B2 binäre Bäume sind. Zusätzlichgilt, daß ein binärer Baum nur endlich viele Knoten hat(Terminierungsbedingung!).
259
Rekursion - Bäume
Der Knoten w, mit dem B1 und B2 oben verbunden sind, heißt dieWurzel von B.
B1 und B2 heißen linker bzw. rechter Unterbaum der Wurzel w.
Falls vorhanden, heißen die Wurzeln von B1 und B2 linker bzw.rechter Sohn der Wurzel von B.
Besitzt ein Knoten weder einen linken noch einen rechten Sohn,so wird er als Blatt bezeichnet.
260
Rekursion - Bäume
Blätter auf einer Ebene
Blätter auf mehreren Ebenen
Wurzel
Innere Knoten
Blätter
261
Rekursion - Bäume
Ein Blatt ist dadurch ausgezeichnet, daß der linke und der rechteUnterbaum leer sind.
Ein innerer Knoten hat die Eigenschaft, daß der rechte oder derlinke Unterbaum nicht leer ist und daß es sich nicht um die Wurzelhandelt.
Die Wurzel ist dadurch charakterisiert, daß sie kein Sohn einesanderen Knotens ist.
262
Bäume - Formalisierung der rekursiven Def.Der leere Baum wird durch die leere Menge Ø dargestellt, seineKnotenmenge ist leer, also
Knoten(Ø) := Ø .Seien B1 und B2 binäre Bäume, so daß ihre Knotenmengendisjunkt sind, es gilt also
Knoten( B1) ∩∩∩∩ Knoten( B2) = Ø .Sei weiterhin w ein Knoten mit w ∉ Knoten( B1) ∪ Knoten( B2) ,dann heißt
B := ( w, B1, B2)ein binärer Baum mit der Knotenmenge
Knoten( B) := { w} ∪∪∪∪ Knoten( B1) ∪∪∪∪ Knoten( B2) ,der Wurzel w, linkem Unterbaum B1 und rechtem Unterbaum B2.Innere Knoten und Blätter lassen sich in dieser Formulierungebenfalls mathematisch präzise beschreiben.
263
Rekursion - Auf dem Weg zu Heapsort
Problem: Gegeben sei ein Feld a mit n Werten, die sortiertwerden müssen.
Ausgangssituation: Werte im Feld sind unsortiert
Ziel: sortiertes Feld
Idee 1: kleinsten Wert suchen, diesen mit dem ersten Werttauschen, fast immer sehr langsam
Idee 2: benachbarte Werte tauschen, wenn der zweite Wertgrößer ist. Solange bis alles sortiert ist. Langsam, wenn von vornenach hinten durchgetauscht werden muß.
Idee 3: Verwendung eines Binärbaums (Heapsort)264
Rekursion - Auf dem Weg zu Heapsort
Wir verwenden die Zahlen 1 … n zur Numerierung der Knoteneines binären Baums: 1 bildet die Wurzel, und derKnoten i > 1 hat i/2 als Vater, so daß der linke Sohn einesKnotens gerade und der rechte Sohn eines Knotens ungerade ist,sofern der Knoten diese Söhne hat.
Damit können wir ein Feld ebenfalls als Baum darstellen: Ist dasFeld a mit n Komponenten gegeben, so beschriften wir denKnoten i mit dem Feldelement a[i] . Im folgenden Beispielhaben wir das Feld mit denElementen 7, 12 , 0, 5, 9, 1, 3, 8, 13 , 10 , 15 als binärenBaum dargestellt. Die Knoten i werden mit ihrerBeschriftung a[i] angegeben.
265
Rekursion - Auf dem Weg zu HeapSort
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
12
5
8 13 10 15
9
0
1 3
266
Rekursion - Auf dem Weg zu Heapsort
Ein Feld genügt der Heap-Bedingungim Knoten i , falls imUnterbaum mit Wurzel i jeder Knoten eine kleinere Beschriftungals seine Söhne trägt.
Die Heap-Bedingung ist in den Knoten 3, 4, 5, 6, 7, 8, 9, 10, 11erfüllt, nicht jedoch im Knoten 2, da
a[2] = 12 , a[4] = 5 und a[5] = 9
aber 12 > 5 und 12 > 9 ,
und auch nicht im Knoten 1, da
a[3] = 0 und 7 > 0 .
267
Lokale Gültigkeit der Heap-Bedingung
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
12
5
8 13 10 15
9
0
1 3
Heap-Bedingung im Teilbaum erfüllt268
Rekursion - Auf dem Weg zu Heapsort
Die Heap-Bedingung kann jedoch im Knoten 2 wie folgthergestellt werden:
Wir vertauschen die Beschriftung im Knoten 2 mit derBeschriftung desjenigen Sohnes, der die kleinereBeschriftung trägt. In diesem Fall handelt es sich um denKnoten 4. Wir nehmen hierzu die kleinere derBeschriftungen der Söhne, damit im Knoten 2 die Heap-Bedingung lokal erfüllt ist: Die Beschriftung des Knotens 2ist kleiner als die Beschriftungen seiner Söhne (Ergebnisvgl. folgende Folie).
269
Rekursion - Auf dem Weg zu Heapsort
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
5
12
8 13 10 15
9
0
1 3
270
Herstellung der lokalen Heap-Bedingung im Knoten 2
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
5
12
8 13 10 15
9
0
1 3
271
Rekursion - Auf dem Weg zu Heapsort
Nun ist zwar die Heap-Bedingung im Knoten 2 lokal hergestellthaben. Als Folge ist sie aber im Knoten 4 verletzt ist!
Die Vertauschung der Beschriftung eines Knotens mit derkleineren Beschriftung eines seiner Söhne, läßt sich an dieserStelle wiederholen, so daß die Beschriftung 12 in ein Blatt, denKnoten 8, wandert.
Trivialerweise ist die Heap-Bedingung in einem Blatt erfüllt, sodaß wir durch das beschriebene Vorgehen schrittweise dafürgesorgt haben, daß die Heap-Bedingung im Knoten 2 hergestelltwurde.
272
Rekursion - Auf dem Weg zu Heapsort
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
5
8
12 13 10 15
9
0
1 3
273
Herstellung der Heap-Bedingung im Knoten 2
Knoten 2
Knoten 11Knoten 10Knoten 9Knoten 8
Knoten 7Knoten 6
Knoten 5Knoten 4
Knoten 1
Knoten 3
7
5
8
12 13 10 15
9
0
1 3
274
Rekursion - Auf dem Weg zu Heapsort
Die Heap-Bedingung gilt aber immer noch nicht für denKnoten 1, da die Beschriftungen beider Söhne, der Knoten 2 und3 kleiner sind als die Beschriftung der Wurzel des Baumes.
275
Rekursion - HeapsortDefinition: Das Feld a[1] , …, a[n] heißt ein Heap, falls dieHeap-Bedingung im Knoten 1 erfüllt ist. Hieraus ergibt sichunmittelbar als Konsequenz, daß das kleinste Element in einemHeap immer in der Wurzel, d.h. in a[1] , steht.
Der populäre Sortieralgorithmus Heapsort arbeitet in zweiPhasen:
Es ist ein Feld a mit n Elementen gegeben.
In der ersten Phase wird dieses Feld in einen Heapumgestaltet, d.h. es wird dafür gesorgt, daß derentsprechende binäre Baum die Heap-Bedingung imKnoten 1 erfüllt.
In der zweiten Phase wird aus dem zuvor aufgebautenHeap systematisch ein geordnetes Feld erzeugt.
276
Rekursion - Heapsort1. Heap-Aufbau: Idee: Sei in i die Heap-Bedingung nicht erfüllt (iist also kein Blatt), wohl aber in allen Söhnen. Dann werdenfolgende Vertauschungen vorgenommen:
2*i < n, 2*i + 1 > n :vertausche a[i] mit a[2*i] . Da i nur einen Sohn hat,ist die Heap-Bedingung in diesem Knoten erfüllt.
2*i < n, 2*i + 1 < n : suche den Sohn k ,
k ∈∈∈∈ {2i, 2i+1} , so daß gilt:a[k] = min {a[2*i], a[2*i + 1]} ,vertausche a[i] mit a[k] und wende rekursiv dieseIdee auf k an.
277
Rekursion - HeapsortDies führt zum Algorithmus Heapify , der rückwärtsgehend fürjeden Knoten k = n/2 , …, 1 die Heap-Bedingung erfüllt.
Rückwärtslaufen ist nötig, denn der Algorithmus sorgt dafür, daßaus kleineren Heaps größere aufgebaut werden.
Wenn wir in einem Knoten sind, dessen Unterbäume beide dieHeapbedingung erfüllen, so wird durch die Bewegung desKnotenelements ja lediglich einer der Unterbäume modifiziert, derandere Unterbaum bleibt in diesem Durchlauf unverändert.
278
Rekursion - HeapsortDie Methode Heapify bekommt als Eingabe denKnoten dieserKnoten und die aktuelle heapGröße desFeldes.
Im ersten Schritt werden zunächst der linke und der rechte Sohnbestimmt. Danach findet eine Fallunterscheidung statt. Dabei wirduntersucht, ob der linke Knoten noch im Feld und der rechteKnoten nicht mehr im Feld liegt: In diesem Fall muß lediglichgetestet werden, ob die Beschriftung des Knotens größer ist alsdie Beschriftung seines einzigen Sohnes.
279
Rekursion - HeapsortDer zweite Fall besteht darin, daß auch der rechte Knoten nochim Feld liegt: In diesem Fall muß der Knoten mit der kleinerenBeschriftung herausgesucht werden und die Beschriftung diesesKnotens mit der Beschriftung des eingegebenen Knotensverglichen werden. Falls es sich hierbei herausstellt, daß dieHeap-Bedingung verletzt ist, wird mit Hilfe der elementarenMethode Tausche der Inhalt dieses Knotens mit dem seinesSohnes vertauscht und Heapify mit dem Sohn und derHeapgröße erneut aufgerufen.
280
Rekursion - Heapsortvoid Heapify(int dieserKnoten, int heapGröße) {
int links = 2 * dieserKnoten,rechts = links + 1,derSohn;
if (links <= heapGröße && rechts > heapGröße) {if (a[dieserKnoten] > a[links])
Tausche(dieserKnoten, links);} else if (rechts <= heapGröße) {
derSohn = (a[links] < a[rechts] ? links :rechts);
if (a[derSohn] < a[dieserKnoten]) {Tausche(dieserKnoten, derSohn);Heapify(derSohn, heapGröße);
}}}
281
Rekursion - HeapSortNachdem Heapify in der beschriebenen Art aufgerufen wordenist, stellt das Feld a einen Heap dar, der jetzt dazu herangezogenwerden kann, das Feld zu sortieren.
Wir hatten gerade festgestellt, daß das kleinste Element in derWurzel liegt. Also vertauschen wir zunächst a[1] mit a[n] .
Damit haben wir bereits ein Element des Feldes, das kleinste,sortiert. Um das zweitkleinste Element zu bestimmen, sorgen wirnun dafür, daß die restlichen n-1 Elemente wieder einen Heapbilden.
Anschließend können wir dessen Wurzel und a[n-1] miteinander vertauschen und haben bereits zwei Elementedes Feldes sortiert, und so geht es weiter, bis alle Elementesortiert sind. 282
Rekursion - HeapSort
Auf der folgenden Folie wird dieser erste Sortierschritt an einemBeispiel gezeigt.
Die übernächste Folie demonstriert dann die nächsten beidenSortierschritte, nach deren Ausführung bereits die drei letztenElemente des Feldes sortiert sind, so daß nun nur noch n-3 Elemente betrachtet werden müssen.
Das Feld ist vollständig sortiert, wenn der im nächstenSortierschritt noch zu betrachtende Heap nur noch aus der Wurzelbesteht.
283
Sortieren mit einem Heap - erster Sortierschritt
4
9 12 8
Aufgebauter Heap 1
6
74
9 12 1
erster Sortierschritt 8
6
7
bereits sortiert
Austausch
bereits sortiert
8
9 12 1
Reorganisation desHeaps
4
6
7284
Sortieren mit einem Heap - 2. / 3. Sortierschritt
8
9 12 1
Zweiter Sortierschritt 7
6
4 8
9 12 1
Reorganisation desHeaps
6
7
4
8
9 6 1
Dritter Sortierschritt 12
7
4
bereits sortiert
285
Rekursion - HeapsortDer Konstruktor für die Klasse Heap allokiert das Feld a.Da a[0] nicht benutzt wird, benötigen wir ein Feld mitk+1 Elementen, um k Zahlen zu speichern.
Die Initialisierung von a passiert über die Methode Setze .
Neben der bereits bekannten, privaten Methode Heapify werdendie parameterlosen Methoden BaueHeap und Sortiereimplementiert. Zusammen realisieren sie den AlgorithmusHeapsort.
286
Rekursion - HeapSortDer Aufbau eines ersten Heaps aus einem gegebenen Felderfolgt durch den Aufruf der Methode BaueHeap.
Da jedes Blatt des Baumes für sich bereits einen Heap bildet,beginnen wir in der Mitte des Feldes mit dem Aufrufvon Heapify und bauen so immer größere Heaps auf.
Anschließend führt die Methode Sortiere das bereitsvorgestellte Vorgehen mit Vertauschen und Reorganisieren durch.
Das Auslesen eines sortierten Feldes kann durch die mehrfacheAusführung der Methode Gib erfolgen
287
Rekursion - Klasse Heapclass Heap {
private int[] a;
Heap(int k) {a = new int[k+1];
}
void Setze(int i, int x) { a[i] = x; }
int Gib(int i) { return a[i]; }
private void Tausche(int eins, int zwei) {int t = a[eins];a[eins] = a[zwei];a[zwei] = t;
} 288
Rekursion - Auf dem Weg zu Heapsortprivate void Heapify(int dieserKnoten, int heapGröße)
{ wie vorne definiert }
void BaueHeap() {for (int i = (a.length-1)/2; i >= 1; i--)
Heapify(i, a.length-1);}
void Sortiere() {BaueHeap();for (int i = a.length-1; i > 1; i--) {
Tausche(1, i);Heapify(1, i-1);
}}
289
Klassifikation rekursiver Methoden
Definition:
Eine rekursive Methode heißt linear , wenn in den einzelnen
Zweigen der bedingten Anweisung, die die rekursiven Aufrufesteuert, jeweils höchstens ein Aufruf der Methode vorkommt.
Beispiele:
Die Methode Fakultät ist linear.
Die Methode Heapify ist linear.
Die Methode Fibonacci ist nicht linear.
290
Klassifikation rekursiver Methoden
Definition:
Eine lineare rekursive Methode heißt schlicht, wenn lediglich
der Wert eines früheren Aufrufs übertragen eingeht.
Beispiele:int F(int x, int y)) {
int t = 0;if (y == 0)
t = x;else if (y > 0)
t = F(x * y, y - 1);return t;
Fakultät ist nicht schlicht, denn es wird nachdem Aufruf noch multipliziert.
291
Klassifikation rekursiver Methoden
Eine systematische Transformation schlichter rekursiverMethoden in nicht-rekursive Methoden ist auf einfache Weisemöglich. Wir erläutern dies zunächst an einem Beispiel.
Beispiel:Sei F gegeben wie oben definiert. Wir berechnen F(a, 3)schrittweise:
F (a, 3) = F (a*3, 2)= F (a*3*2, 1)= F (a*3*2*1, 0)= a*3*2*1
292
Klassifikation rekursiver Methoden
Behauptung:∀∀∀∀ n ≥≥≥≥ 0 gilt F (x, n) = x * n! .
Beweis (durch vollständige Induktion):
Induktionsverankerung n = 0:F (x, 0) = x = x * 0!
Induktionsschritt: Induktionsvoraussetzung ist:
F (x, n) = x * n! ∀∀∀∀ x ∈∈∈∈ N0
Wir wollen zeigen: ∀∀∀∀ x ∈∈∈∈ N0 : F (x, n+1) = x*(n+1)!
F(x, n+1) = F (x*(n+1), n) = x*(n+1)* n! = x*(n+1)!
Induktionsvoraussetzung
293
Klassifikation rekursiver MethodenDies führt zu einer nicht-rekursiven Lösung. Das erste Argumentwird als eine Art Akkumulator eingesetzt wird: Die Resultatewerden im ersten Argument so lange angesammelt, bis y denWert 0 erreicht hat. Dann werden sie ausgegeben.
int Iterativf (int x, int y) {int x1 = x, y1 = y, tx, ty;while (y1 > 0) {
tx = x1 * y1;ty = y1 - 1;x1 = tx;y1 = ty;
}return x1;
294
Klassifikation rekursiver Methoden
Beh.: F(x,y) = Iterativf(x, y)
Beweis (durch vollständige Induktion nach y):
Induktionsverankerung: Für y=0 : Iteratif (x,y) = x = x * 0! = F(x, y).
Induktionsschritt: Die Behauptung gelte für ein y ∈ N0. Wir müssenihre Gültigkeit für y+1 nachweisen. Es muß also gezeigt werden,daß nach x1 = x;
y1 = y+1;while(y1 > 0) { …}
von Iterativf der Wert F(x, y+1) geliefert wird.
295
Klassifikation rekursiver MethodenDie Schleife kann, da y+1 > 0, umformuliert werden zu:
tx = x1 * y1;ty = y1 - 1 ; // 1x1 = tx;y1 = ty; // 2while(y1 > 0) {…}
296
Klassifikation rekursiver MethodenIn // 1 gilt: x1 = x; y1 = y + 1;
also: tx = x * (y + 1); ty = y;
Daraus erhält man in // 2 (durch Einsetzen):
x1 = x * (y + 1); y1 = y;
Mit diesen Anfangswerten wird die Bedingungsschleife betreten,nach Induktionsvoraussetzung liefert Iterativf dann den Wert
F(x * (y+1), y)= x * (y+1) * y! = x*(y+1)! = F(x , y + 1)
was zu zeigen war.
297
Klassifikation rekursiver MethodenVerallgemeinerung der Umformulierung der Schleife:
Ist P(x) eine Aussage über x und sind I 1(x), I 2(x)Anweisungen, so daß I 2(x) den Wert von x ändert, so sind diebeiden folgenden Code-Fragmente gleichwertig.
if(P(x)){I 2(x);
}while(P(x)){
I 2(x);}I 1(x);
while(P(x)){I 2(x);
}I 1(x);
298
Verallgemeinerung dieses VorgehensGegeben sei die schlicht rekursive Methode:
int F(int x, int y) {
… // Deklarationen ausgelassen
return (y > 0 ? F( µµµµ(x, y), y-1) : νννν(x));}
299
Verallgemeinerung dieses VorgehensHier hängen die Funktionen νννν und µµµµ weder direkt noch indirektvon F ab. Die Methode F wird analog zum vorhergehendenBeispiel transformiert in:
int Iterativf (int x, int y) {// ohne Deklarationenx1 = x; y1 = y;while (y1 > 0) {
tx = µµµµ(x1, y1); ty = y1 -1;x1 = tx; y1 = ty;
}return νννν(x1);
}
300
Verallgemeinerung dieses Vorgehens
Derselbe Beweis, den wir gerade für die Fakultätsfunktiondurchgeführt haben, zeigt, daß die rekursive Methode F und dieiterative Methode Iterativf äquivalent in dem obenbesprochenen Sinne sind.
Wir merken abschließend an, daß die Verallgemeinerung auf mehrals zwei Argumente leicht möglich ist.
Kapitel 10
Verschachtelte Klassen (nested classes) /Innere Klassen (inner classes)
302
Verschachtelte Klassen
Definition: Eine verschachtelte Klasse (nested class) ist eineKlasse, die Mitglied einer anderen Klasse ist. Wenn sie staticist, dann spricht man von einer static verschachtelten Klasse.Non-static verschachtelte Klassen heißen auch innere Klassen(inner class).
Man verwendet verschachtelte Klassen, um die Beziehungenzwischen Klassen zu veranschaulichen. Man sollte eine Klasseals verschachtelte Klasse einer umgebenden Klassedefinieren, wenn sie nur in dieser Umgebung Sinn macht odersogar auf die Funktionalität der umgebenden Klasseangewiesen ist.
Beispiel: Textcursor-Klasse in Textverarbeitungsklasse
303
Verschachtelte Klassen
„As a member of its enclosing class, a nested class has a specialprivilege: It has unlimited access to itsenclosing class's members, even if they are declared private.
However, this special privilege isn't reallyspecial at all. It is fully consistent with the meaning of private
and the other access specifiers. The accessspecifiers restrict access to members for classes outside of the
enclosing class. The nested class is insideof its enclosing class so that it has access to its enclosing
class's members.“
(aus dem Java Tutorial)
304
Verschachtelte Klassen
Verschachtelte Klassen können als static definiert werden, dannheißen sie static nested classes . Eine non-staticverschachtelte Klassen heißt inner class.
class EnclosingClass{
. . .
static class AStaticNestedClass {...}
class InnerClass {...}
}
305
Verschachtelte Klassen
Wie für static Methoden und Variablen üblich gilt:„... a static nested class is associated with its enclosing class.And like class methods, a static nested class cannot referdirectly to instance variables or methods defined in itsenclosing class-it can use them only through an objectreference.“ (Java Tutorial)
„As with instance methods and variables, an inner class isassociated with an instance of its enclosing classand has direct access to that object's instance variables and
methods. Also, because an inner class isassociated with an instance, it cannot define any static
members itself.“ (Java Tutorial) 306
Verschachtelte Klassen
Zur Unterscheidung:„nested class“ reflektiert die syntaktische Beziehung zwischenKlassen (der Code einer Klasse erscheint im Code eineranderen).
„inner class“ reflektiert die Beziehungen zwischen Objekten derKlassen.
307
Verschachtelte Klassen
• Verschachtelte Klassen dienen dazu, Klassen die nur lokalbenötigt werden, im lokalen Rahmen zu definieren.
• Zweck der Verwendung verschachtelter Klassen ist es,größtmögliche Übersicht zu gewährleisten.
• Es gibt insgesamt 4 Arten von verschachtelten Klassen:• static verschachtelte Klassen• innere Klassen• lokale Klassen (local classes)• anonyme Klassen (anonymous classes)
308
Innere Klassen
class EnclosingClass {
. . .
class InnerClass { . . . }
}
Ein Objekt der Klasse InnerClass kann nur im Rahmen einesObjektes der Klasse EnclosingClass existieren. Es hatdirekten Zugriff auf Instanzvariablen und Methoden desumgebenden Objekts.
309
Innere Klassen
Innere Klassen sind die wichtigste Anwendung verschachtelterKlassen!
Innere Klassen werden oft im Sinne von Adaptern verwendet.Soll beispielsweise eine beliebige Struktur von Elementen in der
Lage sein, einem Aufrufer bestimmte Information über dieWerte der Struktur zu übermitteln, so kann eine innere Klassein der Rolle des Adapters dazu dienen, sich auf den Aufrufereinzustellen.
Eine solche Klasse ist außerhalb der Struktur (für dieInformationen über die Werte geliefert werden) bedeutungslosund deshalb eine innere Klasse zu der eigentlichen die Strukturrealisierenden Klasse.
310
Innere Klassen
Beispiel Stapel:Die Elemente eines Stapels sollen für externe Anfrageraufgezählt werden. Diese Anforderung soll nicht mit dereigentlichen Stapelfunktionalität vermischt werden.
Als zusätzliche Methoden werden identifiziert:public boolean hasMoreElements();
public Object nextElement();
Eine Bereitstellung in Form einer inneren Klasse ist nötig, wenndie Aufzählung mehrfach simultan aufgerufen werden soll oderwenn in verschiedenen Aufzählungen unterschiedlich reagiertwerden soll.
311
Innere Klassen
Diese innere Klasse muß Zugriff auf die Stapelelemente habenund das unabhängig von den Stapelzugriffsmethoden.
public class Stack {
private Vector items;
//code for Stack-Methoden ausgelassen
class StackEnum { ...
public boolean hasMoreElements()
{ ... }
public Object nextElement() { ... }
}
} Hinweis: Die StackEnum Klasse benutzt direkt dieInstanzvariablen von Stack-Objekten.
312
Lokale Klassen
• Sie befinden sich innerhalb eines Code-Blocks und verhaltensich wie verschachtelte Klassen.
• Sie sind nur sichtbar innerhalb des Blocks, in dem sie definiertsind.
• Sie werden benutzt, wenn die Klasse nur innerhalb einesCode-Blocks gebraucht wird.
• Für einmalige Anwendung, die keine Konstruktoren erfordert,sind anonyme Klassen geeigneter.
313
Anonyme Klassen
Anonyme Klassen
Im vorherigen Beispiel hat der Klassenname StackEnum nichtszum Verständnis des Programms beigetragen. Es gibt dieMöglichkeit, innere Klassen ohne Namen zu definieren. Wirsprechen dann von anonymen Klassen.
Hinweis: Anonyme Klassen sollten nur verwendet werden, wennes um Klassen geht, die ganz sicher nur einen Zweck habenund die maximal zwei Methoden haben. Alles andere gefährdetdie Lesbarkeit des Codes.
314
Anonyme Klassen
• Anonyme Klassen sind lokale Klassen ohne Namen• Das bedeutet: man kann sie in einem Schritt definieren und
benutzen• Syntax: new NameOberklasse() {
// zusätzliche Attribute und Methoden}
• Sie haben keinen Konstruktor• Sie sind praktisch, wenn eine Klasse nur ein einziges Mal
gebraucht wird
Kapitel 11
Elementare Java-Klassen11.1 String11.2 Felder11.3 Object
Kapitel 11.1
String
317
Klasse String
• Zeichenketten werden durch Objekte der Klasse Stringdargestellt. Wir hatten schon gesehen, daß String keinprimitiver Typ, sondern eine vordefinierte Klasse ist!
• String ist eine besondere Klasse, da Literale (konstanteZeichenketten) und Operatoren (+ zur Konkatenation) definiertsind.
• In enger Verbindung mit der Klasse String steht die KlasseStringBuffer.
318
Klasse String
Warum zwei String Klassen?„The Java development environment provides two classes thatstore and manipulate character data:String, for constant strings, and StringBuffer, for strings thatcan change.
You use Strings when you don't want the value of the string tochange. For example, if you write a method that requires stringdata and the method is not going to modify the string in anyway, use a String object. Typically, you'll want to use Strings topass character data into methods and return characterdata from methods.
319
Klasse String
Because they are constants, Strings are typically cheaper thanStringBuffers and they can be shared.
So it's important to use Strings when they're appropriate.“
(aus dem Java Tutorial)
320
Methoden der Klasse String (Ausschnitt)
Konstruktoren:• public String(char chars[])
– Konvertiert Array von Zeichen in einen String
• public String(byte bytes[])
– Konvertiert Array von Bytes in einen String– Plattformspezifische Zeicheninterpretation wird benutzt
• public String(StringBuffer buffer)
– Konvertiert StringBuffer nach String
Beispiel:char[ ] c = {'S', 'c', 'h', 'u', 'l', 'z', 'e'};
Strin g s = new String(c);
System.out.println(s);
321
String-Objekte Elementare Java-Klassen
• Objekte für den Umgang mit Zeichenketten
→ Aufruf von Methoden für Erzeugen, Aneinanderhängen, Längenmessung,Vergleich, ...
• Erzeugen
String vorname= new String ("Max")
String nachname= "Mustermann" (Kurz-Form mit Literal)
• Messen der Länge
int laenge= name.length() →→→→ 14
• Aneinanderhängen (Konkatenation)
String name = vorname + nachname (neues String-Objekt)
322
String-Konkatenation
• Der +-Operator kann verwendet werden, um zwei Objekte derKlasse String zu verknüpfen
• Ist nur einer der Operanden ein Objekt der Klasse String, undein anderer ein primitiver Datentyp, wird letzterer nach Stringgewandelt
Beispiel:int alter = 27;
System.out.println("Alter : " + alte r + " Jahre");
Ausgabe:Alter: 27 Jahre
323
String-Objekte Elementare Java-Klassen
Vergleichen (mit anderem Objekt):
public boolean equals(Object anObject)– Vergleicht String mit einem anderen Object auf Gleichheit– Typ Object heißt, daß Objekte aller Klassen als Argument übergeben
werden dürfen (später mehr)– Operator "==" vergleicht nur, ob die Referenz identisch ist, also ob es
sich um dasselbe Objekt handelt, und nicht, ob es inhaltlich identisch ist•
String vorname2= "Max"
boolean istGleich = vorname.equals(vorname2) →→→→ true
– Achtung: == vergleicht Referenzen beider Seiten miteinander!boolean istGleicheReferenz = (vorname == vorname2) →→→→
false324
Methoden der Klasse String (Ausschnitt)
Beispiel :String s1 = "Test", s2=s1;
String s3="Te", s4="st", s5;
s5 = s3 + s4;
System.out.println((s1 == s2 ) + " / " + s1.equals(s2));
System.out.println((s1 == s3 ) + " / " + s1.equals(s3));
System.out.println((s1 == s5 ) + " / " + s1.equals(s5));
Ausgabe:true / true
false / false
false / true
325
Methoden der Klasse String (Ausschnitt)
• public int length()– Gibt Länge des Strings zurück
• public byte[] getBytes()
– Konvertiert String in Array von Bytes– Plattformspezifische Zeicheninterpretation wird benutzt
• public int compareTo(String anotherString)– vergleicht zwei Zeichenketten lexikographisch basierend auf Unicode-
Nummern (Telefonbuchordnung)– Ergebnis ist gleich 0, falls Strings identisch sind,– kleiner 0, falls der String lexikographisch kleiner ist, als das Argument,– größer 0, falls der String lexikographisch größer ist, als das Argument
326
Methoden der Klasse String (Ausschnitt)
• public String toLowerCase()
• public String toUpperCase()
– Wandelt String in Kleinbuchstaben bzw. Großbuchstaben– Funktioniert auch mit deutschen Umlauten– "ß" wird bei toUpperCase nach "SS" gewandelt, Rückwandlung
funktioniert hier natürlich nicht
Beispiel: Ausgabe:Strin g a = "Schoßhündchen"
System.out.println(a.toLowerCase()); schoßhündchen
System.out.println(a.toUpperCase()); SCHOSSHÜNDCHEN
System.out.println(a.toUpperCase() schosshündchen
.toLowerCase());
327
String und StringBuffer
• String ist nur geeignet, um nicht änderbare Zeichenketten zuverarbeiten, denn z.B. bei Stringkonkatenation durch "+" wirdein neues Objekt erzeugt und die kompletten alten Inhaltekopiert.
• Müssen in eine Zeichenkette laufend kleine Teilzeichenkettenangefügt werden, so ist StringBuffer besser geeignet
328
Methoden der Klasse StringBuffer (Ausschnitt)
• StringBuffer hat ein initiales Fassungsvermögen
• Wird mehr benötigt, wird es automatisch erweitert• Bei anfänglicher realistischer Voreinschätzung der benötigten
Länge läßt sich die Effizienz steigern
Konstruktoren:• public StringBuffer()
– Erzeugt Leerstring mit initialem Fassungsvermögen von 16 Zeichen
• public StringBuffer(int length)
– Erzeugt Leerstring mit spezifiziertem initialen Fassungsvermögen
• public StringBuffer(String str)– Initialisiert StringBuffer mit vorgegebenem String .
329
Methoden der Klasse StringBuffer (Ausschnitt)
• public StringBuffer append(String str)
– Hängt eine Zeichenkette an den String an– Fassungsvermögen wird dynamisch an die benötigten Gegebenheiten
angepaßt
• public int length()– Gibt die Länge der aktuellen Zeichenkette zurück (nicht des aktuellen
Fassungsvermögens)
• public String toString()– Wandlung in eine Zeichenkette vom Typ String
330
Methoden der Klasse StringBuffer (Ausschnitt)
Einfügen von Zeichen in StringBuffer-Objekte:StringBuffer sb = new StringBuffer("Drink Java!");
sb.insert(6, "Hot ");
System.out.println(sb.toString());
Ergebnis: Drink Hot Java!
Ersetzen von Zeichen an bestimmten Positionen:setCharAt ersetzt ein Zeichen an einer bestimmten Positioninnerhalb des StringBuffer-Objektes.
331
Methoden der Klasse StringBuffer (Ausschnitt)
Anhängen am Ende eines StringBuffer-Objekts:
StringBuffer sb = new StringBuffer("Drink Hot");
sb.append("!");
System.out.println(sb.toString());
Ergebnis: Drink Hot!
332
Methoden der Klasse StringBuffer (Ausschnitt)
Reversieren eines StringBuffer-Objektes:class ReverseString {
public static String reverseIt(Stringsource) {
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();
}
}
333
Methoden der Klasse StringBuffer (Ausschnitt)
Erläuterung zum Reversieren:Die Anweisung StringBuffer dest legt fest, daß ein
StringBuffer-Objekt verwendet werden soll.
Hierfür wird Speicherplatz allokiert.
StringBuffer(len) initialisiert das Objekt.
Durch das Anhängen eines Zeichens an ein StrinBuffer-Objektkann prinzipiell neue Speicherallokation nötig sein. Dies istteuer. Deshalb wird im Reversieren ein passend langesStringBuffer-Objekt auf einmal allokiert.
334
Übung: String, Referenzen
Motivation• Benutzen von Zeichenketten• Übergabe von Referenzen statt kompletter Parameter-Objekte
Aufgabe• Jedes Girokonto soll einen eigenen Konten-Inhaber bekommen. Entwerfen
und implementieren Sie eine neue Klasse "Person“:– Attribute: Vorname, Nachname, Strasse, Postleitzahl (plz) und Ort vom Typ String– Methoden:
void setzeName : Setzen von Vorname und Nachnamevoid setzeAdresse : Setzen von Strasse, PLZ, OrtString holeInhaber : Rückgabe aller aneinanderfügten Attribute
• ...
Elementare Java-Klassen
335
Übung: String, Referenzen
Aufgabe (Forts.)
• Testen Sie nun die Klasse "Person" (vgl. Klasse "TestGirokonto").– Was kann/sollte man testen?
– Testen Sie auch folgendes: Erzeugen Sie zwei Konten und eine Person, setzendiese für beide Konten als Inhaber. Ändern Sie ein Attribut dieser Person undgeben Sie danach für beide Konten den Inhaber aus. Was fällt Ihnen auf?
Elementare Java-Klassen
336
Übung: String, Referenzen
Lösung 1:
public class Person {
private String vorname, nachname, strasse, plz, ort;
public Person(String vorname, String nachname, String strasse,String plz, String ort) {
setzeName(vorname, nachname);
setzeAdresse(strasse, plz, ort);
}
public void setzeName (String vorname, String nachname){
this.vorname=vorname;
this.nachname=nachname;
}
→
Elementare Java-Klassen
337
Übung: String, Referenzen
...
public void setzeAdresse(String strasse, String plz, Stringort){
this.strasse=strasse;
this.plz=plz;
this.ort=ort;
}
public String holeInhaber(){
return (this.vorname+" "+this.nachname+", "+this.strasse+", "+this.plz+" "+this.ort);
}
}
Elementare Java-Klassen
338
Übung: String, ReferenzenLösung:
public class Test2 {
public static void main(String[] args) {
Waehrungsrechner wr = new Waehrungsrechner();
Person herrMeyer = new Person ("Martin", "Meyer",
"Saarstrasse 11", "D-44227", "Dortmund");
Girokonto konto1 = new Girokonto (herrMeyer, wr, 100);
Girokonto konto2 = new Girokonto (herrMeyer, wr, 200);
Bildschirm.gibAus(konto1.holeInhaber() );
Bildschirm.gibAus(konto2.holeInhaber() );herrMeyer.setzeAdresse("Moselgasse 5", "D-44223",
“Dortmund");
Bildschirm.gibAus(konto1.holeInhaber() );
Bildschirm. gibAus ( konto2.holeInhaber () );
Elementare Java-Klassen
Kapitel 11.2
Felder
340
Felder
arrayA collection of data items, all of the same type, inwhich each item's position is uniquely designated by aninteger.
Elementare Java-Klassen
341
Felder
• Objekte für den Umgang mit Folgen von Objekten
Girokonto[] Konten;...Konten = new Girokonto[100];...
• belegen der Feldplätze– Index beginnt bei 0
konten[0]=... ;konten[1]=... ;
• zugreifen auf ein einzelnes Feld-Objekt (mittels Index)
konten[2] ergibt das Girokonto-Objekt auf dem 3. Platz des Felds
Elementare Java-Klassen
Typ feldname[]oder: Typ[] feldname
Beim Erzeugen wird dieFeldgröße mitgegeben
342
Eindimensionale Felder
• Deklaration:Typ [] Feldname ;
(alternativ: Typ Feldname []; )
• Initialisierung:Feldname = new Typ [ Feldgröße ];
• Initialisierung mit Werten:Feldname = new Typ []{Konst1, Konst2, ...,Konstn};
• Deklaration und Initialisierung:Typ [] Feldname = new Typ [ Feldgröße ];
Typ [] Feldname = { Konst1 , Konst2 ... };
343
Eindimensionale Felder
• Zugriff auf Feldelemente:Feldname [ Nummer];Nummer ist eine Zahl vom Typ int zwischen 0 und Feldgröße-1
• Zugriff auf Feldlänge:Feldname .length
• Typ kann ein primitiver Datentyp oder auch eine Klasse sein
• Es können mehrere Referenzen auf ein Array zeigen
344
Anwendung: Sortieren durch EinfügenProblem: Eine unsortierte Folge von Zahlen soll geordnet werden.Dazu sollen die Zahlen zunächst in einemFeld int[] zahlen abgelegt werden, das anschließend aufsteigendsortiert werden soll.
Idee: Sind für einen Indexwert i bereits dieElemente zahlen[0], …, zahlen[i-1] aufsteigend sortiert, so sucheman im bereits sortierten Bereich die Position k, ander zahlen[i] eingefügt werden kann, verschiebe zahlen[k], …,zahlen[i-1] um genau eine Position weiter auf die Elementezahlen[k+1], …, zahlen[i] und setze zahlen[k] = zahlen[i].
345
Anwendung: SortierenBei der Bestimmung von k sind die folgenden Fälle zuberücksichtigen:
• Alle Werte im sortierten Bereich sind kleiner als dereinzusortierende Wert, d.h. zahlen[i-1] ≤ zahlen[i]: dannist k = i.
• In allen anderen Fällen: k sei der kleinsteIndex t, t ∈ {1, …, i-1}, für den gilt:
zahlen[i] ≤ zahlen[t](Dann gilt also: zahlen[i] ≤ zahlen[k] und zahlen[i] > zahlen[k-1], denn k ist minimal; für zahlen[i] < zahlen[0] gilt: k = 0)
Code für die Bestimmung von k:k = 0;while ((k < i) & (zahlen[i] >= zahlen[k]))
k++; 346
Anwendung: Sortieren
Die Verschiebung erfolgt in folgender Weise:
merker = zahlen[i];zahlen[i] = zahlen[i-1];zahlen[i-1] = zahlen[i-2];
…zahlen[k+1] = zahlen[k];zahlen[k] = merker ;
Code für die Verschiebung:
for (int j = i; j > k; j--)zahlen[j] = zahlen[j-1];
347
Anwendung: Sortieren
Die Analyse dieses Algorithmus zeigt, daß für dasElement zahlen[i] der Test zur Bestimmung der Position desEinfügens, (k<i) & (zahlen[i]>=zahlen[k]), im ungünstigsten Falli–1-mal durchgeführt wird. Dieser Fall liegt dann vor, wenn daseinzufügende Element an das Ende des sortierten Bereichsplaziert wird. Für die gesamte Zahlenfolge ist der ungünstigsteFall daher dann gegeben, wenn eine bereits sortierte Folgevorliegt. Für n Elemente werden dann insgesamt
1 + 2 + … + (n – 1) = n*(n–1)/2
Tests durchgeführt. Für eine lange Zahlenfolge vonbeispielsweise 10 000 Elementen könnte daher der Falleintreten, daß bis zu annähernd 50 Millionen Vergleicheausgewertet werden müssen.
348
int[] zahlen;int merker=0, k=0;
// Einlesen der Elemente …
for (int i = 0; i < zahlen.length; i++) {k = 0;while ((k < i) & (zahlen[i] >= zahlen[k]))
k++;if (k != i) {
merker = zahlen[i];for (int j = i; j > k; j--)
zahlen[j] = zahlen[j-1];zahlen[k] = merker;
}}
// Ausgeben der Elemente …
349
public class Sort {public static void main(String[] args) {int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,
2000, 8, 622, 127 };for (int i = arrayOfInts.length; --i >= 0; ) {
for (int j = 0; j < i; j++) {if (arrayOfInts[j] > arrayOfInts[j+1]) {
int temp = arrayOfInts[j];arrayOfInts[j] = arrayOfInts[j+1];arrayOfInts[j+1] = temp;
} }}for (int i = 0; i < arrayOfInts.length; i++) {
System.out.print(arrayOfInts[i] + " ");}System.out.println();
}}350
Mehrdimensionale Felder• mehrdimensionale Felder möglich
int[][] dreieck;dreieck = {{1}, {2,3}, {4,5,6}};
dreieck[1][0] ergibt 2
• dreieck[1].length liefert die Ausdehnung der zweiten Dimension in derAbhängigkeit von der ersten Dimension, hier also 2, die Anzahl der Spalten derzweiten Zeile (denn die wird durch den Index [1] referenziert.
• Initialisierung eines Feldes möglich (schon bei Deklaration)– muß alle Elemente belegen
int[][] dreieck = {{1}, {2,3}, {4,5,6}}
Elementare Java-Klassen
Typ Feldname = { Konst1, Konst2 ...}
351
Mehrdimensionale Felder
• Deklaration:Typ [][] Feldname ; // zweidimensional
Typ [][][] Feldname ; // dreidimensional
(alternativ: Typ Feldname [][]; )
• Initialisierung:Feldname = new Typ [ Feldgröße1 ][ Feldgröße2 ];
– oder (für nicht notwendigerweise rechteckige Arrays):
Bezeichner = new Typ [ Feldgröße1 ][];
for (int i=0; i< Feldgröße1 ; i++)
Bezeichner [i] = new Typ [ Feldgröße_i ];
352
Mehrdimensionale Felder
• Deklaration mit Initialisierung:Grundtyp [][] Feldname = new Typ [ Feldgr1 ][ Feldgr2 ];
Grundtyp [][] Bezeichner ={{ Konst1 , Konst2 ... },{ ... }, ... };
• Zugriff auf Feldelemente:Bezeichner [ Nummer1][ Nummer2]
• Feldname ist Referenz auf das n-dimensionale Array• Feldname[Nummer] ist Referenz auf ein
(n-1)-dimensionales Teil-Feld• Feldname.length ist die äußere Feldlänge• Feldname[Nummer].length ist die Feldlänge eine Ebene tiefer
353
Mehrdimensionale Felder
Beispiel:int abteilungsAnzahl = 4;
int[] abteilungsGröße = {6, 17, 13, 14};
String[][] mitarbeiter = new String[abteilungsAnzahl][];
for (int i=0; i<abteilungsAnzahl; i++)
mitarbeiter[i] = new String[abteilungsGröße[i]];
mitarbeiter[0][0] = "Max Born"; // Abteilung 1
mitarbeiter[0][1] = "Werner Heisenberg";
... (6 Leute)mitarbeiter[1][0] = "Albert Einstein"; // Abteilung 2
mitarbeiter[1][1] = "Nils Bohr";
...
354
Mehrdimensionale Felder
Beispiel: Ausgabe zweidimensionaler Felder
float[][] matrix = new float[4][4];
setupMatrix(mat); // Eingabe der Werte
for (int y=0 ; y < mat.length; y++){
for (int x=0 ; x < mat[y].length; x++)
System.out.print(mat[y][x ] + “ “);
System.out.println();
}
355
Übung: Kartenverwaltung
Motivation• Vertiefen von FOR, IF-ELSE, Array und String
• Aus Anforderungstext zu Programmcode kommen• Motivation für Ausnahmebehandlung erkennenAufgabe
• Entwerfen und implementieren Sie eine Klasse „Kartenverwaltung“, die folgendeTabelle verwaltet:
→
Elementare Java-Klassen
i kartennr(Array mit 100 String-Obj.)
pins(Array mit 100 String-Obj.)
konten(Array mit 100 Girokonto-Obj.)
0 ´´000´´ ´´A´´ (Zeiger auf ein Konto)
1 ´´111´´ ´´B´´ ´´´´
2 ´´222´´ ´´C´´ ´´´´
...
34 ´´343434´´ ´´Y´´ ´´´´
...
99 ´´9999999´´ ´´YYYY´´ ´´´´
356
Übung: Kartenverwaltung
Vorgehen• Überlegen Sie sich, wie Sie die Tabelle in Java realisieren möchten
(z.B. mehrere Arrays, parallel durchlaufen)• Welche Attribute und Methoden soll die neue Klasse „Kartenverwaltung“
haben?• Wie kann man in der Tabelle eine Zeile lokalisieren zu einem
vorgegebenen Eintrag (z.B. Kartennummer)?• Schreiben Sie den Quellcode der Klasse „Kartenverwaltung“ auf und
beheben Sie ggf. auftauchende Fehler!• Überlegen Sie, auf welche Weise Sie diese neue Klasse testen können und
schreiben Sie den Quellcode für diese Testklasse!
Elementare Java-Klassen
357
Übung: Kartenverwaltung
Methoden:• ´´erfasseWeiteresKonto´´ : Eintragen von Konto, Kartennummer und
Pin in eine Tabellenzeile
• ´´holeKonto´´ : Rückgabe des Kontos zu einer übergebenenKartennummer
• ´´pinIstGültig´´ : Rückgabe true falls Kartennummer undPIN zusammengehören
false sonst
Elementare Java-Klassen
358
Übung: Kartenverwaltung (1/4)
public class Kartenverwaltung {
private String[] pins =new String[100];
private String[] kartennr =new String[100];
private Girokonto[] konten=new Girokonto[100];
private int freiIndex; //Feldindex des//frühesten
//unbesetzten Eintrags
public Kartenverwaltung(){
freiIndex=0;
}
// weiter auf nächster Folie
Elementare Java-Klassen
359
Übung: Kartenverwaltung (2/4)
public void erfasseWeiteresKonto (String kartennummer,String pin, Girokonto konto){
kartennr[freiIndex]=kartennummer;
pins[freiIndex]=pin;
konten[freiIndex]=konto;
freiIndex++;
}
Elementare Java-Klassen
360
Übung: Kartenverwaltung (3/4)...
public Girokonto holeKonto (String kartennummer){
Girokonto dasKonto=null;
for (int i=0; i<freiIndex; i++){
if (kartennummer.equals(kartennr[i])){
dasKonto=konten[i];
}
}
return (dasKonto);
}
Elementare Java-Klassen
361
Übung: Kartenverwaltung (4/4)
public boolean pinIstGültig (String kartennummer, Stringpin){
int i;
for (i=0; (! kartennummer.equals(kartennr[i])); i++){}
return (pin.equals(pins[i]));
}
}
Elementare Java-Klassen
362
Übung: Test_Kartenverwaltung
public class Test_Kartenverwaltung {
public static void main(String[] args) {
// 1. Erzeuge Waehrunsgrechner, Person und drei Konten
// mit initialen Konständen von 100,200, 300 Pfennigen
Waehrungsrechner wr=new Waehrungsrechner();
Girokonto konto1=new Girokonto(wr, 100);
Girokonto konto2=new Girokonto(wr, 200);
Girokonto konto3=new Girokonto(wr, 300);
// 2. Erzeuge eine Kartenverwaltung und füge dort// die 3 Konten mit PIN ein
Kartenverwaltung kv=new Kartenverwaltung();
kv.erfasseWeiteresKonto("111", "A", konto1);
kv.erfasseWeiteresKonto("222", "B", konto2);
kv.erfasseWeiteresKonto("333", "C", konto3);
→
Elementare Java-Klassen
363
Übung: Test_Kartenverwaltung
// 3. hole von Kartenverwaltung (OHNE PIN-Prüfung!) die Konten// und gib ihre Kontostande aus
Bildschirm.gibAus("Der Kontostand fuer Kartennummer 1 ist "+kv.holeKonto("111").holeKontostand());
Bildschirm.gibAus("Der Kontostand fuer Kartennummer 2 ist"+kv.holeKonto("222").holeKontostand());
Bildschirm.gibAus("Der Kontostand fuer Kartennummer 3 ist"+kv.holeKonto("333").holeKontostand());
→
Elementare Java-Klassen
364
Übung: Test_Kartenverwaltung// 4. hole MIT PIN-Prüfung das Konto2, gib Kontostand aus
boolean istAkzeptiert=false;
do {
String eingabePIN=Bildschirm.gibEin("Bitte PIN für fuer Konto 2");
if (kv.pinIstGültig("222", eingabePIN)) {
istAkzeptiert=true;
Bildschirm.gibAus("Die eingegebene PIN ist gueltig.");
Girokonto dasKonto2=kv.holeKonto("222");
Bildschirm.gibAus("Kontostand: "+dasKonto2.holeKontostand());
} else{
Bildschirm.gibAus("Die eingegebene PIN ist nicht gueltig.");
}
} while (!istAkzeptiert);
Bildschirm.warteAufTastendruck();
}
}
Elementare Java-Klassen
Kapitel 11.3
Object
366
Die Klasse Object
• Die Klasse Object ist die Oberklasse aller Klassen, und stellteinige Methoden zur Verfügung:
• public String toString()
– Die toString() -Methode gibt eine (etwas kryptische) Wandlung einesObjektes in einen Stringsie sollte von Klassen überdeckt werden
– Die System.out.println -Methode akzeptiert beliebige Objekte alsargument, sie benutzt die (eventuell selbst überschriebene)toString() -Methode
– Strings können mit beliebigen Objekten durch den +-Operator verknüpftwerden. Dazu wird implizit von den Objekten die toString() -Methodeaufgerufen, um die String-Darstellung zu erhalten
367
Die Klasse Object
• public boolean equals(Object obj)
– Das Objekt wird mit dem Argument auf Gleichheit überprüft– In der Standardimplementierung wird nur die Referenz verglichen (also,
ob es sich im dasselbe Objekt handelt)– Eine neue Methode sollte die equals -Methode überdecken, um einen
Inhaltlichen Vergleich zu ermöglichenBeispiel:Für einen Kunden soll abgefragt werden, ob er bereits Kunde ist. Fürden Vergleich spielt der Name, der Geburtsort und das Geburtsdatumeine Rolle, nicht jedoch die Adresse
368
Die Klasse Object
• public Object clone()
– returniert eine wertegleiche Kopie des Objektes.– Hinweis: Wenn in dem zu klonenden Objekt Referenzen auf andere
Objekte (z.B. Arrays) vorkommen, so werden die Referenzen geklont,nicht aber die referenzierten Objekte. Auf diese Weise kommt es zu“shared data”. Ob das beabsichtigt ist, muss sorgfältig geprüft werden.
– Diskussion des Stack-Beispiels
• public final Class getclass()
– returniert das Objekt, das die Klasse des Objektes repräsentiert, dessenMethode aufgerufen wird.
Kapitel 12
Ähnliche Objekte (Vererbung)
370
Vererbung
• Klassen können zueinander in einer "ist ein"-Beziehung stehen
• Beispiel: Jeder PKW ist ein Kraftfahrzeug,jedes Kraftfahrzeug ist ein Transportmittel
aber: auch jeder LKW ist ein Kraftfahrzeug und jeder Zug,jedes Schiff und jedes Flugzeug ist ein Transport-mittel
Transportmittel
Kraftfahrzeug Zug Boot Flugzeug
PKW LKW Segelbooot MotorbootVW Golf Opel Astra
371
Vererbung (anschaulich)
• Sowohl PKWs, als auch LKWs besitzen Fahrersitze undFahrertüren, es handelt sich also um Attribute der OberklasseKraftfahrzeug
• Sowohl PKWs als auch LKWs haben die Methoden Sitzverstellen, Tür schließen und fahren, es sind Methoden derOberklasse Kraftfahrzeug
• PKWs haben jedoch mit der Rückbank und dem Kofferraumeigene Attribute und mit "hinten einsteigen" eigene Methoden
• LKWs haben mit der Ladefläche und dem Anhänger aucheigene Attribute und "beladen" ist eine eigene Methode=> Unterklassen PKWs und LKWs besitzen alle Attribute und
Methoden der Oberklasse, haben jedoch noch zusätzliche
372
Ähnlichkeiten bei Objekten
Und bei Konten tritt so was ähnliches natürlich auch auf :-)• Zusammenfassen von gleichen Attributen und Methoden
Vererbung
Girokonto
kontostand : intinhaber : Personhabenzinsen : intsollzinsen : intdispo : int
holeKontostand()zahle()
Sparkonto
kontostand : intinhaber : Personhabenzinsen : int
holeKontostand()zahle()kuendigen()
Festgeld
kontostand : intinhaber : Personhabenzinsen : intmindBetrag : intlaufzeit : int
holeKontostand()zahle()kuendigen()
373
Erweiterung des Klassenmodells Vererbung
Konto
kontostand : intinhaber : Personhabenzinsen : int
holeKontostand()zahle()
Girokontosollzinsen : intdispo : int
Festgeldkonto
mindBetrag : intlaufzeit : int
kuendigen()
Sparkonto
kuendigen()
374
Verhältnis zwischen Objekten erbender Klassen
• Die vererbende Klasse heißt Superklasse.• Die erbenden Klassen sind Unter- oder Subklassen.• Konto ist also die Superklasse der Klassen Girokonto,
Festgeldkonto, Sparkonto. Diese sind die Subklassen derKlasse Konto.
375
Verhältnis zwischen Objekten erbender Klassen
Konto
Girokonto
Sparkonto
Festgeldkonto
• Alle Objekte sind Konten!• Einige sind besondere
Arten von Konten.• Die Menge der
Sparkonten, Girokonen,Festgeldkonten istjeweils eine Teilmengeder Menge der Konten
• Die Teilmengen sinddisjunkt.
376
• Wir nehmen folgende Deklarationen an:
Girokonto einGirokonto;
Sparkonto einSparkonto;
Konto einKonto, einAnderesKonto;
• Legale Zuweisungen:
einGirokonto = new Girokonto();
einSparkonto = new Sparkonto();
einGirokonto.sollzinsen = 12;
einKonto = einGirokonto;
einAnderesKonto = new Sparkonto();
Verhältnis zwischen Objekten erbender Klassen
Konto
GirokontoSparkonto
Festgeldkonto
377
• Wir nehmen folgende Deklarationen an:
Girokonto einGirokonto;
Sparkonto einSparkonto;
Konto einKonto, einAnderesKonto;
• Nicht legale Zuweisungen:
einSparkonto = einGirokonto;
einGirokonto = new Sparkonto();
Verhältnis zwischen Objekten erbender Klassen
Konto
GirokontoSparkonto
Festgeldkonto
378
Erläuterungen :
Jedes Sparkonto / Girokonto ist auch ein Konto, deshalb isteinKonto = einSparkonto legal.
Ein Objekt der einer Klasse kann also mehrereErscheinungsformen haben, es kann ein Objekt der Klasseselbst sein oder es kann ein Objekt einer der Unterklassendieser Klasse sein. Es ist also polymorph .
Verhältnis zwischen Objekten erbender Klassen
379
Erläuterungen :
Nicht jedes Konto ist ein Sparkonto.Ist dann einSparkonto = einKonto legal?
Ja, denn Objekte der Klasse Sparkonto sind wandelbar zuObjekten der Klasse Konto. Allerdings ist der Zugriff auf alleAttribute nicht möglich, denn einKonto hat ja nicht dieSparkonto-Attribute.
Verhältnis zwischen Objekten erbender Klassen
380
Erläuterungen :Was passiert bei folgender Anweisung?
if (x%2 == 0)
einKonto = einSparkonto;
else
einKonto = einGirokonto;
Der Compiler ist nicht in der Lage, die Klasse von einKonto zuermitteln. Die Klasse von einKonto nach dieser Zuweisung istnicht vorhersehbar. einKonto kann also nach der Anweisungeine von mehreren Klassen haben, es ist halt polymorph.
Verhältnis zwischen Objekten erbender Klassen
381
Erläuterungen :
IsteinKonto = (x%2==0 ? einGirokonto : einSparkonto)
erlaubt?
Verhältnis zwischen Objekten erbender Klassen
382
Die Klasse Konto
public class Konto {
private int kontostand = 0;
private Waehrungsrechner wr;
private Person inhaber;
private int habenzinsen;
public Konto (Person inhaber, Waehrungsrechner wr) {
this.inhaber = inhaber;
this.wr = wr;
}
Vererbung
383
Die Klasse Konto
public void zahle (int pfennige) {
int euroCent = wr.wandeleInEuroCent(pfennige);
kontostand += euroCent;
}
public int holeKontostand() {
int pfennige = wr.wandeleInPfennige(kontostand);
return (pfennige);
}
} // Ende der Klasse Konto
Vererbung
384
Die Klasse Girokonto
public class Girokonto extends Konto {
private int sollzinsen;
private int dispo;
} // Ende der Klasse Girokonto
Vererbung
Schlüsselwort: extends
385
Vererbung (technisch)
• Vererbung wird über Schüsselwort extends realisiert:
class Unterklasse extends Oberklasse {
... // Hier zusätzliche Attribute und Methoden}
• Die neu definierte Unterklasse erweitert also die anderswodefinierte Oberklasse um neue Attribute und Methoden.
• Alle Methoden und Attribute der Oberklasse werdenübernommen.
386
Vererbung (technisch)
• Jede Klasse hat genau eine Oberklasse (Java kennt keineMehrfachvererbung)
• Ist keine Oberklasse definiert (kein extends ), so ist dieSystemklasse Object die Oberklasse=> Object ist eine Oberklasse für alle Klassen
(bis auf Object selbst)
387
Vererbung (technisch)
• Konstruktoren werden nicht vererbt, Konstruktoren derabgeleiteten Klasse müssen neu definiert werden!
• Über Schlüsselwort super kann am Anfang eines Konstruktorsder abgeleiteten Klasse ein Konstruktor der Oberklasseaufgerufen werden.Beispiel: class A {
A(String name) { ...}
}class B extends A {
B(String name, int a) {super(name); // Aufruf des Oberkl.-... // Konstruktors
}}
388
Vererbung (technisch)
• Wenn in der ersten Anweisung des Subklassen-Konstruktorsnicht einer der Konstruktoren der Superklasse aufgerufen wird,dann wird der parameterlose Superklassen-Konstruktor(Standard-Konstruktor) automatisch aufgerufen, bevorirgendeine andere Anweisung des Subklassen-Konstruktorsaufgerufen wird.
• Die Verwendung von super ist die einzige Situation, in der dieQuelle einer Referenz für die Wahl der auszuführendenMethode / den Zugriff auf ein Attribut verantwortlich ist.
389
Zugriffsrecht: protected
• private Methoden und Attribute sind nur in der Klassezugreifbar, in der sie definiert sind. Sie sind nicht in denerbenden Klassen zugreifbar.
• Oft ist es so, daß Methoden und Attribute nicht von außenzugreifbar sein sollen, daß sie aber schon vererbt werdensollen. Genau dies wird durch das Schlüsselwort protectedvereinbart.
Vererbung
390
Zugriffsrecht: protected
• protected Methoden und Attribute sind in der Klasse selbstund in allen Subklassen sichtbar.
Vererbung
Konto
private kontostandprotected habenzinsen
Girokonto
Bankautomat
„habenzinsen“ ist hier unbekannt
„habenzinsen“ ist hier bekannt
erweitert
benutzt
391
Zugriffsrecht: protected
• protected Methoden und Attribute einer Oberklasse Akönnen auch in einer Unterklasse B zur Oberklasse Azugreifbar, d.h. genau:
– sie können benutzt werden über eine Referenz auf ein Objekt derKlasse A oder auf ein Objekt einer Unterklasse der Klasse A.
Vererbung
392
Überschreiben von Methoden in Vererbungshierarchien
• Methode: berechneZinsen (int tage)
• gleiche Implementierung in Sparkonto und Festgeld
• aber: in Girokonto Berechnung aus Sollzinsen und Habenzinsen
• Lösung: Standard-Implementierung in Konto undÜberschreiben in Girokonto
393
Überschreiben von Methoden
public class Konto {
...
/**
berechnet für die Anzahl Tage die angefallenen Zinsen
*/
protected int berechneZinsen(int tage) {
Float zinsen =
new Float(kontostand*(habenzinsen/100)*(tage/360));
return (zinsen.intValue());
}
...
}
Vererbung
Wrapper-Klasse: Float
394
Überschreiben von Methoden
public class Girokonto extends Konto {
...
protected int berechneZinsen(int tage) {
int guthaben = holeKontostand();
if (guthaben > 0) {
Float zinsen =new Float(guthaben*(habenzinsen/100)*(tage/360));
return (zinsen.intValue());
} else {
Float zinsen =
new Float(guthaben*(sollzinsen/100)*(tage/360));
return (zinsen.intValue());
}
}
}
Vererbung
395
Zugriff auf überschriebene Attribute / Methoden• In einem Objekt einer abgeleiteten Klasse ist super eine
Referenz auf das Teilobjekt der Oberklasse• Attribute und Methoden der Oberklasse lassen sich so
ansprechen (auch überschriebene Attribute und Methoden)Beispiel:class A { class B extends A {
int variable; int variable; // Überschreibendes Attr.void methode() { void methode() { // Überschreibende Meth.
... ...} }
} void methode2() { // Zugriff aufsuper.variable = 3; // überschriebenesuper.methode(); // Attribute und
} // Methoden der} // Oberklasse
396
Schlüsselwort: final
• Verhindert, daß eine Methode überschrieben wirdpublic final int holeKontostand() {
...
}
• Erben von einer Klasse verbietenpublic final class Girokonto extends Konto {
...
}
Alle Methoden und Attribute einer finalen Klasse sind implizitauch final.
Vererbung
397
Schlüsselwort: final
• Finale Klassen und Methoden sind aus Sicherheitsgründenzuweilen erforderlich. Sie tun das, was sie tun sollen undkönnen nicht manipuliert werden. Typische Anweisung: eineMethode zur Passwort-Prüfung.
• final - Attribute sind Konstanten, sie dürfen nicht verändertwerden
public final int mwst;
Vererbung
398
Einschub: Klasse Datum (wird gleich benötigt)
public class Datum {
public Datum(int tag, int monat, int jahr) { ...}
public void setzeDatum(int tag, int monat, int jahr) { ... }
public static Datum aktuellesDatum() { ... }
public boolean istSpaeterAls(Datum dat) { ...}
public boolean istAbgelaufen() { ...}
public boolean istGleich (Datum dat) { ...}
public int gibDifferenz(Datum dat) { ...}
}
399
Abstrakte Methoden/Klassen
• Situation: Jede Subklasse hat die gleiche Methode aberunterschiedliche Implementierung
• Beispiel: auszahlen(int betrag)– Girokonto: beliebige Auszahlung bis Limit– Sparkonto: Restguthaben von DM 5,- nötig (außer nach Kündigung)– Festgeld: Auszahlung erst nach Ende der Laufzeit
• Lösung: abstrakte Methode in der Superklasse. Eineabstrakte Methode ist eine Methode, die nicht realisiert ist.
• Die abstrakte Methode der Superklasse gibt dann nur dieSignatur der Methode an, nicht aber ihre Realisierung.
Vererbung
400
Abstrakte Methoden/Klassen
public abstract class Konto {
protected Datum letzteTransaktion;
...
public void einzahlen(int betrag) {
Datum heute = Datum.aktuellesDatum();
int zinstage = heute.gibDifferenz(letzteTransaktion);int zinsen = berechneZinsen(zinstage);
zahle(betrag+zinsen);
}
public abstract int auszahlen(int betrag);
}
Vererbung
Schlüsselwort: abstractvor Methode und Klasse
401
Beispiel: Klasse Girokonto
class Girokonto extends Konto {
...
public int auszahlen(int betrag) {
Datum heute = Datum.aktuellesDatum();
int zinstage = heute.gibDifferenz(letzteTransaktion);
int zinsen = berechneZinsen(zinstage);
zahle(zinsen);
if (kontostand-betrag > dispo) {
zahle(-betrag);
return (betrag);
} else Bildschirm.gibAus(“Kein Auszahlen möglich“);
return (0);
}
}
Vererbung
402
Abstrakte Methoden/Klassen
• Enthält eine Klasse eine abstrakte Methode, so ist die ganzeKlasse abstract
• Eine abstrakte Klasse kann nicht instanziiert werden. D.h., eskönnen keine Objekte zu dieser Klasse erzeugt werden. Eskann nur Objekte zu den nicht abstrakten Unterklassen geben.
• Abstrakte Methoden müssen in den Subklassen implementiertwerden (oder die Subklassen sind wieder abstract)
Vererbung
403
Polymorphie
• Wunsch:Alle Objekte aus der Oberklasse “Konto” sollen in der gleichenWeise behandelt werden können.
• Lösung: PolymorphieEine Oberklassen-Referenz kann auch auf Objekte derSubklassen verweisen.
• Methoden der Oberklasse können so aufgerufen werden.Wurde eine Methode von einer Subklasse überschrieben , sowird nicht die Methodenimplementierung der Oberklasseaufgerufen, sondern die Implementierung der Subklasse.
404
Polymorphie
• Methoden können so mit allen möglichen Konten arbeiten
public int berechneVermoegen(Konto[] konten) {
int vermoegen = 0;
for (int i=0; i<konten.length; i++) {
Kont o k = konten[i];
vermoegen += k.holeKontostand();
}
return (vermoegen);
}
• Methodenaufruf wird an die entsprechende Subklasseweitergeleitet
Vererbung
405
Polymorphie (technisch)
• Polymorphie wird bei Vererbung durch Überschreiben derMethoden der Oberklasse erreicht, dabei muß die Signatur(also Parameterliste und Rückgabetyp) mit der Methode derOberklasse übereinstimmen.
• Beim Überschreiben werden die allgemeineren Methoden (derOberklasse) durch die konkreteren der Unterklasseüberschrieben.
406
Polymorphie (technisch)
• Auch wenn ein Objekt durch eine Variable eines allgemeinerenTyps referenziert wird, so werden immer die zum Objektgehörenden Methoden aufgerufen.
• Überschreiben darf nicht mit Überladen verwechselt werden,bei überladenen Methoden hat man unterschiedlicheSignaturen und nur der Methodenname ist der gleiche.
407
Instanceof
• Da jedes Objekt auch über Referenzen der Oberklasseangesprochen werden kann, ist nicht immer klar, zu welcherKlasse ein Objekt gehört. Daher gibt es das Schlüsselwortinstanceof , um die Klassenzugehörigkeit zu bestimmen:
if( Objektname instanceof Klassenname)Anweisung
• Die Abfrage liefert auch dann true , wenn durch Klassennameeine Oberklasse für das zu Objektname zugehörige Objektangegeben wird
408
Übung: Vererbung
Motivation• Vererben von Attributen und Methoden• Überschreiben von Methoden
Aufgabe• Nutzen Sie die Gemeinsamkeiten von Girokonto, Sparkonto und Festgeldkonto in der
gemeinsamen Oberklasse Konto. Implementieren Sie die Klasse Festgeldkonto alsErweiterung der Klasse Konto
– neue Attribute: laufzeit und mindBetrag– neue Methoden:
erweiterter Konstruktor : Übergeben der Laufzeitauszahlen(int betrag) : Auszahlung der Summe nach Ende der Laufzeitkuendigen() : identisch mit auszahlen
• Schreiben Sie eine Testklasse– benutzen Sie die Methode setzeDatum der Klasse Datum, um die letzteTransaktion
zurückzusetzen
Vererbung
409
Übung: Vererbung
public class Festgeld extends Konto {
private int laufzeit = 1080; // Laufzeit: 3 Jahre
public static int mindBetrag = 250000;
public Festgeld (Person inhaber, Waehrungsrechner wr,
int initialkontostand) {
super(inhaber, wr, initialkontostand);
if (initialkontostand < mindBetrag) {
Bildschirm.gibAus("Mindest-Betrag wird nichterreicht");
}
}
Vererbung
410
Übung: Vererbung
public Festgeld (Person inhaber, Waehrungsrechner wr) {
super(inhaber, wr);
}
public Festgeld (Person inhaber, Waehrungsrechner wr,
int initialkontostand, int laufzeit) {
super(inhaber, wr, initialkontostand);
this.laufzeit = laufzeit;
if (initialkontostand < mindBetrag) {
Bildschirm.gibAus("Mindest-Betrag wird nichterreicht");
}
}
Vererbung
411
Übung: Vererbung
public void setzeLaufzeit (int neueLaufzeit) {
this.laufzeit = neueLaufzeit;
}
public int kuendigen () {
return (auszahlen(holeKontostand()));
}
Vererbung
412
public int auszahlen (int betrag) {
if (betrag == holeKontostand()) {
Datum heute = Datum.aktuellesDatum();
int abgelaufeneZeit =heute.gibDifferenz(letzteTransaktion);
if (abgelaufeneZeit >= this.laufzeit) {
int zinsen =holeWaehrungsrechner().wandeleInPfennig
(berechneZinsen(laufzeit));
int pfennige = holeKontostand()+zinsen;
zahle(-betrag);
return (pfennige);
} else {
Bildschirm.gibAus("Laufzeit noch nicht errreicht");
}
} else {
Bildschirm.gibAus(“Auszahlung der ges. Summe nötig");
}
}
413
Zusammenfassung
• Finden ähnlicher Objekte– Vererbungsbeziehung
• Zugriffsrecht: protected
• Überschreiben von Methoden– Schlüsselwort: final
• Abstrakte Methoden
• Polymorphie
Vererbung
Kapitel 13
Schnittstellen (Interfaces)vgl. Kapitel zu Interfaces aus Ken Arnold, James
Gosling, The Java Programming Language,Second Edition, Addison-Wesley
415
Motivation
• Interfaces sind “Klassen ohne Methodenimplementierungen”.
• Interfaces werden auch Schnittstellen genannt. ImDoberkat/Dißmann-Buch werden sie Abstraktionen genannt.
• Grundlegende Motivation:– Trennung Spezifikation / Realisierung– Ermöglichung von Mehrfacherbung
416
Motivation: Trennung Spezifikation / Realisierung
• Realisierung ist noch nicht bekannt, aber man weiß schon, wasrealisiert werden soll.
• Man will mehrere auch konkurrierende Realisierungenzulassen und dabei sicherstellen, daß gewisse Eigenschaftengewährleistet werden.
• Die grundlegenden Eigenschaften werden durch Signaturenfestgelegt.
• Die Signatur einer Methode legt ihr Eingabe-/Ausgabeverhalten fest, also die Typen der Eingabeparameterund den Rückgabewert.
417
Erläuterung SignaturNatSig = (S, F) mit Signatur der Algebra der
natürlichen Zahlen
S={Nat, Bool}F={0Nat, succNat, +Nat, =Nat}
type: F → S* x S0Nat → () x Nat oder 0Nat:() → NatsuccNat → Nat x Nat oder succNat : Nat → Nat
+Nat → Nat x Nat x Nat oder +Nat : Nat x Nat → Nat=Nat → Nat x Nat x Bool oder =Nat : Nat x Nat → Bool
true Bool → () x Bool oder true Bool :() → Bool
false Bool → () x Bool oder false Bool :() → Bool=bool → Bool x Bool x Bool oder =bool : Bool x Bool → Bool1Nat → () x Nat oder 1Nat:() → Nat
418
Motivation: Mehrfacherbung
Mehrfacherbung (multiple inheritance) =eine Klasse besitzt mehrere Oberklassen
Problem: Welche Methode wird bei Namenskonflikten gewählt?
Lösung: In Java nicht möglich!aber: hilfreiches Ersatzkonstrukt verfügbar: Interface
Inventar
Leihwagen
KFZ
419
Interfaces
• Bsp: Lookup und Verwendung der Lookup-Typen
• extends ist das Schlüsselwort für Interfacevererbung:interface Unterinterface extends Oberinterface {
Interfacebody}
• Klassen erben von Interfaces über das Schlüsselwortimplements
• Bsp: SimpleLookup
interface I {Methodendeklarationen;
}
420
Interfaces
• Klassen können von einem oder mehreren Interfaces und auchzusätzlich von einer Oberklasse erben:
class NameUnterklasse extends NameOberklasseimplements Interface1, Interface2, ... {
...}
• Werden von einer Klasse nicht alle Methoden des Interfacesimplementiert, muß sie mit abstract gekennzeichnet werden
• Analog zum Erben von Oberklassen ist Polymorphie möglich
421
Interfaces
• Die Supertypen einer Klasse A sind– die Klasse B, von der A erbt,– die Interfaces, die A implementiert,– und die Supertypen, dieser Klasse und Interfaces.
• Alle Interface-Methoden sind implizit public und abstract.– Begründung: public weil alle realisierenden Klassen wissen müssen,
was sie realisieren sollen, abstract weil das das Merkmal vonInterfaces ist.
• Alle Attribute sind implizit public , static und final– Begründung: Es kann nur um Konstanten gehen, die immer gleich
verwendet werden (also final). Diese braucht man dann nicht pro Objekt,sondern nur pro Klasse (also static).
422
Abstrakte Klasse versus Interface
Eine Klasse ist abstrakt, wenn mindestens eine ihrer Methoden abstrakt ist.
Insofern ist ein Interface ein Spezialfall einer abstrakten Klasse. Ein Interfacehat halt ausschließlich abstrakte Methoden.
Der Vorteil im Hinblick auf Mehrfacherbung ist, daß es ohneImplementierungen bezüglich Methoden auch keine Konflikte geben kann.
public interface Konto {public void einzahlen();public void auszahlen();...
}
423
Interface wird durch Klasse implementiert
public class Privatkontoimplements Konto {
public void einzahlen() {...
}public void auszahlen() {
...}
}
modifier class cNameimplements iName {
...}
Interfaces
424
• Interfaces können eigene Vererbungshierarchie bilden• für Interfaces ist Mehrfacherbung erlaubt:
public interface Kontoextends Vertrag, Historisierbar {
public void einzahlen() {...
}public void auszahlen() {
...}
}
interface I extends I1,I2 {Methodendeklarationen;
}
Interfaces
425
eine Klasse kann mehrere Interfaces implementieren– alle vorgegebenen Methoden müssen realisiert werden
public class Privatkontoimplements Konto, Zähler {
public void einzahlen() {...
}public void auszahlen() {
...}
public int inkrementiere() {...
}
}
class Cimplements I1,I2 {
...}
Interfaces
426
Mehrfacherbung• Mit Interfaces läßt sich Mehrfacherbung erreichen
–
– Lösung: Implementierung eines Interfaces
Interface
Klasse B
Klasse C
Klasse A
Klasse A
Klasse C
Interface I
public class SubNameextends SuperNameimplements InterfaceName, ...,InterfaceName {
...
}
427
Interface kann als Typ für eine Referenz dienen, d.h.Interfaces unterstützen polymorphes Verhalten wie Oberklassen.
Girokonto dasGiro = new Girokonto();
Konto kto = dasGiro;
kto.einzahlen(500);
Das durch kto referenzierte Objekt bestimmt die Methode, die ausgeführt wird!
Interfaces
428
interface W {}
interface X extends W {}
class Y implements W {}
class Z extends Y implements X {}
Interfaces
W
X
Z
Y
429
interface W {}
interface X extends W {}
interface Y extends W {}
class Z implements X, Y {}
Interfaces
W
X
Z
Y
430
Namenskonflikte beim Realisieren mehrerer Interfaces:
Was passiert, wenn eine Methode mit dem gleichen Namen in zwei zurealisierenden Interfaces vorkommt?
1. Fall: Überladen2. Fall: eine Realisierung3. Fall: unlösbarer Konflikt (gleiche Parameter, unterschiedlicheRückgabetypen)
Was passiert bei gleichnamigen Attributen?
Referenzierung über InterfaceName.Attribute
Interfaces
431
Interfaces haben keine ausgezeichnete Wurzel, von der alle Interfaces erben(anders als Klassen, die alle von Object erben). Dennoch könnenAusdrücke eines beliebigen Interface-Typen an eine Referenz auf einObjekt der Klasse Object zugewiesen werden, denn ein Objekt, das einInterface implementiert ist halt irgendein Objekt und damit auch vom TypObject .
Interfaces
432
Garantieren von Methoden
• Trennung von Deklaration und Implementierung– Deklaration
public interface Konto {public void einZahlen();public void ausZahlen();...
}
Interface
public interface iName {Methodendeklarationen;
}
Interfaces können von anderenInterfaces erben (extends )
433
Garantieren von Methoden
• Trennung von Deklaration und Implementierung– Implementierung
public class Girokontoimplements Konto {
public void einZahlen() {...
}public void ausZahlen() {
...}
}
Interface
public class cNameimplements iName {
}
Klassen können mehrereInterfaces implementieren(implements i1, i2, ... )
434
Interfaces versus abstrakte Klassen
Interfaces erlauben eine Art Mehrfacherbung. Eine Klasse kann nur von eineranderen Klasse erben, selbst dann wenn die vererbende Klasse nurabstrakte Methoden hat.
Eine abstrakte Klasse kann teilweise implementiert sein, sie kann überprotected Attribute, static Methoden usw. verfügen. Interfaces könnennur public Konstanten und Methoden ohne Realisierungen beinhalten.
Tipp: Jede grundlegende Klasse, von der geerbt wird, sollte dieImplementierung eines Interface sein! Nur dann können andere Klassen(die schon erben) von der allgemeinen Festlegung profitieren.
Kapitel 14
Ausnahmen (Exceptions)
436
Ausnahmen - Wieso eigentlich?
(Etwas naive) Annahme:
– Algorithmen sind so entworfen, daß alle denkbarenZustände behandelt werden. Ungewollte Terminierungen(Abstürze) können deshalb gar nicht vorkommen.
• Beispiel: beim Einfügen eines Elementes in eine Liste werden alledenkbaren Fälle (Einfügen in leere Liste, Einfügen vor erstemListenelement, Einfügen zwischen Listenelemente, Einfügen hinterdem letzten Listenelement) unterschieden und korrekt behandelt.
– Wozu also Ausnahmen?
437
Ausnahmen - Wieso eigentlich?
Das Ende der Naivität:
– Algorithmen werden durch das Zusammenwirken vonObjekten realisiert. Objekte entscheiden autonom über dieAusführung von Methoden, können dabei aber nicht denGesamtzustand des Systems berücksichtigen. Wenn eineAusführung nicht erfolgen kann, dann erfolgt eineAusnahme, die entsprechend behandelt werden kann (undmuß).
– Viele Objekte mit internen Zuständen führen zu einerZustandsexplosion, so daß es nicht mehr handhabbar ist,alle Zustände explizit zu unterscheiden.
438
Ausnahmen - Wieso eigentlich?
Und noch ein pragmatischer Grund:
– Selbst wenn es in kleineren Programmen möglich ist, alleAusführungen abzufragen und deshalb auch ohneAusnahmen auszukommen, so wird durch die ganzeFallunterscheiderei der eigentlich Algorithmus verschleiert.Das Konzept der Ausnahmebehandlung wirkt dementgegen, indem der eigentliche Algorithmus von derAusnahmebehandlung getrennt wird.
439
Übersicht über dieses Kapitel
• Was sind Ausnahmen? / Grundidee der Ausnahmebehandlung– Die Klasse java.lang.Exception
• „Werfen“ von Exceptions
• Weiterleiten von Exceptions
• „Fangen“ von Exceptions
• Die Klassen Exception, Error, RuntimeException
440
Was sind Ausnahmen?
• Ausnahmen können im Programmablauf auftreten– Division durch Null– Datei nicht vorhanden– ...
• Ziel ist aber: Erstellen eines stabilen Programms• Ausnahme: Zustand, der das Programm daran hindert, im
normalen Ablauf fortzufahren
• Trennung von Fehlerbehandlungscode und regulärem Code• Es kann leichter sein, Ausnahmen eintreten zu lassen und sie
ordentlich zu behandeln als sie unbedingt zu vermeiden.
441
• Es gibt vordefinierte Ausnahmen, diese können erweitertwerden.
• In der Definition von Methoden wird definiert, welcheAusnahmen auftreten können.
• Beim Aufruf von Methoden wird definiert, wie diemöglicherweise auftretenden Methoden behandelt werden.Hierzu wird der potentiell Ausnahmen verursachende Code ineinen try{...}- Block eingebettet.
Grundidee der Ausnahmebehandlung
442
Grundidee der Ausnahmebehandlung
• Wenn im try{...}- Block Ausnahmen auftreten, werden siegefangen. Was dann passiert, wird im catch{...}- Blockfestgelegt.
• Nach dem Fangen und Verarbeiten wird im finally{...}-Block definiert, was zum Abschluß der Ausnahmebehandlungpassiert.
• Und nun erst mal ein Beispiel!
443
Die Klasse java.lang.Exception
public class Exception ... {
public Exception() {..};
public Exception(String s) {...};
// und von java.lang.Throwable geerbt:
// Kurzbeschreibung des Fehlers
public String toString() {...};
// Details des Fehlers
public String getMessage() {...};
// Details mit Aufrufstack
public String printStackTrace() {...};
...
} 444
„Werfen“ von Ausnahmen
...
if (kontostand-betrag > dispo) {
zahle(-betrag);
return (betrag);
} else throw new Exception();
...
throw new Exception ();throw new Exception(„Text“);
445
Definition des Werfens von Ausnahmen in Methoden
public int auszahlen(int betrag) throws Exception {
Datum heute = Datum.aktuellesDatum();
int zinstage = heute.gibDifferenz(letzteTransaktion);
int zinsen = berechneZinsen(zinstage);
zahle(zinsen);
if (kontostand-betrag > dispo) {
zahle(-betrag);
return (betrag);
} else throw new Exception(“Konto nicht gedeckt“);
}
Modifier Rückgabetyp Methodenname (...) throws Exception {
446
Definition des Werfens von Ausnahmen in Methoden
Die Ausnahmen, die geworfen werden können, müssen deklariertwerden, weil Programmierer, die Methonden aufrufen, dasAusnahmeverhalten genauso kennen müssen wie das normaleVerhalten (Signatur).
Die in der Methodendefinition deklarierten Ausnahmen werdenauch „checked“ Ausnahmen genannt (im Unterschied zu dennicht explizit deklarierten und vom Compiler nicht explizitgeprüften Laufzeitausnahmen).
447
Definition des Werfens von Ausnahmen in Methoden
Das heißt: RuntimeException (z.B. ClassCastException ,ArithmeticException ) werden nicht explizit deklariert. Siekönnen von jeder Methode geworfen werden und werdendeshalb auch nicht vom Compiler überprüft (sie bleiben„unchecked“), d.h. Exceptions der Klassen java.lang.Errorund java.lang.RuntimeException und deren Unterklassenmüssen nicht in der throws -Deklaration gekennzeichnetwerden.
448
Aufrufen von Methoden, die Ausnahmen werfen
Beim Aufruf einer Methode, die in ihrer throws-AnweisungAusnahmen auflistet, bleiben drei Möglichkeiten:– Fangen und Behandeln– Fangen, Abbilden auf eigene Ausnahme, Werfen der eigenen
Ausnahme– Deklarieren der Ausnahme in der aufrufenden Methode und dann
Fangen und Weiterleiten der Ausnahme
• Immer dabei: Fangen von Ausnahmen!
449
Fangen von Ausnahmen
• Mit try und catch werden Exceptions aufgefangen– try -Block: Bereich, in dem Ausnahmen auftreten können– catch -Block: Bereich, in dem die Fehlerbehandlung stattfindet– finally -Block: optional, wenn vorhanden, wird er auf jeden Fall ausgeführt
...
Kont o k = new Konto();
try {
k.auszahlen(10000);
} catch (Exception e) {
Bildschirm.gibAus(e.getMessage());
} finally {
Bildschirm.gibAus(k.holeKontostand());
}
Werfen
Fangen
Aufräumen
450
Fangen von Ausnahmen
try {
statements
} catch (exception_type1 identifier1) {
statements
} catch (exception_type2 identifier2) {
statements
....
} finally {
statements
}
Mehrerecatch-Blöcke!
451
Verarbeiten von Ausnahmen
Der Rumpf des try -Blockes wird ausgeführt bis eine Ausnahmeauftritt oder bis zum Ende (falls keine Ausnahme auftritt).
Wenn eine Ausnahme auftritt wird jeder catch -Block geprüft (vonoben nach unten), um diejenigen catch -Blöcke zu finden, diedie Ausnahme fangen können.
Es dürfen keine Ausnahmen gefangen werden, die im try -Blocknicht auftreten können.
Für einen passenden catch -Block wird der Identifier auf dasaufgetretene Exception-Objekt gesetzt. Kein weiterer catch-Block wird ausgeführt (also nur der erste passende!). Es mußalso darauf geachtet werden, daß die catch- Blöckeunterschiedliche Ausnahmen fangen.
452
Verarbeiten von Ausnahmen
Wenn kein passender catch -Block gefunden wird, sickert dieAusnahme in weiter außen liegende try -Blöcke durch.
Wenn ein finally -Block vorkommt, dann wird er ausgeführt,nachdem der try- Block abgearbeitet ist (entweder durchnormale Beendigung, Ausnahme oder return/break ).
Ein finally -Block ist sinnvoll, um notwendige Resourcenfreizugeben (z. B. Schließen einer Datei), denn derProgrammcode außerhalb des try -Blocks wird nicht mehrerreicht, falls innerhalb eines catch -Blocks wieder eineAusnahme geworfen wird.
453
• Ausnahmen können auftreten durch– explizite throw -Anweisung– Aufruf einer Methode mit throws - Deklaration
Ausnahmebehandlung
454
• Auffangen und Weiterwerfen (throw im catch -Block) istsinnvoll, um wichtige Zusatzinformationen anzuhängen
• Kann in einer Methode eine Ausnahme auftreten, muß sie– entweder durch try und catch aufgefangen werden– oder durch throws in der Methodendeklaration weitergeleitet werden
Ausnahmebehandlung
455
Exception, Error, RuntimeException
• Exception:– nicht für ernsthafte, kritische Fehler– Einsatz als Feature im Programmablauf
• Error:– Schwerwiegende Fehler der Virtual Machine– Sollten nicht selbst geworfen oder aufgefangen werden
• RuntimeException– Systemfehler, die nicht deklariert werden müssen– Beispiel: Teilung durch Null (0)
456
Schreiben eigener Ausnahmen
• Neue Klasse wird von java.lang.Exception abgeleitet :
public class KeineDeckungException extends Exception {
public KeineDeckungException() {
super();
}
public KeineDeckungException(String s) {
super(s);
}
}
457
Benutzen eigener Ausnahmenpublic class Girokonto extends Konto {
...
public int auszahlen( int betrag) throws KeineDeckungException {
...
if (kontostand-betrag > dispo) {
zahle(-betrag);
return (betrag);
} else throw new KeineDeckungException( “ Konto nicht gedeckt“);
}
}
• Auffangen der Exception:try {
k.auszahlen(1000);
} catch (KeineDeckungException e) {
Bildschirm.gibAus(e.getMessage());
}
458
Übung: Behandlung von Ausnahmen
Motivation• Schreiben eigener Ausnahmen• Benutzen von Ausnahmen
Aufgabe• Identifizieren Sie zwei weitere Ausnahmen und schreiben Sie jeweils eine
neue Klasse für diese Ausnahme• Erweitern Sie das Programm so, daß diese Exceptions geworfen,
weitergeleitet und gefangen werden• Testen Sie die geänderten Klassen mit der der Klasse
TestKartenverwaltung . Verursachen Sie dabei absichtlich Fehler.
459
Übung: Behandlung von Ausnahmenpublic class KontoNichtVorhandenException extends Exception {
public KontoNichtVorhandenException () {
super ();
}
public KontoNichtVorhandenException (String s) {
super (s);
}
}
public class LaufzeitNichtErreichtException extends Exception {
public LaufzeitNichtErreichtException () {
super ();
}
public LaufzeitNichtErreichtException (String s) {
super (s);
}
}
Exceptions
460
Übung: Behandlung von Ausnahmenpublic class Kartenverwaltung {
...
public Konto holeKonto (String kartennummer)
throws KontoNichtVorhandenException {
Konto dasKonto = null ;
for (int i=0; i<freiIndex; i++){
if (kartennummer.equals(kartennr[i])){
dasKonto = konten[i];
}
}
if (dasKonto == null ) throw new KontoNichtVorhandenException();
return (dasKonto);
}
...
}
Exceptions
461
Übung: Behandlung von Ausnahmenpublic class TestKartenverwaltung {
public static void main (String[] args) {
Waehrungsrechner rechner = new Waehrungsrechner();
Person inhaber = new Person( “ Urs“, “ Müller“, “ Hauptstr. 1“,
“ 12345“, “ Berlin“);
Girokonto k = new Girokonto(inhaber, rechner, 100);
Festgeld f = new Festgeld(inhaber, rechner, 100000);
Kartenverwaltung verwaltung = new Kartenverwaltung();
verwaltung.erfasseWeiteresKonto("1", “1234", k);
verwaltung.erfasseWeiteresKonto(“2", “5678", f);
try {
Festgeld geld = (Festgeld) verwaltung.holeKonto(“2“);
geld.kuendigen();
} catch (LaufzeitNichtErreichtException e) {
Bildschirm.gibAus(e.getMessage());
}
Exceptions
462
Übung: Behandlung von Ausnahmen
try {
Girokonto gKonto = (Girokonto) verwaltung.holeKonto("1“);
gKonto.auszahlen(1000);
} catch (KontoNichtVorhandenException e1) {
Bildschirm.gibAus(e1.getMessage());
} catch (KeineDeckungException e2) {
Bildschirm.gibAus(“Konto ist nicht gedeckt“);
}
...
}
Exceptions
Kapitel 15
Pakete und Zugriffskontrolle
464
Pakete, Verkapselung, Zugriffskontrolle
• Pakete, Verkapselung und Zugriffskontrollmechanismen sindMöglichkeiten, Programme besser zu strukturieren=> Diese Mechanismen sind eine Grundvoraussetzung für
eine erfolgreiche Programmierung im Team
• Überlegungen der Grobstrukturierung sollten vor demProjektstart gemacht werden, und nicht nachher
• Modellierungssprachen wie UML können hier die Planungerheblich erleichtern, denn je größer das Software-Projekt istdesto wichtiger ist eine gründliche Planung
465
Pakete
• Durchpackage Packagename;wird ein neuer Namensraum als Paket zusammengefaßt
• Die package -Anweisung ist die erste Anweisung der Datei
• Zugehörige CLASS-Files stehen in einem Unterverzeichnesmit dem Namen Packagename, dessen Wurzel befindet sich ineinem Verzeichnis, welches im CLASSPATHaufgenommen ist.
• Packages können auch Unter-Packages haben, analog zuUnterverzeichnissen im Dateisystem
466
Pakete
• Pakete werden in der Regel durch eine Abbildung der Pakete-Struktur auf das Dateisystem realisiert
• Unter-Pakete werden mitpackage Hauptpackagename. Unterpackagename;definiert
• Klassen aus anderen Paketen werden durchPackagename.Klassenname angesprochen
467
Pakete
• Durchimport Packagename. Klassenname;wird eine Klasse aus einem anderen Pakete bekannt gemacht.Sie kann dann wie eine lokal definierte Klasse ohne Angabedes Paketnamens benutzt werden.
• Mitimport Packagename. *;werden alle Klassen im entsprechenden Paketbekanntgemacht
• import java.lang.*; wird immer ausgeführt und mußnicht explizit angegeben werden
468
Pakete
Beispiel:
• Anlegen eines Wurzelverzeichnisses für ein Projekt, hierC:\projekt (bzw. ~/projekt in UNIX). und Wechsel indieses Unterverzeichnis (cd projekt ).
• Für Pakete müssen Unterverzeichnisse angelegt werden. Hier:"md utils " und "md hauptpackage ".
• Java-Files für die einzelnen Pakete müssen in denentsprechenden Unterverzeichnissen editiert werden.Hier: Datum.java im Verzeichnis utils undStartklasse.java im Verzeichnis hauptpackage .
469
PaketeDatei Datum.java im Verzeichnisutils :
Datei Startklasse.java imVerzeichnis hauptpackage :
• Zum Compilieren Angabe derHauptdatei vom Wurzelverzeichnisaus.javac hauptpackage/Startklasse.java
•Abhängige Klassen werden (fallsnicht schon geschehen) mitcompiliert.• Zum Ausführen Angabe der zustartenden Klasse innerhalb derPaket-Hierarchie. Unterpaketewerden durch Punkt gekennzeichnet:java hauptpackage.Startklasse
• Ohne Angabe von import utils.*
müßte die Klasse Datum über dasPaket angesprochen werden:utils.Datum d = new utils.Datum();
package utils;class Datum() {
int tag, monat,jahr;
... // nun dieMethoden}
package hauptpackage;import utils.*;class Startklasse {
public static voidmain(String[] args) {
Datum d = new Datum();...
}}
470
Pakete
• Pakete sind Sammlungen von Klassen und Interfaces
package demo;
public class A {...
}
import demo.*;import demo.windows.*
Zusammenfassung von Klassen
Aufruf
import Package.Klasse;
import Package.*;
Definition
package PackageName; oder
package PackgaeName.SubPackageName;
471
Zugriffskontrolle für Klassen
• Klassen können standardmäßig nur auf andere Klassen ausdem gleichen Package zugreifen.
• Mit Hilfe der Zugriffsspezifikation public kann die Klasseauch nach außen sichtbar gemacht werden, also auch überPaketgrenzen hinaus!
public class Klassenname {
...
}
472
Zugriffskontrolle für KlassenBeispiel:
package A;public class Test1 {}
package A;class Test2 {}
package A;class Haupt1 {
void methode() {// beides erlaubt:
Test1 t1 = new Test1();Test2 t2 = new Test2();
}}
package B;
import A.*;
class Haupt2 {
void methode() {
// erlaubt:
Test1 t1 = new Test1();
// nicht erlaubt:
Test2 t2 = new Test2();
}
}
473
Übersicht Zugriffsrechte
• Alle Zugriffsrechte in Java im Überblick
Zusammenfassung von Klassen
Zugriff auf public protected package private
Gleiche Klasse Ja Ja Ja Ja
Klasse im gleichen Paket Ja Ja Ja Nein
Subklasse im fremden Paket Ja Ja / Nein Nein Nein
Keine Subklasse, fremdes Paket Ja Nein Nein nein
474
Zugriffskontrolle für Attribute / Methoden
• Methoden und Attribute einer Klasse können optional eineder Sichtbarkeitsmodifikationen public , protected oderprivate erhalten. Ist nichts spezifiziert, gilt das Zugriffsrechtpackage
• Attribute sollten immer als private definiert werden. DerZugriff auf die Attributwerte wird dann nur über set- und get-Methoden erlaubt.
475
Zugriffskontrolle für Attribute / Methoden
• public heißt, das Attribut bzw. die Methode ist für jedensichtbar.
• protected heißt, das Attribut bzw. die Methode ist innerhalbdes Packages und in abgeleiteten Klassen sichtbar. DieSichtbarkeit in abgeleiteten Klassen ist aber nur danngegeben, wenn die Referenz auf das abgeleitete Objekt, vondem aus das protected -Attribut angesprochen werden soll,nicht eine Referenz vom Typ der Oberklasse ist.
• private heißt, das Attribut bzw. die Methode ist nur innerhalbder Klasse sichtbar
476
Zugriffskontrolle für Attribute / Methoden
• Ohne Spezifikation kann man innerhalb des Packages aufAttribute bzw. Methoden zugreifen.
• Ist die Klasse nicht als public deklariert, kann außerhalb desPackages auch nicht auf Methoden oder Attribute zugegriffenwerden, die als public deklariert sind.
477
Zugriffskontrolle für Attribute / MethodenBeispiel:
package A;public class ZugriffsTest {
private int priv;protected int prot;public int pub;int pack;
private void privMethode() {}protected void protMethode() {}public void pubMethode() {}void packMethode() {}
public void test(ZugriffsTest z) {
// Alle Zugriffe erlaubtpriv = 1; z.priv = 1;prot = 1; z.prot = 1;pub = 1; z.pub = 1;pack = 1; z.pack = 1;privMethode();protMethode();pubMethode();packMethode();z.privMethode();z.protMethode();z.pubMethode();z.packMethode();
}}
478
Zugriffskontrolle für Attribute / MethodenBeispiel:ZugriffsTest2 im gleichen Packagewie Zugriffstest
package A;public class ZugriffsTest2 {
public static voidmain(String[] args) {
ZugriffsTest t =new ZugriffsTest();
t.priv = 1; // n. erlaubtt.prot = 1; // erlaubtt.pub = 1; // erlaubtt.pack = 1; // erlaubt
// nicht erlaubt:t.privMethode();
// erlaubt:t.protMethode();t.pubMethode();t.packMethode();
}}
479
Zugriffskontrolle für Attribute / MethodenBeispiel:ZugriffsTest3 abgeleitet vonZugriffsTest und im gleichenPackage wie ZugriffsTest
package A;public class ZugriffsTest3
extends ZugriffsTest {public static void
main(String[] args) {
ZugriffsTest3 t =new ZugriffsTest3();
t.priv = 1; // n. erlaubtt.prot = 1; // erlaubtt.pub = 1; // erlaubtt.pack = 1; // erlaubt
t.privMethode(); // n.e.t.protMethode(); // erl.t.pubMethode(); // erl.t.packMethode(); // erl.
}void test3 () {
priv = 1; // n. erlaubtprot = 1; // erlaubtpub = 1; // erlaubtpack = 1; // erlaubtprivMethode(); // n.e.protMethode(); // erl.pubMethode(); // erl.packMethode(); // erl.
}}
480
Zugriffskontrolle für Attribute / MethodenBeispiel:ZugriffsTest4 abgeleitet vonZugriffsTest und nicht im gleichenPackage wie ZugriffsTest
package B;import A.*;public class ZugriffsTest4
extends ZugriffsTest {public static void
main(String[] args) {
Zugriffstest4 t =new ZugriffsTest4();
t.priv = 1; // n. erlaubtt.prot = 1; // erlaubtt.pub = 1; // erlaubtt.pack = 1; // n.erlaubt
t.privMethode(); // n.e.t.protMethode(); // erl.t.pubMethode(); // erl.t.packMethode(); // n.e.
}void test4 () {
priv = 1; // n. erlaubtprot = 1; // erlaubtpub = 1; // erlaubtpack = 1; // n. erlaubtprivMethode(); // n.e.protMethode(); // erl.pubMethode(); // erl.packMethode(); // n.e.
}}
481
Zugriffskontrolle für Attribute / MethodenBeispiel:ZugriffsTest5 abgeleitet vonZugriffstest und nicht im gleichenPackage wie ZugriffsTest
package B;import A.*;public class ZugriffsTest5
extends ZugriffsTest {public static void
main(String[] args) {
Zugriffstest t =new ZugriffsTest5();
t.priv = 1; // n. erlaubtt.prot = 1; // n. erlaubtt.pub = 1; // erlaubtt.pack = 1; // n.erlaubt
t.privMethode(); // n.e.t.protMethode(); // n.e.t.pubMethode(); // erl.t.packMethode(); // n.e.
}}
• Im Unterschied zuZugriffsTest4 wird hier übereine Referenz auf Zugriffstestauf die Attribute bzw. Methodenzugegriffen.
• FürZugriffstest t = new
Zugriffstest();
erhalten wir die gleichen Zugriffs-einschränkungen (nur public -Zugriff)
482
Verkapselung
• Verkapselung ist ein Grundprinzip der Objektorientierung, undkann als Empfehlung verstanden werden, Zugriffskontrollenrichtig einzusetzen also:
• Jede Klasse legt mit Hilfe der Zugrifsrechte selbst fest, wer aufihre Attribute und Methoden zugreifen darf, hierbei gilt:– Methoden, die nicht dokumentiert sind, bzw. nur Hilfsfunktionen für
andere Methoden sind, sollten private oder zumindest protectedsein
– Attribute sollten nicht public sein, um Änderbarkeit undDatenkonsistenz sicherzustellen
– Für Zugriffe auf Attribute sollten get - und set -Methoden zur Verfügunggestellt werden, die zugehörigen Attribute sollten dann private sein
483
Verkapselung
• Verstecken von Implementierungsdetails ist wichtig, umÄnderbarkeit der Implementierung zu gewährleisten.Eine nicht sichtbare Methode kann auch nicht von anderenbenutzt worden sein.
• Verstecken von Implementierungsdetails kann das Verständniserleichtern, da nur die für den Endanwender wichtigeSchnittstellen zugreifbar sind.
484
Gesamtbeispiel Klasse Datum
Klasse Datum unter Berücksichtigung von:• Verkapselung / Zugriffskontrolle• Ausnahmebehandlung
Zeigt auch, was von Packages sichtbar gemacht werden muß!• D.h. vieles bleibt intern• nur das nötigste wird nach außen bekannt gemacht
485
Gesamtbeispiel Klasse Datum
Realisierung der folgenden Funktionalitäten:• Wochentagberechnung• Differenzbildung zwischen Daten (in Tagen)• Addition eines Datums mit einem Offset (in Tagen)• Feiertagsberechnungen
486
Klasse DatumException
• Klasse Datum bekommt eine eigene Exception-Klasse fürFehlerbehandlung
package utils;
/**
* Exception für Fehlerbehandlung der Klasse Datum.
*/
public class DatumException extends Exception {
public DatumException() {
super();
}
public DatumException(String s) {
super(s);
}
}
487
Klasse Datum - Attribute
• Attributdefinitionen der Klasse Datumpackage utils;import java.io.*;/**
* Klasse zur Verwaltung von Datumsobjekten*/
public class Datum implements Serializable {private int tagkonst; // Konstante mit Tagen seit Christi Geburt
// Konstanten für Tag, Monat und Jahr.// Daten lassen sich aus tagkonst berechnen, daher// als transient definiert.
private transient int tag, monat, jahr;
private final static String[] wt = {"Montag", "Dienstag", "Mittwoch","Donnerstag", "Freitag", "Samstag", "Sonntag"};
// Hier nun die Methoden, nächste Folien}
488
Klasse Datum - öffentl. Konstruktoren/**
* Konstruktor mit Tag, Monat und Jahr.* @exception utils.DatumException* Datum ist nicht gültig nach Gregorianischem Kalender* (Gregorianischer Kalender seit 15.10.1582)*/
public Datum (int tag, int monat, int jahr) throws DatumException {init(tag, monat, jahr); // Initialisierung der Attribute
}
Achtung: Für Kommentare sollten HTML-Umlaute verwendet werden, also"ü " für "ü". Hier aber "ü" für die bessere Lesbarkeit.
/*** Konstruktor für 1. Januar eines Jahres.*/
public Datum(int jahr) throws DatumException {init(1,1,jahr);
}
489
Klasse Datum - priv. Initialisierungsmethoden
/**
* Berechnung der Tage, die seit eines Bezugsdatums vergangen sind.
* Dieser Tag liegt vor dem 15.10.1582, dem Start des Gregorianischen
* Kalenders.
* Wichtig für Differenzbildung von Daten und für Wochentags- bzw.
* Feiertagsberechnungen.
*/
private synchronized int getTageKonst(int tag, int monat, int jahr) {
boolean schalt = (jahr%4 == 0 && (jahr%100 != 0 || jahr%400 == 0));
return (jahr-1) * 365 + (jahr-1)/4 - (jahr-1)/100
+ (jahr-1)/400
+ (monat-1)*31 - (monat>2 ? 3 : 0) + (monat>2 && schalt ? 1: 0)
- (monat>4 ? 1 : 0) - (monat>6 ? 1 : 0) - (monat>9 ? 1 : 0)
- (monat>11 ? 1 : 0) + tag;
}
490
Klasse Datum - priv. Initialisierungsmethoden
/**
* Initialisiert das Attribut tagkonst.
* Der benötigte Wert kann mit getTageKonst(tag, monat, jahr)
* berechnet werden.
* @exception utils.DatumException
* Datum vor Einführung des Gregorianischen Kalenders
*/
private void init(int tagkonst) throws DatumException {
this.tagkonst = tagkonst;
if (tagkonst < 577736)
throw new DatumException("Nur Gregorianischer Kalender" +
" ab 15.10.1582 wird untertützt");
}
491
Klasse Datum - priv. Initialisierungsmethoden/**
* Initialisiert Attribute jahr, monat und tag bei bereits* initialisiertem Attribut tagkonst.*/
private synchronized void setTagMonatJahr() {jahr = 1500;monat = 1;tag = 1;while (getTageKonst(tag, monat, jahr+100) <= tagkonst)
jahr += 100;while (getTageKonst(tag, monat, jahr+10) <= tagkonst)
jahr += 10;while (getTageKonst(tag, monat, jahr+1) <= tagkonst)
jahr ++;while (getTageKonst(tag, monat+1, jahr) <= tagkonst)
monat++;tag += tagkonst - getTageKonst(tag, monat, jahr);
}
492
Klasse Datum - priv. Initialisierungsmethoden/**
* Initialisiert Attribute jahr, monat und tag und tagkonst.** @exception utils.DatumException* Datum ist nicht gültig nach Gregorianischem Kalender.* (Gregorianischer Kalender seit 15.10.1582).* Hierbei werden alle Regeln der Datumsbildung berücksichtigt.*/
private synchronized void init(int tag, int monat, int jahr)
throws DatumException {
init(getTageKonst(tag, monat, jahr));
setTagMonatJahr();
if (tag != this.tag || monat != this.monat || jahr != this.jahr)
throw new DatumException("Datum " + tag + "." + monat + "."
+ jahr + " existiert nicht");
}
493
Klasse Datum - privater Konstruktor
/*** Konstruktor, der aus der Tageskonstante ein Datumsobjekt* erzeugt.* Dummy-Parameter notwendig, um sich von Initialisierung über* Jahreszahl zu unterscheiden.*/
private Datum(int tagkonst, boolean dummy) throws DatumException {
init(tagkonst);
setTagMonatJahr();
}
494
Klasse Datum - Objektserialisierung
/*** Bei Objektserialisierung wird nur das Attribut tagkonst* berücksichtigt.* Diese Methode sorgt für eine Rekonstruktion der* Attribute tag, monat und Jahr bei Deserialisierung*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
setTagMonatJahr();
}
495
Klasse Datum - öffentliche Methoden/**
* Berechnung des Wochentages.*/
public String wochentag() {
return wt[(tagkonst + 6) % 7];
}
/**
* Gibt die Differenz zu einem Referenzdatum d in Tagen zurück.
* Der Wert ist negativ, falls d in der Zukunft liegt, sonst positiv.
*/
public int diff(Datum d) {
return tagkonst - d.tagkonst;
}
496
Klasse Datum - öffentliche Methoden/**
* Gibt das Datum in i Tagen zurück. Auch negatives i möglich.* @exception utils.DatumException* Das Ergibnis liegt vor Einführung des Gregorianischen Kalenders.*/
public Datum plus(int i) throws DatumException {
return new Datum(tagkonst + i, true);
}
/**
* Gibt String-Repräsentation des Datums zurück.
*/
public String toString() {
return wochentag() + ", den " + tag + "." + monat + "." + jahr;
}
497
Klasse Datum - öffentliche Methoden/**
* Berechnet Ostersonntag des entsprechenden Jahres nach der Gaußschen* Osterformel (1800), welche für die Jahre 1583 bis 8202 gültig ist.* @exception utils.DatumException* Falls Osterformel nicht gültig.*/
public Datum OsterSonntag() throws DatumException {if (jahr < 1583 || jahr > 8202)
throw new DatumException("Osterformel gilt von 1583 bis 8202");int a = jahr % 19; int b = jahr % 4; int c = jahr % 7;int m = (8 * (jahr/100) + 13) / 25 - 2;int s = jahr/100 - jahr/400 - 2; int M = (15 + s - m) % 30;int N = (6 + s) % 7; int d = (M + 19*a) % 30;int D;if (d == 29) D = 28;else if (d == 28 && a >= 11) D = 27;else D = d;int e = (2*b + 4*c + 6*D + N) % 7;return new Datum(22,3,jahr).plus(D+e);
}
498
Klasse Datum - öffentliche Methoden// Auf Ostern basierende Feiertage:public Datum PfingstSonntag() throws DatumException {
return OsterSonntag().plus(49);}public Datum RosenMontag() throws DatumException {
return OsterSonntag().plus(-48);}public Datum Himmelfahrt() throws DatumException {
return OsterSonntag().plus(39);}
// Feste Feiertage:public Datum ErsterWeihnachtstag() throws DatumException {
return new Datum(25,12,jahr);}public Datum Maifeiertag() throws DatumException {
return new Datum(1,5,jahr);}
499
Klasse Datum - Anwendungpackage hauptpackage;
import utils.*;
public class Anwendung {
public static void main(String[] args) {
try {
Datum d = new Datum(1,1,2000).plus(10000);
System.out.println("Am " + d + " wird das 3. Jahrtausend"
+ " 10000 Tage alt.");
}
catch (DatumException e) {}
}
}
Ausgabe:Am Mittwoch, den 19.5.2027 wird das 3. Jahrtausend 10000 Tage alt.
500
Klasse Datum - Anwendungpackage hauptpackage;
import utils.*;
public class Anwendung {
public static void main(String[] args) {
try {
System.out.println("Ostersonntage:");
for (int i=1995; i<=2010; i++)
System.out.println(new Datum(i).OsterSonntag());
}
catch (DatumException e) {}
}
}
Ausgabe:Ostersonntage:Sonntag, den 16.4.1995Sonntag, den 7.4.1996Sonntag, den 30.3.1997Sonntag, den 12.4.1998Sonntag, den 4.4.1999Sonntag, den 23.4.2000Sonntag, den 15.4.2001Sonntag, den 31.3.2002Sonntag, den 20.4.2003Sonntag, den 11.4.2004Sonntag, den 27.3.2005Sonntag, den 16.4.2006Sonntag, den 8.4.2007Sonntag, den 23.3.2008Sonntag, den 12.4.2009Sonntag, den 4.4.2010
Kapitel 16
Überblick über Java-Klassenbibliotheken
502
Klassenbibliothek
• Umfangreiche Klassenbibliotheken machen die Mächtigkeitvon Java aus.
• Während sich der Sprachumfang kaum von dem andererSprachen unterscheidet, bedeutet die Verfügbarkeit einerumfangreichen Klassenbibliothek einen Vorteil.
• Von besonderer Bedeutung ist dabei, daß die Bibliothekplattformübergreifend eingesetzt werden kann.
• Die Bibliothek ist in Pakete gegliedert. Nur dadurch wird siehandhabbar.
• Diese Pakete können wie selbstdefinierte Pakete verwendetwerden.
503
Klassenbibliothek
• Klassenbibliotheken sehr umfangreich• Hier nur Einblick in grobe Einteilung und wichtige
Funktionalitäten• Vollständige Übersicht in• “JDK 1.2 Documentation“ bzw.
“Java SDK SE v1.3 Documentation”=> Nachschlagewerk
504
Übersicht Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
505
java.applet Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
506
java.awt Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
507
java.beans Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
508
java.io Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
509
java.lang Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
510
java.lang
• Basispaket der Sprache
• alle Systemklassen sind hier untergebracht
• Klassen dürfen ohne import -Deklaration direkt angesprochenwerden (vgl. System, String)
Die Java Klassenbibliotheken
511
java.lang: Object , String und StringBuffer
• Klasse Object– Die Mutter aller Klassen
• Klassen String und StringBuffer– Zeichenketten
512
Class
• Klasse Class– Klasse um Klassennamen und Instanzen zu verwalten– Die Klasse Object hat die Methode
public final Class getClass()um zugehöriges Class-Objekt zu erhalten
– Methode public String getName() gibt Namen der Klasse zurück
– Es lassen sich mit Hilfe des Class-Objektes verfügbare Konstruktorenund Methoden ermitteln (seit JDK 1.1)
– Neue Objekte der Klasse können so erzeugt werden, ohne daß manVorabinformationen hat (seit JDK 1.1)
513
System
• Klasse System– Sammlung von Klassenattributen und -methoden– Anbindung an Standard-In, Standard-Out und Standard-Error-Stream
(System.in , System.out und System.err )
– Systemnahe Methoden– public static long currentTimeMillis()
• gibt Millisekunden seit 1. Janur 1970 zurück
– public static void exit(int status)• Beendet das Programm (und die Virtuelle Maschine)
– public static void gc()• Empfehlung an den Garbage - Kollektor, Speicher freizugeben. In der Regel nicht
nötig.
514
java.lang
• java.lang.System– Anbindung an Standard-Err, Standard-In, Standard-Out-Stream
{...System.out.println(“Hallo”);...
}
– Systemnahe Methoden
Die Java Klassenbibliotheken
public static final PrintStream err
public static final PrintStream in
public static final PrintStream out
public static void exit(int status)
public static void gc()
515
Einhüllende Klassen
• Klassen Boolean, Byte, Character, Double,Float, Integer, Long, Short
• Nützlich, wenn primitive Datentypen als Objekt benötigtwerden, z.B. für objektbasierte Datenstrukturen
• Alle einhüllenden Klassen haben den entsprechendeneinfachen Datentypen als Konstruktor– Beispiel:
Float zahl=3.5;Float zahlHülle = new Float(zahl);
• Alle einhüllenden Klassen (bis auf Character) haben Stringals Konstruktorargument– Beispiel:
Long l = new Long("2.142352123");
516
Einhüllende Klassen
• Byte , Double , Float , Integer , Long und Short (sowiejava.math.BigDecimal und java.math.BigInteger )sind von abstrakter Klasse Number abgeleitet
• Für Objekte der Klasse Number sind Wandlungen zu primitivenDatentypen möglich mit byteValue() , doubleValue(),floatValue(), intValue(), longValue() undshortValue()
• Beispiel: Konvertierung von String nach doubleString s = "1.345";double d = new Double(s).doubleValue();
517
java.lang
• java.lang.Math– Konstanten E und Pi
– Methoden für Betrag, Rundung, Trigonometrische Funktionen,Exponent / Logarithmus, etc.
Die Java Klassenbibliotheken
public static int abs(int a)
public static native double sin(double a)
public static native double sqrt(double a)
518
java.math Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
519
java.rmi Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
520
java.security Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
521
java.util Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
Kapitel 17Dynamische
Datenstrukturen
17.1 Listen17.2 Bäume17.3 Graphen17.4 Schlangen17.5 Keller17.6 Mengen
524
Überblick
• Unter dynamischen Datenstrukturen verstehen wir Strukturen,die je nach Bedarf und damit dynamisch wachsen undschrumpfen können (Unterschied zu Arrays!).
• Die Idee ist, daß die einzelnen Elemente die zu speichernden /zu verarbeitenden Daten speichern und daß diese Elementemiteinander verknüpft werden.
• Die Art der Elemente ist dabei stark problemabhängig undvariiert von Anwendung zu Anwendung.
• Für die Verknüpfung gibt es einige typische Muster. Diesetypischen Muster sind in den klassischen dynamischenDatenstrukturen realisiert.
Dynamische Datenstrukturen
525
Überblick
• Neben der Verknüpfung werden diese Datenstrukturen auchnoch dadurch charakterisiert, daß es bestimmteZugriffsmethoden gibt.
• Wie in der Objektorientierung üblich, werden die dynamischenDatenstrukturen also durch die Art der Verknüpfung derElemente und die Zugriffsmethoden festgelegt.
• Weitere Methoden der Ausprägungen der dynamischenStrukturen hängen auch von der Struktur der Einzelelementeab.
Dynamische Datenstrukturen
526
Wichtige dynamische Datenstrukturen
• Listen, lineare Listen, doppelt verkettete• Bäume, binäre Bäume, binäre Suchbäume• Graphen, gerichtete Graphen, ungerichtete Graphen• Stack, Schlangen• Mengen
– Wie wird eine Instanz der Struktur intialisiert und Daten eingefügt bzw. entfernt ?
– Wie wird in den Strukturen navigiert ?– Wie werden einzelne Werte in einer Struktur wiedergefunden ?
– Wie werden alle in einer Struktur abgelegten Werte besucht ?
527
Eigenschaften von Referenzen:
Geld betrag;
if (betrag != null)
betrag.Drucke();
else
betrag = new Geld(10, 25);
Geld preis;
preis = new Geld(48, 98);
preis = null ;
Zugriff über Referenzen
Variable betrag: Referenz auf Objekt der Klasse Geld
Soll eine Referenz auf kein Objekt verweisen, wird der Wertnull zugewiesen
Überprüfung der Referenz mittels Vergleichsoperator
Der Wert null für Referenzen ermöglicht ein Objekt explizit voneiner Referenz zu lösen
Referenz preis verweist auf Objekt der Klasse Geld
Zuweisung auf null vernichtet Verweis auf Objekt mit Werten 48und 98
528
Dynamische Datenstrukturen
Grundlage für den Aufbau dynamischer Datenstrukturen
• Klassen enthalten Attribute, die Referenzen auf Objekte dereigenen Klasse darstellen.
• Diese Attribute schaffen die Möglichkeit, an eine Referenz einweiteres Objekt der Klasse zu binden.
• Die einzelnen Objekte sind in der Lage, gemeinsam einekomplexe Struktur durch aufeinander verweisende Referenzenzu bilden.
Kapitel 17.1
Listen
530
Allgemeines zu Listen• Listen definieren eine Reihenfolge von Elementen, die gemäß dieser
Reihenfolge miteinander verknüpft sind.• Typische Zugriffsmethoden:
– Einfügen am Anfang– Einfügen an bestimmter Stelle
– Anfügen (d.h. Einfügen am Ende)– Ermittlung der Länge– Prüfen auf Leere
– Prüfen, ob Element in Liste vorkommt– Ermittlung der Position eines Elements– Ermittlung des ersten Elements
– Liefern der Liste ohne erstes Element
• Die Verfügbarkeit aller dieser Methoden variiert mit demAnwendungszweck. Nicht immer sind alle Methoden realisiert, aberman redet dennoch von Listen
531
Bestandteile einer Listeclass Element {
Element(int i) { wert = i; weiter = null; }
private int wert;
private Element weiter;
}
• Deklaration einer Klasse Element mit zwei privaten Attributen undeinem Konstruktor
• Ein Objekt vom Typ Element enthält als Attribute eine ganze Zahlund einen Zeiger auf ein weiteres Objekt des Typs Element
• Jedes Objekt vom Typ Element besitzt eine Referenz auf einweiteres Element, man kann sie miteinander verketten
• Die daraus entstehende Datenstruktur ist eine Lineare Liste
532
class Liste {private Element kopf;
Liste() { kopf = null; }Liste(int w) { kopf = new Element(w); }
void FügeAn(int an) {
...
}void FügeEin(int ein) {
...
}
Schema der Klasse lineare Liste
533
Erweiterung einer Liste
Eine lineare Liste kann auf verschiedene Artenkonstruiert werden :
• neues Element an den Anfang, in die Mitte oder an das Endeeiner bereits bestehenden Liste anhängen
• Zugriff auf die Liste wird durch eine Referenz realisiert, die aufdas erste Element der Liste zeigt
• Enthält eine Liste keine Elemente, zeigt die Referenz auf null
• Besuchen eines Elements innerhalb der Liste erfordert eineReferenz von Element zu Element
534
void FügeAn(int neuerWert) {
Element lauf = this;
while (lauf.weiter != null)
lauf = lauf.weiter;
lauf.weiter = new Element(neuerWert);
}
• Die Klasse Element wird um die Methode FügeAn ergänzt, die ein neuesElement an das Ende einer Liste anhängt, die bereits aus wenigstens einemElement besteht.
• Die Liste wird durch die lokale Referenz lauf von Element zu Elementdurchlaufen, bis die Referenz weiter auf null verweist.
• Nun wird auf das neu erzeugte Objekt der Klasse Element verwiesen.• Die Referenz this verweist immer auf das Objekt, für welches die Methode
FügeEin aufgerufen wurde, daher verweist this nie auf den Wert null .
Programm: Einfügen am Ende einerlinearen Liste
Erweiterung einer Liste
535
Initiales Anlegen einer linearen Liste
Anlegen einer linearen Liste:• Mit dem Konstruktor von Element wird ein erstes Objekt geschaffen.• Alle weiteren Listenelemente werden durch FügeAn für das erste Element
angefügt.
Element kopf;
kopf = new Element(25);
kopf.FügeAn(22);
kopf.FügeAn(28);
• Die Methode FügeAn wird für das erste Element der Liste aufgerufen.• Jetzt wird mit lauf die gesamte Liste bearbeitet.
kopf null2825 22
536
Rekursives AnfügenRekursives Vorgehen:
void RekFügeAn(int neuerWert) {
if (weiter != null)
weiter.RekFügeAn(neuerWert);
else
weiter = new Element(neuerWert);
}
Beachte:Die Ausführung der Methode RekFügeAn ist aufwendiger, als die bishervorgestellten Methoden, da alle Aufrufe von RekFügeAn ineinandergeschaltet sind und erst dann beendet werden, wenn das neue Elementangefügt ist.
Programm: Einfügen auf der Basis einesrekursiven Vorgehens
537
Konstruktion einer Liste durch weiteres Anfügen
void FügeEin(int neuerWert) {
Element neuesElement = new Element(wert);
neuesElement.weiter = weiter;
weiter = neuesElement;
wert = neuerWert;
}
kopf.FügeEin(17) wird nun auf die Liste
angewendet
Programm: Methode FügeEin
kopf null2825 22
538
Konstruktion einer Liste durch Einfügen
kopf null2825 22
kopf null25 25 22 28
kopf null25 282217
17
zuweisen mit Konstruktor
zuweisen
Alles andere würde bedeuten, daß kopf umgesetzt wird.
Das aber würde bedeuten, daß ein Element den Zugriff auf sich abtritt.
Das geht nicht, also bleibt nur der Weg über das Einfügen an
der zunächst zweiten Stelle.
539
Klasse lineare ListeUmsetzen von linearen Listen mit der Klasse Element und den
Methoden FügeAn und FügeEin :
Aufbau einer Liste aus einer „leeren“ Liste:Da die Methoden FügeAn und FügeEin Bestandteile der Objekte derKlasse Element sind, können sie nur dann aufgerufen werden, wenn auchein solches Element besteht. Daher muß das erste Element einer Listeimmer über einen Konstruktor erzeugt werden, alle weiteren können dannüber die Methoden hinzugefügt werden. Innerhalb eines Programms mußdaher vor jedem Aufruf von FügeAn oder FügeEin überprüft werden, obdie Referenz auf die Liste auf null verweist. Übersichtlicher wäre eshingegen, in allen Situationen Elemente durch dieMethoden FügeAn und FügeEin hinzufügen zu können.
540
Änderung des ersten Elementes:Die Implementierung der Methode FügeEin hat gezeigt, daß dasHinzufügen eines neuen Objektes als erstes Element der Liste nichtmöglich ist; hierfür muß auf entsprechende Zuweisungen zurückgegriffenwerden. Ebenso problematisch ist das Löschen des ersten Elementes einerListe. Insbesondere das letzte Element einer Liste läßt sich nicht durch eineMethode der Klasse Element entfernen.
Klasse lineare Liste
541
Effizienz der Methode FügeAn:
Die Methode FügeAn erfordert bei jedem Aufruf ein vollständigesDurchlaufen der Liste. Eine sehr viel effizientere Realisierung dieserListenoperation wäre möglich, wenn neben dem ersten Element auch dasletzte Element der Liste unmittelbar erreichbar wäre.
Klasse lineare Liste
542
Verbesserungsmöglichkeiten
• Die Idee, eine Liste mit einer Referenz auf ihr erstes Elementgleichzusetzen, wird dem Umgang mit der entstehendenDatenstruktur nicht gerecht.
• Der Wertebereich einer Klasse, die lineare Listenimplementiert, sollte auch die leere Liste beinhalten und fürdiese eine korrekte Anwendung der Methoden garantieren.
• Die Ausführung von Methoden sollte durch zusätzlicheReferenzen auf ausgewählte Elemente der Liste unterstütztwerden.
• Als Ergebnis entstehen die folgenden, modifizierten KlassenElement und Liste
543
class Element {private int wert;private Element weiter;Element(int i) { wert = i; weiter = null; }Element(int i, Element e) { wert = i; weiter = e; }void SetzeWert(int i) {
wert = i;
}int GibWert() {
return wert;
}void SetzeWeiter(Element e) {
weiter = e;
}Element GibWeiter() {
return weiter;
}}
Klasse Element (verbessert)
544
class Liste {private Element kopf, fuß;Liste() { kopf = fuß = null; }Liste(int w) { kopf = fuß = new Element(w); }void FügeAn(int an) {
Element neu = new Element(an);
if (fuß != null) {
fuß.SetzeWeiter(neu);
fuß = neu;
}
else
kopf = fuß = neu;
}void FügeEin(int ein) {
kopf = new Element(ein, kopf);
if (fuß == null)
fuß = kopf;
}}
Klasse lineare Liste (verbessert)
545
Beispiel Anfügen und Einfügen
Liste eineListe = new Liste();
eineListe.FügeAn(15);
eineListe.FügeAn(52);
eineListe.FügeEin(34)
kopf null fuß
fußnull15kopf
15kopf fußnull52
546
Liste eineListe = new Liste();
eineListe.FügeAn(15);
eineListe.FügeAn(52);
eineListe.FügeEin(34) ein 34
15kopffußnull52
ein 34
15kopffußnull52
ein 34
15kopf fußnull52
Beispiel Anfügen und Einfügen
547
Anwendungsbeispiel
• Einordnen eines Werts in eine bereits aufsteigend geordnete Liste• Keine zwei Elemente haben die identische Belegung des Attributs wert
• Der Algorithmus ist auf natürliche Weise rekursiv
Die Idee:Ist eine ganze Zahl x gegeben, so daß x kleiner als das erste Element der Liste ist,so füge man x am Anfang der Liste ein. Muß x in der Mitte der Liste eingefügtwerden, so suche man die entsprechende Position, spalte dort die Liste in einenAnfangs- und einen Endteil auf und füge x am Anfang des Listenrestes ein.Schließlich verbinde man das Ende des Anfangsteils der Liste mit der soentstandenen neuen Liste. Ist x größer als das letzte Element der Liste, so bildetdas neue Element allein den neuen Rest: x wird angefügt.
548
Präzisierung des Algorithmus:Folgende Fälle sind zu unterscheiden:
• kopf == null:
Einen Sonderfall bildet die Situation, daß die Liste leer ist, also noch kein Elemententhält. Es muß ein erstes Element angelegt werden, das sicherlich eine geordnete,einelementige Liste bildet.
• kopf != null:
Wir definieren eine private Methode Positioniere , die als Parameter deneinzuordnenden Wert und eine Referenz auf den Anfang einer Teilliste übergebenbekommt. Als Ergebnis gibt Positioniere eine Referenz auf Element zurück, dieauf die Teilliste verweist, in die x einsortiert ist.
Anwendungsbeispiel
549
Sei anfang die an Positioniere übergebene Teilliste und gelte:
• x < anfang.wert:
Erzeuge ein neues Element und füge es am Anfang der bei anfang
beginnenden Teilliste ein.
• x > anfang.wert:
Füge x in die mit anfang.weiter beginnenden Restliste ein, indemhierfür Positioniere mit den entsprechenden Parametern erneut
aufgerufen wird.
Anwendungsbeispiel
550
Beachte:
• Keine doppelten Einträge werden zugelassen.• Die Referenz fuß verweist auch nach dem Einsortieren auf das
letzte Element.• Wenn Positioniere die leere Referenz null als Wert für den
Parameter anfang übergeben bekommt, muß fuß korrigiertwerden und auf das neu eingeordnete letzte Objekt gesetztwerden.
Anwendungsbeispiel
551
Einordnen mit Hilfe von Positioniere
class Liste {private Element kopf, fuß;Liste() { kopf = fuß = null; }Liste(int w) { kopf = fuß = new Element(w); }…void OrdneEin(int i) {
kopf = Positioniere(kopf, i);}
Programm: Einordnen in eine geordnete Liste
552
Einordnen mit Hilfe von Positioniere
private Element Positioniere(Element anfang, int i) {if (anfang == null)
fuß = anfang = new Element(i);else {
if (i < anfang.GibWert()) {anfang = new Element(i, anfang);
}if (i > anfang.GibWert())
anfang.SetzeWeiter(Positioniere(anfang.GibWeiter(), i));
}
return anfang;}…
}
Programm: Einordnen in eine geordnete Liste
553
Durchlaufen einer Struktur
Programm: Rekursive Methode zum Druckeneiner verketten Liste
• In vielen Anwendungen, die auf dynamischen Datenstrukturenbasieren, besteht die Notwendigkeit, alle Elemente der Strukturgenau einmal zu besuchen. Dies gilt für Listen wie für anderedynamische Strukturen.
• Dieses möglichst nur einmalige Besuchen aller Elemente nenntman Durchlaufen einer Struktur.
• Anwendungsbeispiele: Prüfen auf Vorhandensein, Einsortieren• Konkrete Ausprägungen dieses Problems spielen in der
theoretischen Informatik eine wichtige Rolle (TravellingSalesman Problem).
554
Durchlaufen einer Listeclass Liste {
…
void RekDrucke() {
RekDrucke(kopf);
}
private void RekDrucke(Element aktuell) {
if (aktuell != null) {
System.out.println(aktuell.GibWert());
RekDrucke(aktuell.GibWeiter());
}
}
…
} Programm: Rekursive Methode zum Druckeneiner linearen Liste
555
void IterDrucke() {
Element aktuell = kopf;
while (aktuell != null) {
System.out.println(aktuell.GibWert());
aktuell = aktuell.GibWeiter();
}
}
Programm: Iterative Methode zum Druckeneiner linearen Liste
Durchlaufen einer Liste
556
Durchlauf einer Liste in umgekehrter Reihenfolge:
• Referenz fuß verweist zwar auf das letzte Element einer Liste,kann jedoch nicht von dort zum vorletzten Element gelangen.
• Für eine umgekehrte Ausgabe müssen alle Listenelementegemerkt werden, während die Liste vom Anfang zum Endedurchläuft.
• Erst nach einmaligem Durchlaufen kann vom letzten bis zumersten Element gedruckt werden.
Durchlaufen einer Liste
557
void ReversivDrucke() {
ReversivDrucke(kopf);
}
private void ReversivDrucke(Element aktuell) {
if (aktuell != null) {
ReversivDrucke(aktuell.GibWeiter());
System.out.println(aktuell.GibWert());
}
}Programm: Ausgabe einer Liste in umgekehrter
Reihenfolge
Durchlaufen einer Liste
558
Doppelt verkettete Listen
• Ist der Durchlauf vom Ende einer Liste zu ihrem Anfang häufigbenötigt, dann ist die lineare Verkettung von vorne nach hintennicht der ideale Navigationspfad.
• Besser wäre es dann auch eine Rückwärtsverkettung zuhaben.
• Auf Grund dieser Überlegung kommt man zu doppeltverketteten Liste (einmal von vorne nach hinten, einmalumgekehrt).
559
Doppelt verkettete Listen
• Die lokale Klasse Element enthält eine zweite Referenz voran ,die genau entgegengesetzt zu weiter gerichtetist und somit für jedes Element innerhalb der Liste auf seinendirekten Vorgänger verweist.
• Mit doppelt verketteten Listen kann in beide Richtungen einerListe navigiert werden und deshalb komplexe Operationen aufeiner Liste unterstützen.
• In Java: LinkedList (Unterklasse vonAbstractSequentialList in java.util)
560
class DElement {… // die bekannten Deklarationen der linearen Listeprivate DElement voran, weiter;void SetzeVoran(DElement e) { voran = e; }Element GibVoran() { return voran; }
}class DListe {
… // die bekannten Deklarationen der linearen Listevoid FügeAn(int an) {
DElement neu;neu = new DElement(an);if (fuß != null) {
fuß.SetzeWeiter(neu);neu.SetzeVoran(fuß);fuß = neu;
} elsekopf = fuß = neu;
}void OrdneEin(int i) {
kopf = Positioniere(kopf, i);}
Doppelt verkettete Listen
561
private DElement Positioniere(DElement anfang, int i) {if (anfang == null)
anfang = new DElement(i);anfang.SetzeVoran(fuß);fuß = anfang;
else {if (i < anfang.GibWert()) {
DElement neu = new DElement(i, anfang);
neu.SetzeVoran(anfang.GibVoran());anfang.SetzeVoran(neu);if (neu.GibVoran != null)
neu.GibVoran().SetzeWeiter(neu);anfang = neu;
}if (i > anfang.GibWert())
anfang.SetzeWeiter(Positioniere(anfang.GibWeiter(), i));
}
return anfang;}
Doppelt verkettete Listen
562
void ReversivDrucke() {
DElement aktuell = fuß;
while (aktuell != null) {
System.out.println(aktuell.GibWert());
aktuell = aktuell.GibVoran();
}
}
}
Doppelt verkettete Listen
563
Exkurs: java.util - Hilfsklassen
Umfaßt Interfaces und Klassen, um unterschiedlicheDatenstrukturen zu realisieren, insbesondere:
• Interfaces:– Enumeration für Objekte, die mehrere Elemente generieren– Set für Mengen ohne doppelte Elemente
• Klassen:– Vector : Mehr Flexibilität als [] -Arrays– Stack : Stapel für allgemeine Objekte, abgeleitet von Vector
– LinkedList: für doppelt verkettete Listen– StringTokenizer : Einfaches Zerlegen von Strings– Random: Zufallsgenerator
(für Kryptographie: java.security.SecureRandom )
– Verschiedene Kalender und Datumsklassen564
java.util.Vector
• Klasse java.util.Vector– public Object[] toArray()
• Wandelt Vector in ein Array vom Basistyp Object
– public int size()• Gibt Anzahl der enthaltenen Komponenten zurück
– public boolean contains(Object elem)• Prüft, ob ein Objekt enthalten ist. Gleichheit wird mit equals() überprüft.
– public int indexOf(Object elem)• Gibt Index eines Objektes zurück. Gleichheit wird mit equals() überprüft.
– public Object elementAt(int index)• Gibt Element an entsprechender Position zurück
– public void insertElementAt(Object obj, int index)
– public void removeElementAt(int index)• Fügt Objekt an Position ein, bzw. entfernt Objekt
565
• Zugriff auf Elemente mit einem Index (analog zu Arrays)
• Abarbeiten der Liste mit einem Enumeration - Objekt
public interface Enumeration {
// liefert true, falls noch Elemente vorhanden sind
public abstract boolean hasMoreElements();
// liefert das nächste Objekt der Aufzählung
public abstract Object nextElement();
}
java.util.Vector
566
• Methode elements() von Vector liefert ein Enumeration -Objekt
Vector v = new Vector();
Person p1 = new Person( “ Urs“, “ Müller“, “ Hauptstr. 1“, “ 12345“, “ Berlin“);
Person p2 = new Person( “ Max“, “ Muster“, “ Südwall 1“, “ 44332“,“Dortmund“);
v.addElement(p1);
v.addElement(p2);
for (Enumeration el = v.elements(); el.hasMoreElements(); ) {
Person p = (Person) el.nextElement();
String inhaber = p.toString();
Bildschirm.gibAus(inhaber);
}Explizites Typcasting durchvorangestellte runde Klammern:
Person p = (Person) el.nextElement();
Das Interface Enumeration
567
• add (int index, Object element)• addFirst (Object element)• addLast (Object element)• get (int index)• remove (int index)• remove (Object o) löscht das erste Auftreten des Elementes o• getFirst()• getLast()• size() gibt die Anzahl der Elemente zurück
Methoden der Klasse LinkedList
Kapitel 17.2
Bäume
569
• Bäume sind hierarchische Strukturen. Man kommt von einerWurzel zu inneren Knoten und letztlich zu Blättern.
• Es gibt keine Zyklen zwischen Mengen von Knoten.• Bäume sind damit auch verkettete Strukturen, die dynamisch
wachsen und schrumpfen können.• Binäre Bäume sind Bäume, in denen jeder Knoten maximal
zwei Söhne hat (zur Definition siehe vorne).• Ein Beispiel für die nützliche Anwendung binärer Bäume ist
das Heapsort von weiter vorne.• Eine andere Anwendung binärer Bäume sind die binären
Suchbäume.
Allgemeines zu Bäumen
570
• Typische Zugriffsmethoden– einfügen einer Wurzel– einfügen eines inneren Knotens– entfernen der Wurzel– entfernen eines inneren Knotens– suchen– nach links/rechts navigieren
Allgemeines zu Bäumen
571
Binäre Suchbäume
Die Grundidee
Ein vorgelegtes Element x wird in einer geordneten Mengegesucht, es wird rekursiv vorgegangen.
Man beschaffe sich das mittlere Element der geordneten Menge undvergleiche es mit dem vorgelegten Element x. Stimmt das mittlere Elementmit x überein, so ist man fertig; ist x kleiner, so wende man diese Idee aufalle Elemente an, die kleiner als das mittlere Element sind; ist x größer,wende man die Idee auf alle Elemente an, die größer als das mittlereElement sind. So kommt man durch fortgesetztes Halbieren sehr schnell zuder Entscheidung, ob x in der vorgegebenen Menge liegt oder nicht.
572
Definition:Sei B ein binärer Baum, dessen Knoten mit ganzen Zahlenbeschriftet sind. B heißt binärer Suchbaum, falls gilt:
B ist leer oder
– der linke und der rechte Unterbaum von B sind binäre Suchbäume,– ist w die Beschriftung der Wurzel, so sind alle Elemente im linken
Unterbaum kleiner als w, alle Elemente im rechten Unterbaum größerals w.
Binäre Suchbäume
573
Beispiel für einen binären Suchbaum:
16
10
9 14
13 15
18
24
Binäre Suchbäume
574
• Der Aufbau eines binären Suchbaums erfolgt durchwiederholtes Einfügen in einen leeren Baum.
• Die Reihenfolge der Werte, die in einen binären Suchbaumeingefügt werden, bestimmt die Gestalt des Baumes.
• Eine Menge von Werten kann bei unterschiedlichenEingabereihenfolgen zu verschiedenen Repräsentationen alsBaum führen.
Binäre Suchbäume
575
Beispiele:
1
2
3
3
2
1
2
1 32
1
3
Eingabefolge 1 2 3
Eingabefolge 3 2 1
Eingabefolge 3 1 2Eingabefolge 2 1 3 oder 2 3 1
Binäre Suchbäume
576
class Knoten {
private int wert;
private Knoten links, rechts;
Knoten(int i) { wert = i; links = rechts = null; }
void SetzeWert(int i) { wert = i; }
int GibWert() { return wert; }
void SetzeLinks(Knoten k) { links = k; }
Knoten GibLinks() { return links; }
void SetzeRechts(Knoten k) { rechts = k; }
Knoten GibRechts() { return rechts; }
};
Binäre Suchbäume - die Klasse Knoten
577
Algorithmus für das Einfügen von Knoten
Gegeben seien ein binärer Suchbaum B und eine ganze Zahl k, die in Beingefügt werden soll. Es können vier Fälle auftreten:
• B ist leer: Erzeuge einen neuen Knoten, weise ihn B zu und setze B.wertauf k.
• B ist nicht leer und B.wert = k: Dann ist nichts zu tun, da keine doppeltenEinträge vorgenommen werden sollen.
• B ist nicht leer und B.wert < k: Füge k in den rechten Unterbaum von B ein.
• B ist nicht leer und B.wert > k: Füge k in den linken Unterbaum von B ein.
Binäre Suchbäume
578
class BST {
private Knoten wurzel;
BST() { wurzel = null; }
void FügeEin(int i) {
wurzel = FügeEin(wurzel, i);
}
Die Klasse Binary Search Tree (BST)
579
private Knoten FügeEin(Knoten aktuell, int ein) {
if (aktuell == null)
aktuell = new Knoten(ein);
else {
if (ein < aktuell.GibWert())
aktuell.SetzeLinks
(FügeEin(aktuell.GibLinks(), ein));
if (ein > aktuell.GibWert())
aktuell.SetzeRechts
(FügeEin(aktuell.GibRechts(), ein));
}
return aktuell;
}
}
Die Klasse Binary Search Tree (BST) - Einfügen
580
Algorithmus für die Suche von Konten
Der am Beginn dieses Kapitels skizzierte Algorithmus für das binäreSuchen läßt sich nun mit der durch die Methode FügeEin aufgebautenDatenstruktur recht einfach realisieren.
Gegeben sind ein binärer Suchbaum B und eine Zahl k,die in dem Baum B gesucht werden soll:
B ist leer: k kann nicht im Baum sein.B ist nicht leer, so betrachtet man die Fälle
B.wert = k : k ist gefunden, d.h. bereits in dem Baum B vorhanden.B.wert < k : Suche im rechten Unterbaum von B.B.wert > k : Suche im linken Unterbaum von B.
Binäre Suchbäume
581
class BST {...boolean Suche(int i) {
return Suche(wurzel, i);}private boolean Suche(Knoten aktuell, int i) {
boolean gefunden = false;if (aktuell != null) {
gefunden = (aktuell.GibWert() == i) ;if (aktuell.GibWert() < i)
gefunden = Suche(aktuell.GibRechts(), i);if (aktuell.GibWert() > i)
gefunden = Suche(aktuell.GibLinks(), i);}return gefunden;
}...
}
Die Klasse Binary Search Tree (BST) - Suchen
582
Suchen in binären Suchbäumen
Definition:
Ist B ein binärer Baum, so definiert man die Höhe h(B) von B rekursiv durch:
h(B):={
Ist B ein binärer Suchbaum mit h(B)=n, so enthält B mindestens n und höchstens2n-1 Knoten, nämlich n, wenn der Baum zur Liste degeneriert ist, und 2n-1, wennjeder von 2n-1-1 inneren Knoten genau zwei Söhne und jedes von 2n-1 Blätternkeine Söhne hat.
0, falls B leer ist1 + max {h(B1), h(B2)}, falls B1 und B2 linker bzw.
rechter Unterbaum von B sind
583
Behauptung : In einem beliebigen binären Suchbaum B, braucht man für eineerfolglose Suche maximal h(B) Vergleiche
Beweis : durch vollständige Induktion nach dem Aufbau von B.
Induktionsanfang : Ist B leer, also h(B)=0, so ist kein Vergleich nötig.
Induktionsschritt : Wenn für zwei Bäume B1 und B2 mit der Höhe n gilt,daß in jedem eine erfolglose Suche in maximal n Vergleichen möglich ist,so gilt für den binären Suchbaum mit einer neuen Wurzel und derenUnterbäume B1, B2, dass maximal n+1 Vergleiche nötig sind.Beweis des Induktionsschrittes : Durch Wurzelvergleich (ein Vergleich)wird ermittelt, ob im linken oder rechten Teilbaum weitergesucht werdenmuß. Die maximale Zahl der Vergleiche in einem Teilbaum ist n. Also,braucht man insgesamt maximal n+1 Vergleiche. In einem Baum der Höhen+1 braucht man also maximal n+1 Vergleiche.
Suchen in binären Suchbäumen
584
Daraus ergibt sich:
Bei einer erfolglosen Suche in einem binären Suchbaum mit n Elementensind mindestens log n (Basis 2) und höchstens n Vergleiche notwendig.
Der günstige Fall (log n Vergleiche) gilt in einem minimal ungleichgewichtigenBaum. Der ungünstige (n Vergleiche) gilt in einem vollständig degeneriertenBaum, der beispielsweise immer dann entsteht, wenn die Elemente insortierter Reihenfolge eintreffen.
Um diese Unsicherheit auszuräumen (und somit eine Laufzeit auf der Basisvon log n Vergleichen sicherzustellen), werden balancierte, binäreSuchbäume benutzt.
Suchen in binären Suchbäumen
585
Eine Art balancierter, binärer Suchbäume sind die AVL-Bäume (nach ihrenErfindern Adelson, Velskii, Landis).
Def.: Ein AVL-Baum ist ein binärer Suchbaum, in dem sich für jeden Knotendie Höhen seiner zwei Teilbäume um höchstens 1 unterscheiden.
Einfüge- und Entferne-Operationen werden dann etwas aufwendiger, aberdafür ist die Suche auch in ungünstigen Fällen effizienter (mehr dazu in derVorlesung Datenstrukturen).
Suchen in binären Suchbäumen
586
Schema der vollständigen Induktion über Bäumen
• Spezifikation der Behauptung S(T), wobei T ein Baum ist.• Beweis, daß S(T) gilt für Bäume, die nur einen Knoten haben.
• Aufsetzen des Induktionsannahme, T ist ein Baum mit Wurzel w und k ≥1Unterbäume, T1, ..., Tk. Annahme, daß S(Ti) gilt für i ∈ 1,2, ..., k
• Beweis, daß S(T) unter der Induktionsannahme gilt.
587
Entfernen der Wurzel aus einem binären Suchbaum
Algorithmus für das Entfernen
• Entfernen der Wurzel führt zur Konstruktion eines neuen binärenSuchbaums.
• Darum: Finden eines Knotens, der an die Stelle der Wurzel gesetzt wird unddie Kriterien für einen neuen binären Suchbaum erfüllt.
• Der Knoten muß größer als die Wurzel des linken Unterbaumes sein undkleiner als die Wurzel des rechten Unterbaumes.
588
16
10
9 14
13 15
18
24
Kandidaten
15
10
9 14
13
18
24
Situation vor dem Löschen Situation nach dem Löschen
Entfernen der Wurzel - Beispiel
589
Algorithmus für das Entfernen
• Es wird der Knoten mit der größten Beschriftung im linken Unterbaumgenommen.
• Dieser Knoten wird entfernt und als Wurzel eingesetzt.• Ist der linke Unterbaum einer Wurzel leer, nimmt man analog zur
vorgestellten Methode das kleinste Element der rechten Wurzel.• Ist der Unterbaum einer Wurzel leer, kann auch auf eine Umgestaltung
des Baumes verzichtet werden: Wird die Wurzel entfernt, bildet derverbleibende Unterbaum wieder einen binären Baum.
Entfernen der Wurzel aus einem binären Suchbaum
590
Wird ein innerer Knoten aus einem binären Suchbaum entfernt,stellt dieser Knoten die Wurzel eines Unterbaumes dar unddiese Wurzel wird dann entfernt.
Entfernen eines Knotens aus einem binären Suchbaum
591
Durchlaufstrategien für binäre Suchbäume
• Tiefendurchlauf : Hier wird von einem Knoten aus in die Tiefegegangen, indem einer der Söhne besucht wird und danndessen Söhne usw. Erst wenn man die Blätter erreicht hat,beginnt der Wiederaufstieg.– Preorder-Durchlauf– Inorder-Durchlauf– Postorder-Durchlauf
• Breitendurchlauf : Mit dem Besuch eines Knotens werdenauch seine Nachbarn besucht.„Schichtweises Abtragen“
592
Dynamische Datenstrukturen Binäre Suchbäume
Tiefendurchlauf / Preorder
void PreOrder() {PreOrder(wurzel); }
private void PreOrder(Knoten aktuell) {
if (aktuell != null) {
System.out.println(aktuell.GibWert());
PreOrder(aktuell.GibLinks());
PreOrder(aktuell.GibRechts());
}
}
16
10
9 14
13 15
18
24
Reihenfolge der besuchten Knoten: 16, 10, 9, 14, 13, 15, 24, 18
593
Tiefendurchlauf / Inorder
void InOrder() { InOrder(wurzel); }
private void InOrder(Knoten aktuell) {
if (aktuell != null) {
InOrder(aktuell.GibLinks());
System.out.println(aktuell.GibWert());
InOrder(aktuell.GibRechts());
}
}
16
10
9 14
13 15
18
24
Reihenfolge der besuchten Knoten: 9, 10, 13, 14, 15, 16, 18, 24594
void PostOrder() { PostOrder(wurzel); }
private void PostOrder(Knoten aktuell) {
if (aktuell != null) {
PostOrder(aktuell.GibLinks());
PostOrder(aktuell.GibRechts());
System.out.println(aktuell.GibWert());
}
}
16
10
9 14
13 15
18
24
Reihenfolge der besuchten Knoten:
9, 13, 15, 14, 10, 18, 24, 16
Tiefendurchlauf / Postorder
595
16
10
9 14
13 15
18
24
Reihenfolge der besuchten Knoten: 16, 10, 24, 9, 14, 18, 13, 15
Breitendurchlauf
596
• Noch nicht besuchte Knoten werden in einer verketteten Listegespeichert, so daß der Knoten, der als nächster besucht wird,am Anfang der Liste steht.
• Wird ein Knoten besucht, so wird er aus der Liste entfernt und sein linkerund sein rechter Sohn werden, falls vorhanden, in dieser Reihenfolge ansEnde der Liste angefügt.
• Dies geschieht solange, bis die Liste leer ist.• Die Liste wird mit der Wurzel des Baumes initialisiert.• Insgesamt wird also durch die Liste eine Warteschlange von Knoten
aufgebaut:Der Knoten am Anfang der Warteschlange wird als nächsterausgedruckt.Der Knoten am Ende der Warteschlange ist als
letzter hinzugefügt worden.
Idee zur Realisierung des Breitendurchlaufs
597
Dynamische Datenstrukturen Binäre Suchbäume
Warteschlange für die Breitensuche16
10
9 14
13 15
18
24
ws null
ws null
16
10
9 15
13 14
18
24
nach Besuch des Knotens16, vor Besuch des Knotens10
nach Besuch des Knotens 10
598
Breitendurchlauf durch einen binären Suchbaumclass BST {
...
void Breitendurchlauf() {
SohnListe ws = new SohnListe();
Knoten aktuell;
ws.FügeAn(wurzel);
while ((aktuell = ws.Entferne()) != null) {
System.out.println(aktuell.GibWert());
if (aktuell.GibLinks() != null)
ws.FügeAn(aktuell.GibLinks());
if (aktuell.GibRechts() != null)
ws.FügeAn(aktuell.GibRechts());
}
}
...
}
599
Die Klasse SohnElem
class SohnElem {
private Knoten wert;
private SohnElem weiter;
SohnElem(Knoten k) { wert = k; weiter = null; }
void SetzeWert(Knoten k) { wert = k; }
Knoten GibWert() { return wert; }
void SetzeWeiter(SohnElem s) { weiter = s; }
SohnElem GibWeiter() { return weiter; }
}
600
class SohnListe {
private SohnElem kopf, fuß;
SohnListe() { kopf = fuß = null; }
void FügeAn(Knoten an) {
SohnElem neu = new SohnElem(an);
if (fuß != null) {
fuß.SetzeWeiter(neu);
fuß = neu;
} else
kopf = fuß = neu;
}
Die Klasse SohnListe
601
Knoten Entferne() {
Knoten erster = null;
if (kopf != null) {
erster = kopf.GibWert();
kopf = kopf.GibWeiter();
if (kopf == null)
fuß = null;
}
return erster;
}
}
Die Klasse SohnListe
Kapitel 17.3
Graphen
603
Allgemeines zu Graphen
Programm: Die Klasse SohnListe
• Listen stellen eindimensionale Verkettungen von Informationendar: Jeder Knoten einer Liste hat einen oder keinen Nach-folger.
• Binäre Bäume stellen eine zweidimdensionale Informations-verkettung dar: Jeder Knoten ist mit höchstens zwei Söhnenverbunden.
• Graphen stellen für jeden Knoten dar, in welcher Weise diesermit anderen Knoten gerichtet verbunden ist.
604
• Eine der originären Anwendungen ist die Darstellungräumlicher Beziehungen, Bäume reichen hier nicht aus, weil esBeziehungen zwischen allen Knoten geben kann.
• Oft ist es so, daß den Kanten zwischen zwei Knoten auch nochAttribute zugeordnet werden (Kosten, Entfernungen, etc.).
• Wenn die Beziehung zwischen zwei Knoten unabhängig vonder Richtung ist (Erreichbarkeit zwischen Orten), dann reichenungerichtete Kanten.
• Wenn die Beziehung von der Richtung abhängt (eine Stellungim Schach läßt sich per Zug aus einer anderen erreichen),dann braucht man gerichtete Kanten.
Allgemeines zu Graphen
605
Allgemeines zu Graphen
Typische Methoden:
• das Erzeugen eines neuen Graphen• das Einfügen oder Löschen eines Knotens• das Einfügen oder Löschen einer Kante• den Test, ob ein Knoten vorhanden ist• den Test, ob eine Kante vorhanden ist
606
Programm: Die Klasse SohnListe
G = (V, E) heißt gerichteter Graph mitKnotenmenge V und Kantenmenge E, falls gilt:
V (englisch: vertex, vertices) ist eine endlicheMenge und
E (englisch: edges) ⊆ V × V
Definition Graph
607
2
1
3
8
9
7
4
6
5
Beispiel eines gerichteten Graphen
608
Sei G = (V, E) ein gerichteter Graph, so besteht ein Pfad ausKnoten (p0, p1,…, pk) von p0 nach pk für k > 0 aus Knotenp0, … , pk ∈ V, so daß jedes Paar aufeinanderfolgender
Knoten (pi, pi+1) eine Kante bildet. Dies gilt für 0 ≤ i ≤ k-1.
Ein Zyklus ist ein Pfad von einem Knoten zu sich selbst.
Definition Pfad
609
Ein gerichteter Graph heißt stark zusammenhängend , wennes zwischen je zwei Knoten des Graphen einen Pfad gibt.
Ein gerichteter Graph heißt schwach zusammenhängend ,wenn es zwischen zwei Knoten immer einen Semiweg gibt.Ein Semiweg ist ein Pfad, wobei von der Richtung der Kantenabgesehen wird.
Definition Zusammenhang
610
Ein Teilgraph heißt Zusammenhangskomponente , wenn erbzgl. der Zusammenhangseigenschaft (stark oder schwach)maximal ist, d.h. der Teilgraph kann nicht durch einen odermehrere Knoten und/oder eine oder mehrere Kanten desGraphen erweitert werden, ohne diese Eigenschaft zuverlieren.
Definition Zusammenhang
611
Graphen werden rechnerintern durch Adjazenzlisten oderAdjazenzmatrizen dargestellt werden.
Speicherdarstellung von Graphen
612
Ist n ∈ V ein Knoten im gerichteten Graphen (V, E), so heißt{p ∈ V; (n, p) ∈ E}die Adjazenzliste zum Knoten n.
Eine Alternative zu dieser Darstellung ist die Darstellungüber Boolesche Matrizen:Man definiere eine Matrix (ak,l)k,l ∈∈∈∈ V und setze:
ak,l :=((k,l) ∈ E)
Adjazenz von Knoten
613
Knoten Adjazenzliste
1 5
2 1, 3
3 (leer)
4 2, 8
5 2, 3, 7, 8
6
7 (leer)
8 7
9 6
2
1
3
8
9
7
4
6
5
Beispiel Adjazenzliste
614
2
1
3
8
9
7
4
6
5
Adjazenzmatrix
Beispiel Adjazenzmatrix
615
Der Platzverbrauch von Adjazenzmatrizen ist unabhängig vonder Zahl der Kanten pro Knoten. Bei n Knoten werden n2
Speicherplätze gebraucht.
In Adjazenzmaztrizen läßt sich schnell prüfen, ob eine Kantevorhanden ist (indizierter Zugriff auf zweidimensionales Array).
Adjazenzlisten brauchen Speicherplatz pro Kante. Wenn wenigKanten vorkommen, dann wird auch wenig Platz gebraucht.Bei vielen Kanten muß man beim Suchen nach einer Kanteerst eine ggf. lange Kantenliste durchlaufen.
Adjazenz von Knoten
616
Deshalb folgende Daumenregel:
Adjazenzlisten sind für Graphen mit wenig Kanten pro Knotengeeignet.
Adjazenzmatrizen sind für dichte Graphen geeignet.
Adjazenz von Knoten
617
Klassen Knoten, ..., Graph
class Graph {private Knoten erster;…
}
class Knoten {private int name;private KnotenListeadjazenz;private Knoten nächster;…
}
class KnotenListe {private KnotenElem kopf,fuß;…
}
class KnotenElem {Knoten verweis;KnotenElem weiter;…
}
618
Listendarstellung gerichteter Graphen
2
16
4
7
9
8
5
3
erster
619
Realisierung der Graph-Methoden
• Das Erzeugen eines neuen Graphen erfolgt durch den Aufrufeine Konstruktors.
• Das Hinzufügen eines Knotens ist eine Listenoperation auf derListe der Knoten.
• Das Entfernen eines Knotens ist eine Listenoperation auf derListe der Knoten und auf all den Adjazenzlisten, die einenZeiger auf den zu entfernenden Knoten besitzen.– Aufwand!
620
Realisierung der Graph-Methoden
• Das Hinzufügen einer Kante ist eine Operation auf denAdjazenzlisten.
• Der Test, ob ein Knoten vorhanden ist, stellt eine Operation aufder Liste aller Knoten dar.
• Der Test, ob eine Kante vorhanden ist, stellt zunächst eineOperation auf der Liste aller Knoten - Ausgangsknoten derKante finden - und anschließend auf der entsprechendenAdjazenzliste dar.
621
Die Klasse Graph
class Graph {
private Knoten erster;
void Graph( ) { … }
void FügeKnotenEin(int kno ) { … }
void EntferneKnoten(int kno ) { … }
void FügeKanteEin(int start, int ende ) { … }
boolean IstKnotenDa(int kno ) { … }
boolean IstKanteDa(int kno1, int kno2 ) { … }
}
622
Durchlaufen mit einmaligem Besuchen
• Ausdrucken aller Knotennamen• Da Graphen keine vergleichbar reguläre Struktur haben wie
Bäume kann man keine vergleichbaren Durchlaufstrategienangeben. Durch Zyklen kann man beispielsweise auf bereitsbesuchte Knoten kommen.
• Die Klasse Knoten wird deshalb erweitert um ein AttributwarDa .
623
Ergänzung der Klasse Knoten
class Knoten {
private boolean warDa;
void SetzeWarDa(boolean wd) { warDa = wd; }
boolean GibWarDa() { return warDa; }
…
}
624
Durchlaufen mit einmaligem Besuchen
• Problem: Was passiert, wenn noch mal ausgedruckt werdensoll?
• Idee: Umdrehen der Werte.• Das Einfügen muß dann aber entsprechend arbeiten und die
Belegung der warDa-Attribute berücksichtigen.• Eine ganz einfache Ausgabestrategie wäre das Durchlaufen
der Knotenliste, allerdings verliert man dann jeden Aufschlussüber die Graphenstruktur.
• Deshalb wird oft ein so genannter Tiefendurchlauf benötigt.Hierdurch werden zusammenhängende Teilgraphen auchzusammenhängend ausgegeben.
625
Durchlaufen mit einmaligem Besuchen
• Erst wenn in einem Teilgraph alle Knoten besucht sind, wirdüber nächster der nächste Knoten aufgesucht.
• Wir versuchen von einem Knoten alle erreichbaren Knoten zufinden. Dabei steigen wir erst hinab und erst wieder hinauf(zum Vorgängerknoten), wenn nichts mehr gefunden wird.
• Beispiel:
626
Durchlaufen mit einmaligem Besuchen
• Das Durchlaufen der Adjazenzlisten wird durch den rekursivenAufruf von BesucheTeil für die in der Adjazenzlistevorkommenden Knoten unterbrochen.
• Die Methoden InitIteration und GeheWeiter sorgendafür, dass die Adjazenzliste dennoch nicht jedes Mal vonvorne durchlaufen werden muß.
627
Die Klasse KnotenListeclass KnotenListe {
…
private KnotenElem position = null;
Knoten InitIteration() {
position = kopf;
return position.Gibverweis();
}
Knoten GeheWeiter() {
position = (position != null?
Position.GibWeiter(): null);
return position.GibVerweis();
}
}
628
Tiefensuche in gerichteten Graphen
Programm: Die Tiefensuche in einemgerichteten Graphen (1/2)
class Graph {
…
void Durchlaufe() {
Knoten inListe;
boolean besucht = !erster.GibWarDa();
inListe = erster;
while (inListe != null) {
System.out.println(“Teilgraph:“);
if (inListe.GibWarDa() != besucht)
BesucheTeil(inListe, besucht);
inListe = inListe.GibWeiter();
}
}
629
Programm: Die Tiefensuche in einemgerichteten Graphen (1/2)
private void BesucheTeil(Knoten aktuell, boolean besucht){
KnotenListe adjazenz;
Knoten inAdjazenz;
aktuell.SetzeWarDa(besucht);
System.out.println(aktuell.GibWert());
adjazenz = aktuell.GibAdjazenz();
inAdjazenz = adjazenz.InitIteration();
while (inAdjazenz != null)
if (inAdjazenez.GibWarDa() == besucht)
inAdjazenz = adjazenz.GeheWeiter();
else
BesucheTeil(adjazenz.GeheWeiter(),besucht);
}
…
}
Tiefensuche in gerichteten Graphen
Kapitel 17.4
Schlangen / Queues
631
Allgemeines zu Queues
16
10
9 14
13 15
18
24
ws null
ws null
16
10
9 15
13 14
18
24
vor Besuch des Knotens 10
nach Besuch des Knotens 10
Programm: Die Klasse SohnListe
• Queues sind wichtig für die Abarbeitung von Aufgaben in derReihenfolge FIFO (first-in-first-out), wie an derSupermarktkasse
• Typische Methoden:– Prüfen auf Gefülltheit (bei beschränkten Schlangen)– Prüfen auf Leerheit– Anfügen– Entfernen (am Anfang)– Liefern des ersten Elementes– Ermittlung der Länge
632
Allgemeines zu Queues
16
10
9 14
13 15
18
24
ws null
ws null
16
10
9 15
13 14
18
24
vor Besuch des Knotens 10
nach Besuch des Knotens 10
Programm: Die Klasse SohnListe
• Queues werden realisiert über Listen, auf die mittels dergenanten Methoden zugegriffen wird.
• Da nur über diese Methoden zugegriffen wird, ist sichergestellt,daß keine anderen, nicht Queue-kompatiblen Manipulationenstattfinden.
Kapitel 17.5
Kellerspeicher / Stapel / Stacks
634
Allgemeines zu Stacks
• Stacks sind ein weiteres Beispiel für einen abstrakten Datentypund den Umgang mit verketteten Listen.
• Stacks basieren auf den Elementen wie sie in linearen Listenverwendet wurden.
• Das letzte in einem Stack abgelegte Element wird als erstesherausgenommen.
• Elemente dieser Datenstruktur werden nach dem LIFO-Prinzip(Last In First Out) verwaltet.
635
• Initialisieren eines leeren Stacks.• Testen, ob der Stack leer ist.• Ablegen eines Elements auf dem Stack
(push -Operation)• Inspektion des obersten Elementes
(top -Operation)• Entfernen des obersten Elementes des Stacks
(pop -Operation)
Methoden auf Stacks
636
Darstellung der Stack-Methoden
17
9
8
19
4
17
9
8
17
9
8
24
17
9
8
push 19
push 24
pop
pop4
637
Die Klasse Stackclass Stack {
private Element derStack;
Stack() { derStack = null; }
Stack(int i) { derStack = new Element(i); }
boolean empty() {
return derStack == null;
}
void push(int i) {
derStack = new Element(i, derStack);
}
int pop() {
int topWert = (derStack != null ? derStack.GibWert() : 0);
derStack = derStack.GibWeiter();
return topWert;
}
int top() {
return (derStack != null ? derStack.GibWert() : 0);
}
}
638
java.util.Stack
• Klasse java.util.Stack extends java.util.Vector– Stapel auf Objekten basierend mit allen geerbten Funktionalitäten von
Vector– Sehr mächtig und sehr langsam
=> für reine Stackfunktionalität Eigenimplementierung besser– public Stack()
• Konstruktor für leeren Stack
– public Object push(Object item)• Legt Objekt auf Stapelspitze
– public Object pop() throws EmptyStackException• Holt Objekt von Stapelspitze (und entfernt es)
– public Object peek() throws EmptyStackException• Gibt Referenz von Objekt auf Stapelspitze, ohne es zu entfernen
– public boolean empty()• Testet, ob Stack leer ist
639
java.util.Stack - Beispieljava.util.Stack stapel = new java.util.Stack();stapel.push("Text");stapel.push(new Integer(2));stapel.push(new Double(1e100));
System.out.println("Gesamt: " + stapel);try {
while (!stapel.empty())System.out.println("Objekt: " + stapel.pop());
} catch (java.util.EmptyStackException e) {}
Ausgabe:Gesamt: [Text, 2, 1.0E100]Objekt: 1.0E100Objekt: 2Objekt: Text
Kapitel 17.6
Mengen
641
Allgemeines zu Mengen
• ist nicht erforderlich, weil jeder Mengen kennt :-)• Interessant ist dann nur die Frage, wie Mengen rechnerintern
dargestellt werden.• Dazu gibt es zwei grundlegende Möglichkeiten:
– Charakteristische Vektoren– Hashing-Tabellen
642
Charakteristische Vektoren
• Für jedes potentielle Mengenelement wird in einem Array-Eintrag des Typs Boolean festgehalten, ob es in der Menge istoder nicht.
• Vorteil: einfache Prüfung auf Enthaltensein• Vorteil: einfache Durchführung von Mengenoperationen• Nachteil: enorme Platzverschwendung, gerade bei vielen
potentiellen Elementen und kleinen Mengen
643
Charakteristische Vektoren
• Beispiel:– Grundmenge: alle potentiellen 600 Programmierungsstudenten
(Erstsemester Informatik, Physik, Mathe)– Menge der am Vorlesungsende regelmäßig teilnehmenden
Studierenden, voraussichtlich 300.– Studierende seien gegeben durch Name, Fach– Wir nehmen an, dass der Name eindeutig ist.
• Das Prüfen, ob Studierende nach am Ende vonProgrammierung und RS noch in der Vorlesung sind, ist danneine einfach Bitoperation (UND)
• Schema der aktuellen Teilnehmermenge:
644
Charakteristische Vektoren
• Beispiel:– Grundmenge: alle Erstligavereine im DFB, also 18– Vereine seien gegeben durch offiziellen Namen, letzte Meisterschaft,
letzter internationaler Wettbewerb, Bundesland– Darzustellende Mengen:
• die in bestimmten Pokalrunden vertretenden Verein• die Menge der Meistermannschaften,• die Menge der Mannschaften aus NRW,• die Meistermannschaften aus NRW mit internationalem Titel.
645
Hashing
• Die begrenzte Einsetzbarkeit von charakteristischen Vektorenzeigt sich an sehr großen Mengen.
• Beispiel:– Grundmenge: Liste aller Wörter im Duden– Darzustellende Menge: die Menge aller Wörter auf den Prog-Folien
• Wenn wir nun die Speicherplatzverschwendung begrenzenwollen, dann stellen wir nicht mehr für jedes potentielleElement der Menge einen Speicherplatz zur Verfügung,sondern nur noch eine kleine Anzahl von Speicherplätzen, aufdie die Elemente der darzustellenden Menge abgebildetwerden.
646
Hashing
• Eine Hash-Funktion bildet die darzustellende Menge(=Teilmenge der Grundmenge) auf eine feste Anzahl vonSpeicherplätzen ab.
• Da man nicht für jedes Element der Grundmenge einenSpeicherplatz hat, werden mehrere Elemente der Grundmengeauf die gleiche Position abgebildet.
• Schema einer Hash Table:
647
Hashing
• B sei die Anzahl der Speicherplätze.• Eine Hash-Funktion h arbeitet auf den Elementen der
Grundmenge und bildet diese auf einen Wert zwischen 0 undB-1 ab. Auf Grund dieser Eigenschaft nennt man Hash-Funktionen auch Schlüsseltransformationen.
• B wird die Anzahl der „Buckets“ der Hash Table genannt.• h(x) ist der Bucket, in dem das Element x der Grundmenge zu
finden ist.• Wenn die Elemente Integer-Zahlen sind, dann ist h(x) = x mod
B eine sinnvolle Hash-Funktion
648
Hashing
• Wenn die Elemente Strings sind, dann kann man die Integer-Werte der Character addieren, die Summe ganzzahlig durch Bteilen und hat damit eine sinnvolle Hash-Funktion
649
Hashing
• Die Qualität einer Hash-Funktion hängt davon ab, ob sie dieElemente der Grundmenge gleichmäßig auf die Speicherplätzeverteilt, d.h. für beliebige darzustellende Teilmengen aus derGrundmenge soll eine gelichmäßige Verteilung auf die Bucketsstattfinden.
• Konkreter:– Eine Hash-Funktion sollte surjektiv sein, also auf alle Buckets abbilden.– Sie sollte die Elemente der Grundmenge gleichmäßig auf die Buckets
verteilen.– Sie sollte effizient zu berechnen sein.
650
Hashing
• Beispiel:– Grundmenge: Fußballvereine,– darzustellende Menge: DFB-Viertelfinal-Teilnehmer,– 8 Speicherplätze, Zuordnung über Bundesland.– Das könnte kollisionslos klappen.– Das kann aber auch ganz daneben gehen.
• Beispiel: Monatsnamen auf 17 Buckets
• Beispiel: Wörter und ASCII-Summen
651
Hashing
16
10
9 14
13 15
18
24
ws null
ws null
16
10
9 15
13 14
18
24
vor Besuch des Knotens 10
nach Besuch des Knotens 10
Programm: Die Klasse SohnListe
• Der Lastfaktor einer Hash Table ergibt sich bei BSpeicherplätzen und einer Kardinalität M der darzustellendenMenge durch M/B.
• Beispiel: Viertelfinalvereine, Monate, Wörter
• Beim offenen Hashing wird zu jedem Bucket eine dynamischeDatenstruktur (typischerweise eine verkettet Liste) benutzt.
652
Hashing
16
10
9 14
13 15
18
24
ws null
ws null
16
10
9 15
13 14
18
24
vor Besuch des Knotens 10
nach Besuch des Knotens 10
Programm: Die Klasse SohnListe
• Beim geschlossenen Hashing kann pro Bucket nur eine kleine,fest definierte Anzahl von Elementen aufgenommen werden.
– Hier braucht man dann rehashing-Verfahren, die im Fall desÜberschreitens der Grenze ein freies Plätzchen suchen.
– Das rehashing kann dabei kaskadieren.– Die feste Begrenzung kann dabei zu mühevollem Suchen führen.
653
Die Klasse java.util.Hashtable
• Kartenverwaltung: Zwei Listen (Kartennummern, PINs), die paralleldurchlaufen werden müssen
• besser: Datenstruktur, die Schlüssel und Wert gemeinsam speichert• Lösung: java.util.Hashtable
public class Hashtable extends Dictionary ... {
...
public boolean contains(Object value) {...};
public boolean containsKey(Object key) {...};
public Enumeration elements() {...};
public Enumeration keys() {...};
public Object put(Object key, Object value) {...};
public Object get(Object key) {...};
public Object remove(Object key) {...};
...
}
Hilfsklassen
654
Kartenverwaltung mit Hashtableimport java.util.*;
public class Kartenverwaltung {
private Hashtable karten;
...
public void erfasseWeiteresKonto (String kartennummer, String pin,Girokonto konto) {
karten.put(kartennummer, pin);
...
}
public boolean pinIstGültig (String kartennummer, String pin) {
String geheim = (String) karten.get(kartennummer);
return (pin.equals(geheim));
}
}
Hilfsklassen
Importieren von Klassen :
* importiert alle Klassen eines Packages
655
Übung: Hashtable
Motivation• Verwenden von Hashtable statt Arrays• Schneller Zugriff auf die gespeicherten Daten
Aufgabe• Verwenden Sie zur Speicherung der Konten ebenfalls eine Hashtable
– Überlegen Sie sich dazu, was als Schlüssel und was als Eintrag verwendetwerden kann
• Ändern Sie die Klasse Kartenverwaltung• Fügen Sie eine Methode hinzu, die zu allen Konten den Inhaber ausgibt• Testen Sie die neue Kartenverwaltung
– Verwenden Sie hierzu die alte Testklasse– Erweitern Sie die Testklasse zum Testen der neuen Methode
Hilfsklassen
656
Übung: Hashtableimport java.util.*;
public class Kartenverwaltung {
private Hashtable karten;
private Hashtable konten;
public Kartenverwaltung(){
karten = new Hashtable();
konten = new Hashtable();
}
public void erfasseWeiteresKonto (String kartennummer, String pin,
Konto einKonto) {
karten.put(kartennummer, pin);
konten.put(kartennummer, einKonto);
}
Hilfsklassen
657
Übung: Hashtablepublic Konto holeKonto (String kartennummer) throws
KontoNichtVorhandenException {
Konto k = (Konto) konten.get(kartennummer);
if (k == null) throw new KontoNichtVorhandenException();
return (k);
}
public boolean pinIstGültig (String kartennummer, String pin){
String geheimzahl = (String) karten.get(kartennummer);
return (pin.equals(geheimzahl));
}
public void listeInhaber() {
for (Enumeration el=konten.elements(); el.hasMoreElements(); ) {
Konto k = (Konto) el.nextElement();
Bildschirm.gibAus(k.holeInhaber().toString());
}
}
Hilfsklassen
658
Zusammenfassung
• Dynamische Datenstrukturen sind wesentlich für fast alle Informatik-Probleme.
• Es gibt eine natürliche Hierarchie dieser Strukturen.• Alle dynamischen Strukturen verfügen über strukturell ähnliche Methoden.• In Java sind vordefinierte Lösungen für die grundlegenden dynamischen
Strukturen verfügbar, und zwar im Paket java.util
– Listen werden mit java.util.Vector realisiert
– Stapel werden mit java.util.Stack realisiert– Realisierung von Tabellen (mit zwei Spalten) mit java.util.Hashtable
– Durchlauf durch Listen mit java.util.Enumeration
Hilfsklassen
Kapitel 18
Ein- und Ausgabe (java.io)
660
java.io Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
661
java.io - Ein- und Ausgaben, Streams
• Ergebnisse der Durchführung von Programmen müssenzuweilen persisten gemacht werden.
• Von Persistenz eines Objektes spricht man, wenn das Objektdas Ende einer Programmausführung überlebt und von einemanderen Programm (oder einer anderen Ausführung desgleichen Programms) benutzt werden kann.
• Persistent werden Objekte, indem man sie speichert.Speicherort kann das Dateisystem sein oder auch eineDatenbank (dazu mehr in der Vorlesung Informationssysteme).
• Die Beschreibung der Struktur persistenter Objekte wird dasFormat genannt.
• Wie lassen sich die Fußballvereine persistent machen?
662
java.io - Ein- und Ausgaben, Streams
• Und wie lassen sich solche persistent gemachten Objektewieder einlesen?
• Wie einigen sich Schreiber und Leser auf Formate?
• Java-Ansatz: Eine Reihe von Formaten wird in Form vonKlassen und Interfaces vordefiniert. Hierzu gehört daseigentliche Format und natürlich auch der schreibende /lesende Zugriff.
663
Streams– Ein Objekt, aus dem eine Sequenz von Bytes gelesen
werden kann, ist ein Eingabe-Stream.
– Das Schreiben von Bytes erfolgt in Ausgabe-Streams.
– Die Implementierung erfolgt mit Hilfe der abstrakten KlassenInputStream und OutputStream
– Character (Unicode) werden analog über die abstraktenKlassen Reader und Writer behandelt.
java.io - Ein- und Ausgaben, Streams
664
java.io - Ein- und Ausgaben, Streams
• In diesem Kapitel:
– Streams: Merkmale, Klassen, einfache Verwendung– Ablegen der Ergebnisse eines binären Suchbaums
665
java.io - Ein- und Ausgaben, Streams
• Ein- und Ausgaben werden über Streams realisiert(außer GUI-Komponenten!)
• Streams (Ströme) sind sequentiell organisierte Datenmengen.• Streams sind Objekte, in die Daten hineingegeben bzw. aus
denen Daten ausgelesen werden können.• Mittels des Pakets java.io werden unterschiedliche Streams
unterstützt, so dass das in vielen Programmiersprachenmühevolle Thema der Dateibehandlung vereinfacht wird.
• Grob:– InputStream als Superklasse für Eingabeströme, also Ströme, aus
denen gelesen wird.– OutputStream als Superklasse für Ausgabeströme, also Ströme, in die
geschrieben wird.
666
java.io - Ein- und Ausgaben, Streams
• Unterschiedliche Formate von Streams für– Ströme von Bytes / Ströme von Unicode-Zeichen– Schreiben oder Lesen– Unterschiedliche Ziele bzw. Quellen:
• Dateien• Standardeingabe und -ausgabe• Andere Klassen, wie z.B. Strings• Piped-Streams, in denen Schreibe- und Lesestreams gepuffert
verbunden sind• gefilterte Streams, in denen Inhalte verändert werden können• Streams für sicheren Datenaustausch zwischen Threads• Objektserialisierung
667
java.io - Ein- und Ausgaben, Streams
• Von besonderer Bedeutung: Filter
• Ein Filter verbirgt den Zugriff auf einen Strom und gruppiert(filtert) die von diesem gelesenen Informationen durchgeeignete Methoden.
• Der Filter DataInputStream stellt beispielsweise Methodenbereit, die als Ergebnis des Lesevorgangs einen Wer einesprimitiven Typs liefern.
• Der Filter FileInputStream liefert einzelne Zeichen.
• Durch diesen vordefinierten Zugriff wird die Detailkenntnis desFormats entbehrlich! 668
java.io - Ein- und Ausgaben, Streams
• In Java wird strikt unterschieden zwischen:
– der Manipulation der Inhalte einer Datei und– der Änderung des organisatorischen Rahmens (Namensänderung,
Öffnen, Schließen etc.)
– Inhaltsänderungen basieren auf Methoden der KlasseInputStream, OutputStream
– Änderungen der Rahmenbedingungen basieren auf Methoden derKlasse File
• Hinweis: Portabilität!
669
java.io
• java.io.OutputStream– abstrakte Klasse– Superklasse aller Byte Output Streams
– definiert grundlegende Methoden für alle Byte Output Stream Klassen– close unterbricht die Verbindung zwischen Programm und Datei
Die Java Klassenbibliotheken
public void close()
public void flush()
public void write(byte[] b)
670
java.io.OutputStream
• Abstrakte Klasse java.io.OutputStream :– public abstract void write(int b) throws IOException
• Schreibt ein Byte b in den Stream• muß von abgeleiteter Klasse überschrieben werden
– public void write(byte[] b) throws IOException• Schreibt ein Array von Bytes• Falls nicht überschrieben, wird write(int b) benutzt
– public void write(byte[] b, int off, int len)throws IOException
• Zusätzlich lassen sich Anfang und Ende bestimmen
– public void flush() throws IOException• Kann überschrieben werden, um eine Entleerung eines Puffers gewährleisten
zu können
671
java.io
• java.io.InputStream– abstrakte Klasse– Superklasse aller Byte Input Streams
– definiert grundlegende Methoden für alle Byte Input Stream Klassen
Die Java Klassenbibliotheken
public int available()
public void close()
public void read(byte[] b)
public void reset()
672
java.io.InputStream
• Abstrakte Klasse java.io.InputStream :– public abstract int read() throws IOException
• Liest ein Byte aus dem Stream• muß von abgeleiteter Klasse überschrieben werden
– public int read(byte[] b) throws IOException• Liest ein Array von Bytes• Falls nicht überschrieben, wird read() benutzt
– public int read(byte[] b, int off, int len)throws IOException
• Zusätzlich lassen sich Anfang und Ende bestimmen
– public int available() throws IOException• Bestimmt Anzahl der noch lesbaren Bytes
– public void close() throws IOException• Schließt Stream und läßt belegte Systemresourcen frei
673
java.io
• java.io.Writer– abstrakte Klasse– Superklasse aller Character Output Streams
– definiert grundlegende Methoden für alle Character Output StreamKlassen
Die Java Klassenbibliotheken
public void close()
public void flush()
public void write(char[] c)
674
java.io.Writer
• Abstrakte Klasse java.io.Writer :– public void write(int c) throws IOException
• Schreibt ein Zeichen c in den Stream. Untere 16 Bit werden benutzt.
– public void write(char[] cbuf) throws IOException• Schreibt ein Array von Zeichen
– public abstract void write(char[] cbuf, int off,int len) throws IOException
• Zusätzlich lassen sich Anfang und Ende bestimmen
– public void write(String str) throws IOException• Ausgabe eines Strings
– public abstract void flush() throws IOException• Muß überschrieben werden, soll eine Entleerung eines eventuellen Puffers
gewährleisten
675
java.io
• java.io.Reader– abstrakte Klasse– Superklasse aller Character Input Streams
– definiert grundlegende Methoden für alle Character Input StreamKlassen
Die Java Klassenbibliotheken
public void close()
public void read(char[] c)
public void reset()
676
java.io.Reader
• Abstrakte Klasse java.io.Reader :– public int read() throws IOException
• Liest ein einzelnes Zeichen aus dem Stream• -1 wird bei Stream-Ende zurückgegeben
– public int read(char[] cbuf) throws IOException• Liest ein Array von Zeichen• Bis Eingabe erhältlich ist, wird gewartet
– public abstract int read(char[] cbuf, int off,int len) throws IOException
• Zusätzlich lassen sich Anfang und Ende bestimmen
– public boolean ready() throws IOException• Fragt ab, ob der Stream fertig ist, um ausgelesen zu werden
– public void close() throws IOException• Schließt Stream und läßt belegte Systemresourcen frei
677
Stream Sorten• Ströme von Bytes (z. B. für Byte[] )
– Schreibende Streams sind Unterklassen von OutputStream– Lesende Streams sind Unterklassen von InputStream
• Ströme von Unicode-Zeichen (z. B. für String )– Schreibende Streams sind Unterklassen von Writer– Lesende Streams sind Unterklassen von Reader
• Abgeleitete Klassen für spezifische Zwecke sollten Namenhaben, die auf Reader , Writer , InputStream oderOutputStream enden=> Sie sind so einfach in die richtige Kategorie einzuordnen
678
InputStream Hierarchy
InputStream
StringBufferInputStream
FileInputStream
FilterInputStream
SequenceInputStream
ByteArrayInputStream
PipedInputStream
java.io
679
Filter InputStream Hierarchy
FilterInputStream
CheckedInputStream
DigestInputStream
BufferdInputStream
LineNumberInputStream
DataInputStream
PushbackInputStream
InflaterInputStream
GZIPInputStream
ZIPInputStream
java.io
680
Output Stream Hierarchy
OutputStream
FileOutputStream
FilterOutputStream
ByteArrayOutputStream
PipedOutputStream
java.io
681
Filter OutputStream Hierarchy
FilterOutput Stream
CheckedOutputStream
BufferdOutputStream
DigestOutputStream
DataOutputStream
PrintStream
DeflaterOutputStream
GZIPOutputStream
ZIPOutputStream
java.io
682
Benutzung eines I/O Stream
Ein FileInputStream ist ein I/O stream, der an eineDatei gekoppelt ist:
FileInputStream f = new FileInputStream("myfile.dat");
byte b = f.read();
Ein DataInputStream verfügt über Methoden, umnumerische Typen zu lesen:
DataInputStream d = irgendwas;
double a = d.readDouble();
683
Kombination von Stream-Filtern
FileInputStream kann keine Zahlen lesen,DataInputStream können nicht auf Dateien operieren
FileInputStrea m f = new FileInputStream("myfile.dat");
DataInputStrea m d = new DataInputStream(f);
doubl e a = d.readDouble();
Diese Kombination ist in den meisten I/O-Anwendungen nötig.
684
Eigenschaften von Streams
read() und write() werden selten direkt benutzt.
read() und write()( direkt oder indirekt benutzt)blockieren Threads.
available() wird benutzt, um Blockierungen durchread() zu vermeiden.
Streams sollten mit close beendet werden .
Streams können mit flush geleert werden .
685
Unicode Streams
Unicode Streams benutzen Klassen, die von Reader undWriter abgeleitet sind.
Readerpublic abstract int read()
throws IOException
Writerpublic abstract void write(int b)
throws IOException
686
Reader hierarchy
FilterReader
CharArrayReader PipedReader
BufferedReader
StringReader
Reader
InputStreamReader
LineNumberReader
PushbackReader
FileReader
java.io
687
Writer hierarchy
FilterWriter
CharArrayWriter PipedWriter
BufferedWriter
StringWriter
Writer
OutputStreamWriter
FileWriter
PrintWriter
java.io
688
Schreiben von Text
Benutzung eines PrintWriter
PrintWriter out = new PrintWriter
(new FileWriter("myfile.txt"));
out.println("Hello world");
Die Methoden print() und println() werden durchInstanzen von PrintWriter implementiert.
689
Lesen von Text
Verwendet BufferedReader Klasse
Liest Zeile für Zeile und „parsed“ diese.
BufferedReader in = new BufferedReader(
new FileReader("myfile.txt"));
String s;
while ((s = in.readLine()) != null)
{
process s;
}
690
java.io
• java.io.File– Objekte werden erzeugt, um Dateien erzeugen, öffnen und schließen zu
können
public void erzeugeDatei {File datei = new File(“Test.txt”);System.out.println(“Dateiname: ” + datei.getName());
}
Ausgabe:
Dateiname: Test.txt
Die Java Klassenbibliotheken
691
java.io.File
• Klasse java.io.File– Objekte werden erzeugt, um Dateien zu Erzeugen, zu öffnen und zu
schließen. Dateisystem kann dem SecurityManager unterliegen
Konstruktor :– public File(String pathname)throws NullPointerException
• Erzeugt Objekt über Pfadnamen
Prüfung von Eigenschaften:– public boolean exists()– public boolean canRead()– public boolean canWrite()– public boolean isFile()– public boolean isDirectory()– public boolean isHidden()– public long length()
692
java.io.File
Filesystem-Handhabung:– public boolean delete()
• Löscht Datei oder Verzeichnis
– public void deleteOnExit()
• Löscht bei Beendigung der Virtual Machine• Flag wird gesetzt, welches nicht zurückgenommen werden kann
– public boolean mkdir()
• Erstellt Verzeichnis
– public boolean mkdirs()
• Erstellt Verzeichnis und eventuell benötigte, nicht existierendeMutterverzeichnisse
693
FileWriter
• Klasse java.io.FileWriter– Indirekt abgeleitet von java.io.Writer
Konstruktoren:– public FileWriter(File file) throws IOException
– public FileWriter(String fileName, boolean append)throws IOException
• append == true: Daten sollen angehängt werden
– public FileWriter(String fileName) throws IOException
694
FileReader
• Klasse java.io.FileReader– Indirekt abgeleitet von java.io.Reader
Konstruktoren:– public FileReader(File file) throws IOException
– public FileReader(String fileName) throws IOException
695
FileOutputStream
• Klasse java.io.FileOutputStream– Abgeleitet von java.io.OutputStream
Konstruktoren:
– public FileOutputStream(File file) throws IOException
– public FileOutputStream(String fileName,boolean append) throws IOException
• append == true: Daten sollen angehängt werden
– public FileOutputStream(String fileName)throws IOException
696
FileInputStream
• Klasse java.io.FileInputStream– Abgeleitet von java.io.InputStream
Konstruktoren:
– public FileInputStream(File file) throws IOException
– public FileInputStream(String fileName)throws IOException
697
Beispiel FileWriter
try {
FileWriter out = new FileWriter("Datei.txt");
out.write("Erste Zeile\n");
out.write("Zweite Zeile\n");
out.close();
} catch (IOException e) {
System.out.println("Fehler: " + e);
}
• Es entsteht eine Datei mit entsprechendem Inhalt
698
Beispiel FileReader / StringWritertry {
FileReader in = new FileReader("Datei.txt");
StringWriter sout = new StringWriter();
int c;
while ((c = in.read()) != -1) // Solange Ende nicht erreicht
sout.write(c);
System.out.println(sout); // gesamter Inhalt in string// gewandelt, inklusive der// Zeilenumbrüche
} catch (IOException e) {
System.out.println("Fehler: " + e);
}
Ausgabe:Erste Zeile
Zweite Zeile
699
Unterschiedliche Streams• Andere Sorten von Streams funktionieren ähnlich:
Zeichen- Streams Byte StreamsCharArrayReaderCharArrayWriter
ByteArrayInputStreamByteArrayOutputStreamHaupt-
speicher StringReaderStringWriter
StringBufferInputStream
Pipe PipedReaderPipedWriter
PipedInputStreamPipedOutputStream
File FileReaderFileWriter
FileInputStreamFileOutputStream
700
Beispiel: Zählen von Zeichen in Dateien
• Typische Struktur des Programms:– Identifikation der Datei und Überprüfung ihrer Existenz– implizites Öffnen durch den Aufruf eines Konstruktors für einen Strom– Bearbeiten des Inhalts und Schließen (hier implizit am Programmende)
import java.io.*;
class Auswertung {
public static void main(String[] args) throws IOException {
InputStream eingabedatei = null;
StringBuffer dateiname = new StringBuffer();
701
Beispiel: Zählen von Zeichen in Dateien// Datei bestimmen
if (args.length == 0) {
while (dateiname.length() == 0) {
System.out.println("Bitte Dateinamen angeben: ");
char zeichen;
boolean wortende = false;
do {
zeichen = (char)System.in.read();
wortende = (zeichen == ' ' || zeichen == '\n');
if (!wortende) dateiname.append(zeichen);
} while (!wortende);
}
} else dateiname.append(args[0]);
702
Beispiel: Zählen von Zeichen in Dateientry {
eingabedatei = new FileInputStream(dateiname.toString());
}
catch (FileNotFoundException f) {
System.out.println("Datei " + dateiname + "nicht vorhanden!");
System.exit(1);
}
703
Beispiel: Zählen von Zeichen in Dateien// Datei auswerten
int nächstesZeichen;
int zeilen = 0, andereZeichen = 0, leerzeichen = 0;
while ((nächstesZeichen = eingabedatei.read()) != -1) {
switch ((char)nächstesZeichen) {
case '\n': zeilen++; break;
case ' ': leerzeichen++; break;
default: andereZeichen++;
}
}
// Auswertung ausgeben
System.out.println("Auswertung der Datei " +dateiname);
System.out.println("Zeilen: " + zeilen);
System.out.println("Leerzeichen: " + leerzeichen);
System.out.println("andere Zeichen: " + andereZeichen);
}
}704
Erläuterungen zur Klasse Auswertung
• Die Referenz eingabedatei verwaltet bei der Ausführungdes Programms die zu analysierende Datei, der variable TextStringBuffer dateiname ihren Namen.
• Parameter, die beim Aufruf eines Programms angegebenwerden, werden durch den Parameter args (Feld vonTexten) an die Methode main übergeben.
705
Erläuterungen zur Klasse Auswertung
• Falls kein Parameter übergeben wurde, wird der Dateinamezeichenweise eingelesen.
• Innerhalb des Paketes java.lang steht eine Klasse Systemzur Verfügung, die ein öffentliches, statisches Attribut mit demNamen out hat. out ist eine Referenz auf ein Objekt derKlasse PrintStream , die eine Unterklasse vonFilterOutputStream ist.
706
Klasse PrintStream
• PrintStream ist (indirekt) von OutputStream abgeleitet• Es werden print - und println -Methoden für Objekte und
sämtliche simple Datentypen zur Verfügung gestellt.– println -Methode hängt im Gegensatz zur print -Methode ein
Zeilenumbruch bei jedem Aufruf an.
• Im Package System sind statische Attribute definiert:– public static final PrintStream out // Standard-Out– public static final PrintStream err // Standard-Error– public static final InputStream in // Standard-In
• Aus diesem Grunde geschieht Ausgabe mitSystem.out.println( ...)
707
Objektserialisierung
• Serialisierung bedeutet, Objekte in einen Stream zu schreibenund Objekte aus einem Stream zu lesen
• Schreiben geschieht mit java.io.ObjectOutputStream– Unterklasse von java.io.OutputStream
• Lesen geschieht mit java.io.ObjectInputStream– Unterklasse von java.io.InputStream
708
Konstruktoren für Object-Streams
• Konstruktoren für ObjectOutputStream /ObjectInputStream :
– public ObjectOutputStream(OutputStream out)throws IOException
– public ObjectInputStream(InputStream in)throws IOException, StreamCorruptedException
• => Objekte können durch beliebige InputStreams undOutputStreams geschickt werden
• Um Objekte in Dateien zu speichern, wirdFileOutputStream und FileInputStream benutzt
709
Interface Serializable
• Klassen, deren Objekte serialisierbar sein sollen, müssen dasInterface java.io.Serializable implementieren
• Interface java.io.Serializable ist leer, hat also keineMethoden oder Attribute=> Interface wird nur als Markierung benutzt
• Viele Klassen in den Standardbibliotheken sind serialisierbar(Achtung, nicht alle)
710
Kontrolle über Serialisierung (Teil 1)
• Von Objekten werden alle serialisierbaren Attribute mitserialisiert– Bei komplexen Datenstrukturen, wie Bäumen oder Listen muß nur das
Basisobjekt serialisiert werden, weil automatisch alle referenziertenObjekte mit berücksichtigt werden.
• Statische Attribute werden nicht serialisiert• Attribute, die nicht zum persistenten Teil von Objekten
gehören, können bei Deklaration mit transientgekennzeichnet werden.
• Als transient werden die abgeleiteten Attribute gekennzeichnet.
711
Methoden der Object-Streams
• ObjectOutputStream:– public final void writeObject(Object obj)
throws IOException• Schreibt serialisierbares Objekt in den Stream
– public void writeDouble(double d) throws IOException
– public void writeLong(long l) throws IOException• Viele andere primitive Datentypen können geschrieben werden
• ObjectInputStream:– public final Object readObject()
throws OptionalDataException,ClassNotFoundException,IOException
– public double readDouble() throws IOException• viele andere primitive Datentypen können gelesen werden
712
Beispieltry {
FileOutputStream out = new FileOutputStream("Persistenz.txt");ObjectOutputStream objout = new ObjectOutputStream(out);objout.writeObject("Text");objout.writeInt(200);objout.flush();out.close();
FileInputStream in = new FileInputStream("Persistenz.txt");ObjectInputStream objin = new ObjectInputStream(in);String zeichen = (String)objin.readObject();int zahl = objin.readInt();in.close();
System.out.println(zeichen + "\n" + zahl);} catch (IOException e) {} catch (ClassNotFoundException e) {}
Ausgabe:Text
200
713
Kontrolle über Serialisierung (Fortsetzung)
• Es gibt für Klassen, die serialisiert werden sollen, dieMöglichkeit, den Vorgang selbst zu bestimmen da– Zusatzinformationen mit serialisiert werden sollen, um Konsistenz mit
Umgebung sicherzustellen (z. B. statische Attribute)• Hier kann Standardserialisierung erweitert werden• Mit wenig Aufwand möglich
– Informationen über transiente under nicht serialisierbare Attributebenötigt werden
• Objektkonsistenz ist bei Existenz von transienten Attributen nicht immer trivial
– Ein Objekt selbst situationsabhängig bestimmen möchte, ob esserialisierbar ist
714
Kontrolle über Serialisierung
• Kontrolle von ObjectOutputStream :– In der Klasse des zu serialisierenden Objektes muß die Methode
private void writeObject(ObjectOutputStream s)throws IOException
mit exakt dieser Signatur definiert sein.– Statt der Standard-Serialisierung wird diese Methode aufgerufen– Der Outputstream (s) wird übergeben, daher kann die Serialisierung von
Hand vorgenommen werden– Mit s.defaultWriteObject(); kann die Standard-Serialisierung
aufgerufen werden, die ggf. noch ergänzt wird– Soll dem ObjectOutputStream die Serialisierung verweigert werden,
kann NotSerializableException geworfen werden.• Der ObjectOutputStream fängt diese Exception ab und wertet sie aus.
715
Kontrolle über Deserialisierung
• Kontrolle von ObjectInputStream :– In der Klasse des zu deserialisierenden Objektes muß die Methode
private void readObject(ObjectInputStream s)throws IOException, ClassNotFoundException
mit exakt dieser Signatur definiert sein.– Statt der Standard-Deserialisierung wird diese Methode aufgerufen– Der Inputstream (s) wird übergeben, daher kann die Serialisierung von
Hand vorgenommen werden– Mit s.defaultReadObject(); kann die Standard-Serialisierung
aufgerufen werden, die ggf. noch ergänzt wird.– Soll dem ObjectInputStream die Serialisierung verweigert werden,
kann NotSerializableException geworfen werden.• Der ObjectInputStream fängt diese Exception ab und wertet sie aus.
716
Interface Externalizable
• Die stärkste Kontrolle über Serialisierung wird durchImplementierung des Interfaces Externalizable erreicht
package java.io;
public interface Externalizable extends Serializable {
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
– Die Methoden writeExternal und readExternal müssen überschriebenwerden
– Die Klasse ist selbst für das Lesen und Schreiben verantwortlich undmuß das auch für die Oberklassen gewährleisten
– Methoden writeExternal und readExternal sind public=> Gefahr des Überschreibens
717
Beispiel: Ablegen von binären SuchbäumenZiel: binäre Suchbäume werden persistent gemacht, sie können
nach Beendigung eines Programms wieder geladen werden.
Dazu werden die Methoden Sichere und Lade in die KlasseBST eingefügt.
Sichere arbeitet rekursiv (Preorder) und verwendet die privateMethode PreSichere .
Lade arbeitet iterativ.
718
Beispiel: Ablegen von binären Suchbäumenimport java.io.*;
class BST {
private Knoten wurzel;
BST() { wurzel = null; }
…
void Sichere(String dateiname) throws IOException {
DataOutputStream ausStrom =
new DataOutputStream( new FileOutputStream(dateiname);
PreSichere(ausStrom, wurzel);
}
private void PreSichere(DataOutputStream aus, Knotenaktuell) throws IOException {
if (aktuell != null) {
aus.writeInt(aktuell.GibWert());
PreSichere(aus, aktuell.GibLinks());
PreSichere(aus, aktuell.GibRechts());
}
}
719
Beispiel: Ablegen von binären Suchbäumen
void Lade(String dateiname) throws IOException {
DataInputStream inStrom =
new DataInputStream( new FileInputStream(dateiname);
try {
while (true)
FügeEin(inStrom.readInt());
}
catch (EOFException eof) {};
720
Beispiel: Ablegen von binären SuchbäumenEtwas trickreich ist die Konstruktion:
new DataOutputStream( new FileOutputStream(dateiname);
Von innen nach außen:
• zunächst wird ein Objekt der Klasse FileOutputStreamerzeugt, das auf einer Datei arbeitet, deren Name durchdateiname gegeben ist,
• das erzeugte Objekt der Klasse FileOutputStream wird anden Konstruktor der Klasse DataOutputStream übergeben,der es so verkapselt, daß die komfortable Schnittstelle vonDataOutputStream genutzt werden kann
Kapitel 19
Graphische Oberflächen (java.awt, java.swing)
722
javax.swing Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
723
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
724
Graphische Benutzungsoberflächen
Ziel: Erstellen einer GUI (z.B. für Bankautomaten)
Applets
Container für mehrerezusammengehörendeKomponenten
Behandlung vonBenutzereingaben(Mausklicks,...)
Eingabebereiche für Text
Schaltknöpfe
Anzeigefelder (Label)
Menü's
725
GUI-Bibliotheken in Java: JFC
• Java Foundation Classes (JFC)
– Swing Komponentenbibliothek (oftmals ungenauerweise synonym zuJFC verwendet)
– Unterstützung für frei wählbares Look&Feel– API für Dialoghilfen (Accessibility)– API für Einbinden von 2D-Grafik, Text, Bildern– Unterstützung für Drag&Drop
726
GUI-Bibliotheken in Java: Swing, AWT
• Erweiterbare Komponenten für Java-Benutzerschnittstellen– sichtbare („J“-Klassen) und unsichtbare Klassen
• JButton, JTextField vs. Modell-Klassen, Event-Klassen
• Swing 1.1 (javax.swing)– ist im JDK 1.2 enthalten– com.sun.java.swing in der Version 1.0.3 für JDK 1.1.x
• AWT (bereits im JDK 1.0 definiert)– wird weiterhin unterstützt– Button und JButton– wird vor allem für anspruchslose Anwendungen eingesetzt
727
Unterschied AWT - Swing
• AWT - Klassen (Abstract Window Toolkit)• Plattformabhängige Darstellung (Peer Klassen) („schwergewichtig“)• plattformabhängige Behandlung von Benutzereingaben• rechteckige Zeichenfläche, nicht überlappend• AWT umfaßt Schnittmenge aller Plattformen
• Swing - Klassen• Plattformunabhängige Darstellung• in Java geschrieben („leichtgewichtig“), bauen auf AWT auf• nicht nur rechteckige Formen• Swing umfaßt Konjunktion der Plattformen
GUI und Ereignisse
728
Entwicklungsziele
• Implementierung in Java ÿ(„lightweight components“)ÿ Ausführung ist plattformunabhängig
• frei wählbaren Look&Feels ÿÿ Darstellung ist plattformunabhängig
• Modell-basierter Programmierung ÿÿ MVC
• Komponenten als JavaBeans verpackt ÿ
• Kompatibilität zu AWT nein!
729
Aufbau der Swing-API
• Insgesamt 15 öffentliche Pakete, z.B.• javax.swing Elementare GUI-Komponenten
• javax.swing.event Ereignisbehandlung von Swing
• javax.swing.text Textdaten anzeigen, editieren• ...• (früher com.sun.java.swing)
• Benutzen eines Paketes:import javax.swing.*;import javax.swing.event.*;
GUI und Ereignisse
730
Bezug AWT - SwingVererbungshierarchie AWT-Swing
javax.swing
java.awt
JComponent
(java.applet)
JFrame
java.awt.Frame
JDialog
java.awt.Dialog
JWindow
java.awt.Window
java.awt.Window
JApplet
java.applet.Applet
java.awt.Panel
java.awt.Container
java.awt.Component
java.lang.Object
731
Aufbau von Swing 1.1
15 öffentliche Pakete:• javax.swing GUI-Komponenten• javax.swing.event Ereignisbehandlung von Swing• javax.swing.border Rahmen für GUI-Komponenten• javax.swing.table Tabellendaten anzeigen• javax.swing.tree Hierachische Daten anzeigen• javax.swing.text Textdaten anzeigen, editieren• javax.swing.text.html, javax.swing.text.html.parser ... In HTML• javax.swing.colorchooser Farbe auswählen-Dialog• javax.swing.filechooser Datei auswählen-Dialog• javax.swing.undo „Rückgängig“ bei GUI-Komp.• javax.swing.plaf, javax.swing.plaf.basic Frei wählbares Look&Feel• javax.swing.plaf.metal, javax.swing.plaf.multi• javax.accessibility Dialoghilfen für Ein-/Ausgabe
732
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
733
Fenster-Objekt: JFrame
• Bildschirm-Fenster mit Rahmen, Titel mit Buttonsund Menüzeile
• kann minimiert, verschoben, geschlossen undvergrößert werden
• ErzeugenJFrame f= new JFrame();
• JFrame hat einen Container "ContentPane".• enthält alle Komponenten, die auf der Zeichenfläche gezeichnet werden:
Container c= f.getContentPane();
•Hinzufügen von Komponenten zu einem JFrame
f.getContentPane().add(...);
GUI und Ereignisse
734
GUI-Komponenten (1/3)
Auf der Zeichenfläche können Komponenten angelegt werden!
wichtige Komponenten:
• JButtonKnopf, beim Drücken wird eine Aktion ausgeführt
JButton b= new JButton();b.setText("Drück' mich!");getContentPane().add(b);
GUI und Ereignisse
735
GUI-Komponenten (2/3)
• JTextField• Eingeben eines einzeiligen TextesJTextField t = new JTextField();String eingabetext = t.getText();
• JTextArea• Eingeben eines längereren Textes
• JLabel• einzeiliger Text, auch für Icon-Anzeige verwendbarJLabel l= new JLabel();l.setText("Eine Menge Buchstaben...");
GUI und Ereignisse
736
GUI-Komponenten
In der Zeichenfläche können Komponenten gezeichnet werden.
Die wichtigsten Komponenten:
• JButton– Knopf, beim Drücken wird eine Aktion ausgeführt
JButton b= new JButton()b.setText("Drück' mich!")
• JCheckBox– Boolesche Anzeige: "wahr"/"falsch"
• JRadioButton– exklusive Wahl aus Alternativen
737
GUI-Komponenten
• JComboBox– Einstellung eines Wertes (oben) mit
vorgegebenen Alternativen
738
• JList– damit kann man ein oder mehrere Element aus
einer Liste auswählen lassenString[] data = {“January", “February",...};
JList dataList = new JList(data);
– Holen der markierten ZellenObject[] objekte=eineListe.getSelectedValues();
• JTree– Darstellung von Hierarchien als Baum– Die Baumäste können an einem Knoten
auf- und zugeklappt werden
GUI-Komponenten
739
• JTable– Darstellen zweidimensionaler Daten in Tabellenform– Die dargestellten Daten werden im TableModel
gespeichert und verwaltet– Man kann einzeln, zeilen- oder spaltenweise Elemente
selektieren
– Erzeugen einer 4x3 TabelleJTable tabelle=new JTable(4,3);
– Holen des zugeordneten TableModelTable Model modell=tabelle.getModel();
– Ereignissez.B. TableColumnModelEvent mit MethodencolumnAdded(), -Moved();
GUI-Komponenten
740
Weitere Elemente
• JSlider– Schieberegler für Werteingabe
aus Zahlenbereich
• Datei-Dialog „Öffne“/Speichere“FileDialog(vaterFenster, „Titel“, LOAD);
741
GUI-Komponenten (3/3)import javax.swing.*;public class EinfachesGUI extends JFrame {
public EinfachesGUI() {getContentPane().setLayout(null);setSize(300,300);
JLabel l= new JLabel();l.setText(“Label-Fläche");l.setBounds(0,0,200,50);getContentPane().add(l);JButton b= new JButton();b.setText("Button-Fläche");b.setBounds(0,100,200,50);getContentPane().add(b);
}}public static void main (String args[]){
EinfachesGUI oberflaeche = new EinfachesGUI();oberflaeche.setVisible( true );
}}
GUI und Ereignisse
742
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
743
Komponenten-Hierarchien
• Grundlegende Idee: Komponenten enthalten wiederum Komponenten• übersichtlich• leicht austauschbar• Komponente ist verantwortlich für ihre "Kinder"
(z.B. Anordnung und Größe aller Kinder bestimmen)
• Beispiel: Komponenten-Baum für die EinfachesGUI (vereinfacht)
EinfacheGUI
ContentPane
b (JButton)l (JLabel)
...
GUI und Ereignisse
744
Strukturieren von Fenstern
Ziel: Fenster aus kleineren Gruppen zusammensetzen• Übersichtliche Gestaltung• Wiederverwendung: Code wird nicht mehrmals geschrieben
Lösung: Container (für Komponenten)
• Beispiel eines Containers: JPanel• Container mit Zeichenfläche• faßt Komponenten zusammen zu einer Einheit• ordnet diese in seinem Zeichenbereich an
Container und Layout
745
JPanels bei der BankautomatGUI Container und Layout
746
Beispiel: JPanel für PIN-Eingabeimport javax.swing.*;import java.awt.*;
public class PINPanel extends JPanel {
public PINPanel() {setLayout(null);
JLabel pinLabel = new JLabel();pinLabel.setText("PIN");pinLabel.setBounds(10,5,50,20);add(pinLabel);
JPasswordField pinField = new JPasswordField();pinField.setBounds(100,5,150,20);add(pinField);
}}
Container und Layout
747
Beispiel: JPanel für PIN-Eingabe
public static void main (String[] args) {
JFrame f= new JFrame();f.setBounds(0,0,300,70);
PINPanel p= new PINPanel();
f.getContentPane().add(p);f.setVisible( true );
}
Das JFrame:
Container und Layout
748
Weitere Container
Es gibt weitere Container in Swing:• Toplevel-Container:
• JFrame Fenster mit Rahmen, Titelzeile mit Buttons• JApplet Fenster für Darstellung im Web-Browser• JDialog kurzzeitig erscheinendes Fenster, um Mitteilungen an den
Benutzer und Reaktionen des Benutzers abzufragen
• Allgemeine Container (Auswahl)
JScrollPane JSplitPane JTabbedPane
Container und Layout
749
Container: Dialogfenster
• Aufteilung des Dialogfensters• Icon• Text-Botschaft• Knopf-Leiste
• abhängig• gehört zu einem Toplevel-Container,
der nach Dialogende aktiviert wird
• Arten von Dialogen:• Bestätigungs-Dialoge Frage mit Ja/Nein/Abbruch• Eingabe-Dialoge Text, Eingabefeld und "Ok"• Nachricht-Dialoge Text und "Ok"• Auswahl-Dialoge Text mit frei beschrifteten Knöpfen
Container und Layout
750
Beispiel: Bestätigungs-Dialog
//das Fenster, das am Dialogende aktiviert wird
JFrame f = new JFrame();
JOptionPane.showConfirmDialog(f,"Möchten Sie wirklich alle Daten löschen?","Warnung",JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.WARNING_MESSAGE
);
Container und Layout
751
Vererbung bei Containern
Ziel: Alle Container sollen dieselben grundlegendeFähigkeiten für Container-Verwaltung besitzen
Lösung: Benutze Vererbung!
• Alle Container erben von einer Klasse java.awt.Container:• Hinzufügen und Entfernen von Komponenten• Anordnen der Komponenten auf der Zeichenfläche
(Layout-Management)
Container und Layout
752
Container: Vererbungshierarchie
com.sun.java.swing
java.awt
JComponent
(java.applet)
JFrame
java.awt.Frame
JDialog
java.awt.Dialog
JWindow
java.awt.Window
java.awt.Window
JApplet
java.applet.Applet
java.awt.Panel
java.awt.Container
java.awt.Component
java.lang.Object
Container und Layout
753
Vererbung bei Komponenten
Ziel: gleiche Fähigkeiten für alle Swing-Komponentenbereitstellen, dabei Code wiederverwenden
Lösung: Benutze Vererbung!
• Alle Swing-Komponenten erben von einer Klasse JComponent:– Behandlung von Tastatureingaben– Rahmen
– Accessibility, Lokalisation (Datum, Währung,...), Tooltips
• Analog können neue, eigene Klassen von beliebigen Swing-Komponentenerben und diese ebenfalls um neue Fähigkeiten erweitern
Container und Layout
754
• Mutter (fast) aller GUI-Klassen– Ausnahme: Toplevel-Container
• leichtgewichtig• vererbt an alle Komponenten:
– (z.B. frei wählbares Look&Feel)
• ist ein Container und kanndamit andere Komponenten enthalten.
• in der Enthaltensein-Hierarchie stetsunterhalb eines Toplevel-Container(benutzt dessen Zeichenfläche)
javax.swing.JComponent
javax.swing.JComponent
java.awt.Container
java.awt.Component
java.lang.Object
755
Erweitern von Swing-Komponenten
Ziel: Neue Klassen von bestehenden Swing-Kom-ponenten ableiten und neue Fähigkeiten hinzu-fügen:z.B. neuer Schaltknopf
Lösung: Benutze Vererbung!
public class MeinEigenerButtonextends JButton{
...
}
MeinEigenerButton b= new MeinEigenerButton()
MeinEigenerButton
javax.swing.JButton
javax.swing.AbstractButton
javax.swing.JComponent
java.awt.Container
java.awt.Component
java.lang.Object
Container und Layout
756
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
757
Layout-Management
Ziel: Anordnen von Komponenten in einer anderenKomponente (Größe, Position festlegen)
Idee 1: Angabe von festen Layout-Koordinaten für jeden BestandteilNachteil: unflexibel, aufwendig, nicht nachträglich änderbar
Idee 2: Komponente „layoutet“ sich selbst.
Es gibt mehrere Layout-Strategien, die Komponenten selbstständig in einerZeichenfläche anordnen:
FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout,GridBagLayout,
Layout-Strategie auswählen: eineKomponente.setLayout( new FlowLayout())
Container und Layout
758
FlowLayout und GridLayout
• FlowLayout (Fluß)• Komponenten von links nach rechts• Zeilenumbruch am Zeilenende• Default für JPanel
• GridLayout (Gitter)• Alle Komponenten bekommen gleiche Größe• Plazierung durch Angeben von Zeile und Spalte
Container und Layout
759
Beispiel: FlowLayoutimport java.awt.*; import javax.swing.*;
public class FlowWindow extends JFrame {
public FlowWindow() {JButton b1= new JButton ("Button 1");JButton b2= new JButton ("Button 2");...
setLayout( new FlowLayout());add(b1);add(b2);...
}...
public static void main(String args[]) {FlowWindow w = new FlowWindow();w.setSize(300,300);w.setVisible( true );
}
Container und Layout
760
BoxLayout und CardLayout
• BoxLayout (Kiste)– Hängt Komponenten in 1 Spalte
untereinander
• CardLayout (Spielkarte)– Komponenten liegen
als „Spielkartenstapel“– Nur die oberste „Karte“ sichtbar– Zugriff auf oberste, unterste,
folgende, vorherige Karte
Container und Layout
761
BorderLayout und GridBagLayout
• BorderLayout (zuerst die Grenzen)– zuerst 4 Komponenten innen an die
Kanten fügen, zuletzt die verbliebeneZentralfläche mit 1 Komponenteausfüllen
– Orte: Nord, Süd, Ost, West, Center
• GridBagLayout– in Gitter anordnen, aber Größe
für jede Komponente frei wählbar– Plazierung durch Angeben
der Zeile und Spalte– mehrere Gitterplätze belegbar
Container und Layout
762
Beispiele: Auswahl eines Layout-Managers
• Viel Platz für jede einzelne Komponente– BorderLayout, GridBagLayout– im Zentrum liegt größte Komponente
• Wenige Komponenten aufgereiht– FlowLayout, BoxLayout
• Wenige Komponenten gleicher Größe– Gridlayout
• Viele Komponenten mit komplexem Layout– GridBagLayout
763
Weitere Layout-Möglichkeiten
•keinen Layout-Manager benutzen
eineKomponente.setLayout(null)
→ absolute Positionierung durch Angabe der Positions- Koordinaten (x/y)sowie Breite und Höhe für jede einzelne Komponente
JRadioButton rb = new JRadiuoButton();rb.setText("zahle aus");rb.setBounds(5,26,113,26); // (x,y, breite, höhe)
• eigenen Layout-Manager schreiben
Container und Layout
764
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
765
Frei wählbares Look&Feel
• Aussehen(Look) und Verhalten(Feel) einer GUI-Schnittstelle
• Look&Feel-Verwaltung übernimmt das Paketjavax.swing.plaf
• Schaltzentrale „UI-Manager“– Wählen eines Look&Feel:
...// zuerst das Look&Feel auf CrossPlatform einstellen
try {UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e) { }
...// jetzt erst die GUI aufbauen und anzeigen
766
Die verfügbaren Look&Feels
• Java (Metal)
• Windows
• CDE, OSF/Motif(Common Desktop Environment)
• Apple Macintosh
767
Look&Feel Detail• Jede Klasse „J...“ hat in javax.swing.plaf eine Klasse „...UI“ (Delegate)
– z.B. die Klasse „JButton“ duch „ButtonUI“.– Ausnahme: Toplevel-Container (JFrame etc.) haben stets Windows-Look&Feel,
weil sie schwergewichtig sind
• Delegate kennt für alle Look&Feels, in denen die Klasse gezeichnet werdenkann, die konkreten API‘s– In jedem API‘s ist eine Klasse bereitgestellt, mit der die sichtbare Klasse sich
zeichnen kann.z.B. „MetalButton“, „WindowsButton“, etc.
• Zeichnen– Für ein Objekt holt beim UI-Manager den Delegate. Von diesem Delegate kann
für das aktuell verwendete Look&Feel zu der Klasse verzweigt werden, die fürdas Zeichnen in diesem Look&Feel sorgt.
768
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
769
Das MVC-Modell• Model-View-Controller (MVC) ist eines der bekanntesten
Entwurfsmuster
• Ein Entwurfsmuster ist ein bewährter Lösungsansatz• MVC trennt Datenhaltung von Datendarstellung
– Modell hält Daten einer Anwendung– View für graphische Repräsentation der Daten– Controller übersetzt Benutzereingaben im View
in Änderungen am Zustand des Modells
770
MVC-Beispiel
a b cx 60 30 10y 50 30 20z 80 10 20
window window window
A B C
A
BC
a=50%b=30%c=20%
change notification
requests, modifications
771
MVC - Model
Das Model enthält den funktionalen Anwendungskern.Es kapselt die enstprechenden Daten und bietet Operationen an.Diese werden vom Controller aufgerufen.Zusätzlich bietet das Model Operationen zum Zugriff auf Daten, die die
Views brauchen, um Daten abzufragen.Das Model verwaltet die abhängigen Komponenten.Alle Ansichten und einige Controller (diejenigen, die mit Views
zusammenhängen, von denen Änderungen veranlaßt werden) lassensich beim Model registrieren.
772
MVC - View
Views präsentieren dem Anwender Informationen.Jede View definiert eine Aktualisierungsoperation, die vom
Änderungsmechanismus des Models aufgerufen wird.Diese Änderungsoperation ermittelt die anzuzeigenden Werte und zeigt
sie an.Während der Initialisierung werden alle Views mit dem Model assoziiert.Jede View erzeugt eine Controller-Komponente (1:1-Beziehung).
773
MVC - Controller
Ein Controller-Objekt akzeptiert Bedieneingaben als Ereignisse.Ereignisse werden in Anforderungen an das Model oder die assoziierte
View übersetzt.Wenn das Verhalten eines Controllers vom Zustand des Models abhängt,
läßt sich der Controller beim Mechanismus zur Benachrichtigung überÄnderungen registrieren und implementiert eineAktualisierungsoperation (z.B. nötig, wenn eine Änderung des Modelseinen Menüeintrag aktiviert oder deaktiviert).
774
Das MVC-Modell
• Varianten
– Vollständige Entkopplung von Modell und View
– Einseitige Abkopplung des View• Modell kennt seine Views direkt• Views müssen Controller benutzen
(düfen Modell nicht direkt manipulieren)
775
Das MVC-Modell: Diskussion
• Vorteile– View leicht änderbar– Wiederverwendung durch Entkopplung– Modell mit mehreren Darstellungen– Views sind schachtelbar
(schwer, wenn Modelldaten und View vermischt sind).– Controller (zur Laufzeit) änderbar
• Z.B. View „abschalten“: Controller, der alle Eingabeereignisse ignoriert
• Nachteile– Kleinere, einfache Anwendungen werden unnötig aufgeblasen.– Die Trennung von Controller und View kann schwierig sein.
776
Ereignisse
• Programme ohne GUI haben klaren Programmablauf
• Programme mit GUI sind ereignisgesteuert
– Aktionen des Benutzers erzeugen Ereignisse(Tastaturanschläge, Mausklicks, Mausbewegungen etc.)
Problem: GUI kann nicht vorhersehen, was Benutzer tun wird.
Idee: GUI wartet auf Aktionen des BenutzersKomponenten erzeugen Ereignisse(Maus, Tastatur,...)
777
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
778
Benutzer-EreignisseProblem: GUI kann nicht vorhersehen, was Benutzer tun wird.Idee: GUI wartet auf Aktionen des Benutzers
Komponenten erzeugen Ereignisse (Maus, Tastatur,...)
• Ereignis-Objekte (erben von java.util.EventObject )• stellen bestimmte Ereignisse dar (Interaktion des Benutzers)
• Ereignis-Auslöser-Objekte• lösen Ereignisse aus (in der Regel graphische Elemente)
• Ereignis-Lauscher-Objekte (EventListener -Objekte):• melden sich bei Auslöser-Objekten an,• werden bei Ereignissen benachrichtigt• stellen für Behandlung der Ereignisse passende Methoden bereit• implementieren EventListener -Schnittstellen• bilden die Schnittstelle zur Anwendungsfunktionalität!
GUI und Ereignisse
779
Beispiel: Mausklicks
Ereignis: Benutzer drückt Maustaste über einem Schaltknopf
Reaktion: Schaltknopf erzeugt Ereignis-Objektnew java.awt.event.ActionEvent
• Schaltknopf benachrichtigt alle registrierten Listener und
• ruft dort die passende Listener-Methode auf:
• Listener muß Schnittstelle ActionListener implementierenactionPerformed(ActionEvent e)
• Jede „zuhörende“ Klasse kann die Methode beliebig implementieren
• Jede Klasse hält Methoden für alle interessierenden Ereignisarten bereit
GUI und Ereignisse
780
Beispiel (1/2)Ziel: Button mit wechselnder Aufschriftimport java.awt.event.*;import javax.swing.*;
public class Wechselbutton extends JButton {public Wechselbutton (String text){
super(text);}public void wechsle() {
if (this.getText().equals("Drück mich!")){this.setText("Nochmal...");} else {this.setText("Drück mich!");}
}}public class WechselbuttonFrame extends JFrame {
private Wechselbutton b;public WechselbuttonFrame(Hoerer h){
b = new Wechselbutton("Drück mich!");getContentPane().add(b);b.addActionListener(h);
}
}
GUI und Ereignisse
781
Beispiel (2/2)
import javax.swing.*;import java.awt.event.*;public class Hoerer implements ActionListener {
public void actionPerformed(ActionEvent e){Wechselbutton but=(Wechselbutton) e.getSource();but.wechsle();
}}
public class Testumgebung {public static void main(String[] args) {
Hoerer h = new Hoerer();WechselbuttonFrame wbf = new WechselbuttonFrame(h);wbf.setSize(200,50);wbf.setVisible(true);
}}
GUI und Ereignisse
782
Ereignis-Objekt
• Ein Ereignis ist ein Objekt
• in java.util.EventObjekt , java.awt.Event oderjavax.swing.event
• enthält
– auslösende Quelle (z.B. Button)
– Nachricht (z.B. „Maustaste 1 wurde gedrückt“)
Event-Quelle(Button) Event
Listener
Event
EventListener
783
Arten von Ereignissen
Basis-Ereignisse und semantische Ereignisse
Verwendung Ereignisart Schnittstelle Lauscher-Methoden
BasisereignisseTastaturereignisse KeyEvent KeyListener keyPressed, keyReleasedMausereignisse MouseEvent MouseListener mouseClicked,-PressedKomponentenereign. ComponentEvent ComponentList. componentHidden, -movedContainerereignisse ContainerEvent ContainerListener componentAdded, -RemovedFokusereignisse FocusEvent FocusListener focusGained, focusLostFensterereignisse WindowEvent WindowListener windowIconified, -Opened
Semantische EreignisseAktion des Benutzers ActionEvent ActionListener actionPerformedTextereignisse TextEvent TextListener textValueChangedAuswählen (Checkb.) ItemEvent ItemListener itemStateChangedWertmanipulation AdjustmentEvent AdjustmentListener adjustmentValueChanged
GUI und Ereignisse
784
Zugehörigkeit von Listener-Interfaces zu Kompon.Ausschnitt (siehe JDK-Dokumentation und Tutorial)
Komponente ActionListener
ChangeListener
ItemListener
WindowListener
JFrame X
JDialog X
JScrollPane X
JButton X X X
JComboBox X X
JSlider X
JTextField X
JFileChooser X
785
Methoden der Listener-Interfaces:ComponentListener:
void componentHidden(ComponentEvent e)
void componentMoved(ComponentEvent e)
void componentResized(ComponentEvent e)
void componentShown(ComponentEvent e)
FocusListener:void focusGained(FocusEvent e)
void focusLost(FocusEvent e)
KeyListener:keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
786
Methoden der Listener-Interfaces:MouseListener:
void mouseClicked(MouseEvent e)
void mouseEntered(MouseEvent e)
void mouseExited(MouseEvent e)
void mousePressed(MouseEvent e)
void mouseReleased(MouseEvent e)
MouseMotionListener:void mouseDragged(MouseEvent e)
void mouseMoved(MouseEvent e)
ActionListener:void actionPerformed(ActionEvent e)
787
Methoden der Listener-Interfaces:ChangeListener:
void stateChanged(ChangeEvent e)
ItemListener:void itemStateChanged(ItemEvent e)
WindowListener:void windowActivated(WindowEvent e)
void windowClosed(WindowEvent e)
void windowClosing(WindowEvent e)
void windowDeactivated(WindowEvent e)
void windowDeiconified(WindowEvent e)
void windowIconified(WindowEvent e)
void windowOpened(WindowEvent e)
788
Listener implementieren:
• Listener-Interfaces beinhalten Methoden, an die Eventsweitergeleitet werden.– Beispiel: interface FocusListener {
void focusGained(FocusEvent e);void focusLost(FocusEvent e);
}
• Swing-Komponenten können nur Ereignisse an Objektebestimmte Listener-Interfaces weiterleiten. EntsprechendeObjekte werden mit add...Listener() bei der Swing-Komponente registriert. Hier:
addFocusListener(...);
789
Benutzen von anonymen Klassenimport javax.swing.*; import java.awt.event.*;public class Wechselbutton2 extends JFrame {
public Wechselbutton2(){JButton b= new JButton("Drück mich!");getContentPane().add(b);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){JButton but=(JButton) e.getSource();if (but.getText().equals("Drück mich!")){
but.setText("Nochmal...");} else {
but.setText("Drück mich!");}
}}
);}
}
GUI und Ereignisse
Wird von
Programmier
umgebungen
generiert!
790
Benutzen von Anonymen Klassen...
public static void main(String[] args) {Wechselbutton2 wb2 = new Wechselbutton2();wb2.setSize(200,50);wb2.setVisible( true );
}
GUI und Ereignisse
791
1 Motivation, Historie Java und Guis, AWT, SWING, JFC
2 Einfaches Bildschirmfenster mit elementaren Komponenten3 Komponenten zusammenfassen in Containern (Übersicht)
• JPanel• alle Container erben von Container• alle Komponenten erben von JComponent
4 Layout von Containern (Komponenten-Anordnung, -Größe)FlowLayout, GridLayout, BoxLayout,CardLayout, BorderLayout, GridBagLayout
5 Pluggable Look&Feel (inkl. Vorführung/Demo Swing-Set zur PräsentationGUI-Elemente)
6 Allgemeine Betrachtung: Interaktion, MVC-Konzept, Ereignisse,7 Behandlung von Benutzer-Ereignissen (Mausklicks, ...)8 Menüs für Funktionsauswahl
792
Menüs
Ziel: Menüs an Bildschirm-Fenstern- Gruppieren von Funktionen in Menüs
- Anordnen aller Menüs in 1 Menüleiste am oberen Fensterrand- Anbinden an Methoden über Ereignisse (analog Knöpfe, etc.)
Menüs und Applets
793
Bestandteile eines Menüsystems
• Menüleiste• nimmt Menüs auf
• Trennlinien• Popup-Menü
• Menu-Elemente• Menüeinträge• Radiobuttons• Checkbuttons• Kommando-Sammlung (JMenu)
(ein bzw. mehrere Kommandos,verschachtelte Menüs)
Menüs
794
Vererbungshierarchie für Menüs
Alle Menu-Elemente sind Container und Komponenten
JMenuBar JPopupMenu
JMenu JCheckBoxMenuItem JRadioButtonMenuItem
JMenuItem
JAbstractButton JSeparator
JComponent
java.awt.Container
java.awt.Component
Menüs
795
Beispiel: Menüleiste
public class BankautomatGUI extends JFrame {public BankautomatGUI(String s) {
super (s);JMenuBar mbar = new JMenuBar();setJMenuBar(mbar);JMenu dateiMenu = new JMenu(“Datei“);mbar.add(dateiMenu);JMenu bearbeitenMenu = new JMenu("Bearbeiten");mbar.add(bearbeitenMenu);JMenuItem editierenItem = new JMenuItem();editierenItem.setText("Editieren");bearbeitenMenu.add(editierenItem);JMenuItem anschauenItem = new JMenuItem();anschauenItem.setText("Anschauen");bearbeitenMenu.add(anschauenItem);setJMenuBar(mbar);...
Menüs
796
Look&Feel Detail• Jede Klasse „J...“ hat in javax.swing.plaf eine Klasse „...UI“ (Delegate)
– z.B. die Klasse „JButton“ duch „ButtonUI“.– Ausnahme: Toplevel-Container (JFrame etc.) haben stets Windows-Look&Feel,
weil sie schwergewichtig sind
• Delegate kennt für alle Look&Feels, in denen die Klasse gezeichnet werdenkann, die konkreten API‘s
– In jedem API‘s ist eine Klasse bereitgestellt, mit der die sichtbare Klasse sichzeichnen kann.z.B. „MetalButton“, „WindowsButton“, etc.
• Zeichnen– Für ein Objekt holt beim UI-Manager den Delegate. Von diesem Delegate kann
für das aktuell verwendete Look&Feel zu der Klasse verzweigt werden, die fürdas Zeichnen in diesem Look&Feel sorgt.
Kapitel 20
Applets (java.applet)
798
java.applet Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java
• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
799
Application / Applet / Servlet
• Application– Java-Programm, welches (in der Regel) alle Systemresourcen nutzen
darf– Abgrenzung von Applets mit eingeschränkten Rechten
• Applet– Java Programm, welches innerhalb von Web-Browsern lauffähig ist
• Netscape Navigator• HotJava von Sun Microsystems• InternetExplorer von Microsoft
– Es gibt eingeschränkte Rechte, z.B. darf nicht ohne Erlaubnis desAdministrators auf lokales Dateisystem zugegriffen werden
• Servlet– Serverprogramm, mit dem Applets eine Verbindung aufnehmen können– Ersetzt CGI-Scripts, die kein "Gedächnis" haben
800
Applets
Ziel:Applet für Bankautomatzur Anzeige im Web-Browserbzw. im AppletViewer
Menüs und Applets
801
Applets
• Klasse "com.sun.java.swing.JApplet"• Applets:
– Programmcode wird vom Web-Browser angefordert (per URL)– Web-Server verschickt Programmcode zum Web-Browser– Web-Browser führt Programmcode aus (eigene Java Virtual Machine)
• Lebenszyklus eines Applets:applet.init() Selbstinitialisierung automatisch nach dem
Laden aufgerufen
applet.start() Starten automatisch nach demInitialisieren
applet.stop( ) Beenden beim Verlassen der Web-Seiteim Browser
applet.destroy() Löschung für Garbage Collection
Menüs und Applets
802
Toplevel-Container: Applet
• Konstruktion einer Applet-KlassePublic class HelloApp extends JApplet...
• Erzeugung eines JAppletHelloApp applet=new HelloApp();
• Festlegen eines Layouts für das Fensterapplet.setLayout (einLayoutManager);
• Anheften einer Menüzeile am oberen Fensterrandapplet.setJMenuBar(einJMenubar);
• Hinzufügen von darzustellenden JComponentsapplet.getContentPane().add(new JButton(„Swing!“));
803
Das java.applet - Package
Appletinit();
start();
stop();
destroy();
getAppletInfo();
getParameterInfo();
AppletContextDefinition von Interaktionsschnittstellen
AppletStubinterne Schnittstelle zur Implementierung eines Appletviewers
AudioClip
804
Beispiel: "Hello World" - Applet
import java.awt.*;
import com.sun.java.swing.applet.*;
public class HelloApp extends JApplet {
public void init() {
setSize(200,100);
JLabel l= new JLabel();
l.setText("Hello World !");
this .getContentPane().add(l);
}
}
Menüs und Applets
805
Ausführen eines Applets
Zwei Möglichkeiten:
• AppletViewer vom JDK benutzen
• Aufruf des Applets in Web-Seite einbetten– <APPLET> Tag:
<APPLET CODE=HelloApp.classWIDTH=500HEIGTH=300NAME=„HelloWorld“>
</APPLET>
Menüs und Applets
806
Parameterübergabe an Applets
• Übergabe von der HTML-Seite zum AppletHTML: <PARAM> TagsApplet: getParameter() - Methode
• Lesen aller Parameter innerhalb des <APPLET> Tags möglich• Parameter enthält immer einen Namen und einen Wert
<PARAM name=„Name“ value=„MyApplet“>
• Anzeigen aller einlesbaren Parameter:String info[][] = getParameterInfo();
• Lesen eines Parameters:String titel = getParameter(„Name“);
807
Sicherheit bei Applets
• Verboten– Herstellen von Netzwerkverbindungen (außer zum Host)– Lesen und Schreiben von Dateien auf dem Host– Starten von Programmen auf dem Host– Auslesen von sicheren System-Einstellungen auf dem Client– Laden von Klassenbibliotheken– Definieren von native Methoden
• Erlaubt– Herstellen von Netzwerkverbindungen zum Host– Aufruf anderer Webseiten (per URL)– Abspielen von Sounds– Kommunikation mit weiteren Applets auf dem Client
Menüs und Applets
808
(Standard)-Sicherheitsrestriktionen von Applets
• Kein Überschreiben von Standard-Klassenbibliotheken undDefinieren von native Methoden
• Kein Lesen und Schreiben von Dateien auf dem Host• Kein Herstellen von Netzwerkverbindungen
– außer zum Host, von dem es geladen wurde
• Kein Starten von Programmen auf dem Host• Kein Auslesen von sicheren System-Einstellungen• Unterschiedliches Aussehen von Applet-Fenstern und
Anwendungsfenstern
809
Was können Applets?
• Aufbau von Netzwerkverbindungen zum Host
• einfaches Aufrufen anderer Web-Seiten
showDocument(„http://www.javasoft.com/index.html“);
• Applets aus dem lokalen Filesystem unterliegen nicht den
Sicherheitsrestriktionen
• Abspielen von Sounds
• Kommunikation mit anderen Applets
• Für signierte Applets können Sicherheitsrestriktionen gelockert
werden
Kapitel 21
Threads
811
Multithreading Die Java Klassenbibliotheken
• java.applet (JDK 1.0) Java-Applets (für WWW-Browser)• java.awt (JDK 1.0) AWT-Komponenten
• java.beans (JDK 1.1) Beans-Development• java.io (JDK 1.0) Input / Output / Datenströme• java.lang (JDK 1.0) Basispackage für Java• java.math (JDK 1.1) Zahlen großer Genauigkeit• java.rmi (JDK 1.1) Remote Method Invocation• java.security (JDK 1.1) Sicherheit, Kryptographie
• java.sql (JDK 1.1) JDBC-Paket• java.util (JDK 1.0) Verschiedene Hilfsklassen• javax.swing (JDK 1.2) Swing-Komponenten
Für JDK 1.1.x: com.sun.java.swing
• org.omg.CORBA (JDK 1.2) CORBA-Schnittstelle
812
Threads
• Threads können auf einer Maschine mit nur einem Prozessorablaufen und sich dabei aufführen, als ob sie eigene Prozessewären.
• Ihr Unterschied zu wirklich eigenständigen Prozessen ist, daßsie aus einem Hauptprogramm erzeugt werden.
• Ein Thread modelliert Objekte, die innerhalb einesumgebenden Prozesses einen eigenen Kontrollfluß haben.
• Der Zusammenhang mit anderen Threads ergibt sich durch dieNutzung gemeinsamer Ressourcen (Objekte, CPU-Zeit, Zugriffauf Datenbanken).
813
Multithreading
• Multithreading bedeutet:– Programmpfad wird in unterschiedliche Richtungen verzweigt, diese
laufen parallel.– Ein Thread hier ein Programmpfad, wird auch Ausführungskontext oder
leichtgewichtiger Prozeß genannt.– Multithreading bedeutet nun, dass es möglich ist, mehrere Threads
parallel laufen zu lassen (bei nur einem Prozessor ist dies natürlich leineechte Parallelität).
814
Multithreading
• Probleme:– Konkurrierende Threads benutzen gleiche Ressourcen und Daten
=> Bei Zugriff auf gemeinsam genutzte Ressourcen muß Schutzeingreifen (nur ein Thread hat den Monitor)
– Threads, die mehrere Resourcen gleichzeitig benötigen, können sichgegenseitig blockieren (Deadlock), indem sie jeweils eine Ressourcefesthalten und auf die anderen warten.
– Nicht jede Virtual Machine verteilt CPU-Zeit automatisch gerecht(Es gibt Timeslicing-fähige und -unfähige Systeme)=> Laufende Threads sollten auch anderen eine Chance geben
– Mögliche Zustände oft schwer verständlich, da Parellelität nicht sehrintuitiv verständlich
815
Beispiel
class AddThread extends Thread{
public void run(){
for(int i=0;i<10;i++){
MyThreadExample.count++;
System.out.print("Add ");
System.out.println(MyThreadExample.count);
}
}
}
816
Beispiel
class SubtractThread extends Thread{
public void run(){
for(int i=0;i<10;i++){
MyThreadExample.count--;
System.out.print("Subtract ");
System.out.println(MyThreadExample.count);
}
}
}
817
Beispiel
class MyThreadExample{public static int count=0;
public static void main(String args[]){AddThread a = new AddThread();SubtractThread b = new subtractThread();a.start();b.start();
}}
818
Beispiel
Mögliches Ergebnis
Add 1
Add 2
Add 3
Add 4
Add 5
Subtract 5
Subtract Add 4
4
Subtract 3
Subtract 4
Subtract 2
Subtract Add 1
Add 2
1
Subtract 2
Subtract 1
Subtract Add 0
Add 0
Subtract 0
1
819
Thread / Runnable
• Ein Thread wird immer in einer run-Methode gestartet– public void run()
– Diese Methode muß von einer Klasse implementiert werden, dessenObjekt sich mit einem eigenen Thread ablösen möchte
– Bei Start des Threads wird die run -Methode vom System automatischaufgerufen (nicht selbst aufrufen!)
• Ein Threadfähige Klasse kann durch zwei Möglichkeitendefiniert werden:A) Erben von der Klasse Thread , hier muß die run() -Methode der
Klasse Thread überschrieben werdenB) Implementieren des Interfaces Runnable , hier muß die run() -
Methode des Interfaces implementiert werden
820
java.lang
• Threadfähigkeit einer Klasse kann auf zwei Arten erreichtwerden– erben von der Klasse Thread
– implementieren des Interfaces Runnable
Die Java Klassenbibliotheken
Thread
MyClass
RunnableMyClass
821
java.lang
• in beiden Fällen wird die Methode run() implementiert
– im erbenden Fall wird sie überschrieben
class MyClass extends Thread {
public void run() {
// hier wird run() überschrieben
}}
Die Java Klassenbibliotheken
Thread
MyClass
822
java.lang
• in beiden Fällen wird die Methode run() implementiert
– im Interface Fall wird sie implementiert
class MyClass implements Runnable {
public void run() {
// hier wird run() implementiert
}}
Die Java Klassenbibliotheken
RunnableMyClass
823
Using the Runnable Interface
class AddThread extends SomeClass implements Runnable{
public void run(){
for(int i=0;i<10;i++) SyncThread.incCount();
}
}
...
// Where the thread shall be started
// a new Thread Object is created
AddThread a = new AddThread();
Thread this_is_the_Thread = new Thread(a);
this_is_the_Thread.start();
...
824
Thread / Runnable
• Erzeugen eines Objektes, welches später einen eigenenProgrammpfad bekommen soll:A) Bei Unterklasse von Thread (z. B. MeinThread extends Thread )
kann einfach durch new das startfähige Objekt erzeugt werden(hier: Thread leicht = new MeinThread() )
B) Bei Implementierung von Runnable(z. B. MeineKlasse implements Runnable ) wird durchMeineKlass e a = new MeineKlasse(); ein Objekt erzeugt unddurchnew Thread dann das startfähige Objekt erzeugt(hier: Thread leicht = new Thread(a) )
• Starten des Threads:– Durch die start() -Methode von Thread wird der Thread gestartet:
leicht.start();
825
Warum zwei Möglichkeiten?
• Einfache Möglichkeit ist, von Thread abzuleiten=> einfacheres Verständnis
• Aber:– Java kennt keine Mehrfachvererbung von Klassen, jedoch
Mehrfachvererbung von Interfaces– Es ist Wünschenswert, auch Unterklassen multithreadingfähig zu
machen
=> Hier bleibt nur die Möglichkeit, Runnable zu implementieren
826
Methoden von Thread
• Konstruktoren:– public Thread()
• Muß von abgeleiteter Klasse durch super() aufgerufen werden
– public Thread(String name)• Muß von abgeleiteter Klasse durch super(name) aufgerufen werden
• Dem Thread wird hier ein Name gegeben
– public Thread(Runnable target)• Muß direkt aufgerufen werden, um Threads über das Runnable -Interface zu
definieren
• Methoden:– public native synchronized void start()
• Startet den Thread. Die Virtuelle Maschine startet die run() -Methode in eigenemProgrammpfad
• synchronized ist neues Schlüsselwort, später mehr
827
Methoden von Thread
• Methoden:– public static native Thread currentThread()
• Klassenmethode, um den aktuell laufenden Thread zu ermitteln
– public static native void yield()• Aufforderung, eventuell andere wartende Threads zum Zuge kommen zu lassen
– public static native void sleep(long millis)throws InterruptedException
• Thread wartet angegebene Zeit. Andere Threads kommen zum Zuge, sofern sie nichtdurch belegte Resourcen blockiert sind
– public final void setPriority(int newPriority)• Legt die Priorität des Threads fest. Threads höherer Priorität laufen bevorzugt
– public final String getName()• Gibt den Namen des Threads zurück
828
Deaktivierung eines Threads
• Methoden:– sleep
siehe oben
– suspend
Unterbricht die Arbeit eines Prozesses
– wait
veranlaßt, daß ein Prozeß eine vorgegebene Zeit wartetvon Object ererbt
829
Aktivierung eines passiven Threads
• Methoden:– resume
Gegenstück zu suspend
– notify, notifyAll
reaktiviert wartende Prozesse (Gegenstück zu wait)von Object ererbt
830
Vernichten eines Prozesses
• Methoden:– stop
anomale und sofortige Beendigung eines aktiven oder gerade erzeugtenProzesses (mit Aufräumarbeiten)
– destroy
wie stop aber ohne Aufräumarbeiten
831
Zustandsübergänge von Threads
832
Ein neuer Thread (Zustand new), der noch nicht ausgeführtwurde, erfordert vor der ersten Ausführung erst mal dieZuweisung von Ressourcen (Speicher).
Dann wird er mittels der Methode start() in den Zustandrunnable überführt.
Runnable bedeutet, daß der Prozeß durchgeführt werdenkann (also aktiv werden kann). Allerdings kann nur einProzeß zu jeder Zeit aktiv sein.
Die wartenden, schlafenden, unterbrochenen Prozesse sindim Zustand blocked.
Wenn der aktive Prozeß in den Zustand blocked übergeht,dann wird ein runnable Prozeß aktiviert.
Zustandsübergänge von Threads
833
Die JVM wählt aus der Menge der runnable Prozesse dendurchzuführenden aus.
Hier gibt es Unterschiede zwischen den JVMs aufverschiedenen Plattformen.
Ein Prozeß verläßt den Zustand blocked, wenn
die Schlafperiode zu Ende geht,
er notifiziert wird (notify),
die I/O-Operation, auf die er wartet, terminiert,
wenn er per resume fortgesetzt wird.
Zustandsübergänge von Threads
834
Threads gehen in de Zustand dead über, wenn
seine run()-Methode beendet wird,seine stop()- oder destroy-Methode aufgerufen wird.
Ein dead Thread kann nicht reaktiviert werden.
Zustandsübergänge von Threads
835
Prioritäten
Jeder Thread hat eine Priorität.
Die JVM bevorzugt die Threads mit hohen Prioritäten, wennein Thread von runnable in aktiv überführt werden soll.
Threads laufen solange bis:
er die yield()-Methode aufruft,er nicht mehr runnable ist (z.B. weil er auf einen initiierten I/O warten
muß),ein Thread mit höherer Priorität runnable wird.
836
Egoistische Threads
Ein langlaufender Thread mit hoher Priorität, der kein I/Overanlaßt, kann den Prozessor dauerhaft beanspruchen.
Das ist kein Problem, wenn die JVM zeitscheiben-fähig ist.
Langlaufende Threads sollten regelmäßig sleep() oder yield()aufrufen, um auch anderen Threads Zugriff zu erlauben.
837
Monitore
Sperren sind ein Mittel, um den parallelen Zugriff aufRessourcen zu reglementieren.
Ein kritischer Abschnitt ist ein Speicherbereich, auf den immernur ein Prozeß zugreifen darf.
Eine typische Art von kritischen Abschnitten sind Variablen,diese dürfen nicht beliebig parallel gelesen und geschriebenwerden.
Es ist möglich, Bereiche zu schützen, die nur ein Thread zurZeit abarbeiten darf.
838
Monitore
Jedes Objekt besitzt genau einen Monitor,ein Thread kann nur in einen geschützten Bereich eintreten,wenn der entsprechende Monitor frei ist
Objekte, die Threads blockieren können und die Threadsnotifizieren, wenn die Bearbeitung weitergehen kann,werden Monitor genannt. Monitore realisieren Sperren.
Jedes Objekt mit einer oder mehreren synchronisiertenMethoden, wird Monitor genannt.
In einer synchronisierten Methode kann ein Thread seineSperre mittels wait() aufgeben.
839
Synchronisation
Wenn ein Objekt zu einer Klasse mit synchronisisertenMethoden gehört, dann hat es eine Schlange, in der alleThreads verwaltet werden, die die synchronized Methodeaufgerufen haben.
Aufrufende Threads kommen in diese Schlange, wenn:
sie eine synchronized Methode aufrufen, während ein anderer Threadauf das Objekt zugreift,
wenn sie in der aufgerufenen, synchronized Methode wait()aufrufen.
840
Parallelitätsregeln
Wenn 2 oder mehr Threads ein Objekt modifizieren, solltendie modifizierenden Methoden als synchronizeddeklariert werden.
Wenn eine Methode einen Thread anhalten muß, um dasObjekt selbst zu ändern, dann sollte wait() aufgerufenwerden.
Wenn eine synchronized Methode ihr Objekt ändert, dannsollten die gerade wartenden Prozesse mit notifyAll()alarmiert werden.
841
Monitorkonzept
• Es lassen sich sowohl einzelne Blöcke, als auch ganzeMethoden schützen:– Eine ganze Methode kann durch Kennzeichnung von synchronized
geschützt werden, z. B.:public synchronized int get() { ...}
– Ein Block kann durchsynchronized( ObjektName) {
...}geschützt werden. Hierbei wird der Monitor des Objektes ObjektNamebelegt.
842
Methoden der Klasse Object
• Alle Threads, die den Monitor einer Klasse bekommen wollen,werden in einer Warteliste aufgenommen. Hier greifen danndie bereits oben diskutierte Zustandsübergänge.
• Sie sind solange blockiert, bis sie geweckt werden:– Die Methode public final void notify() der Klasse Object
benachrichtigt einen Thread aus der Warteliste auf den zum Objektzugehörigen Monitor (willkürliche Auswahl)
– Die Methode public final void notifyAll() der Klasse Objectbenachrichtigt alle Threads aus der Warteliste, diese werden um denMonitor konkurrieren
843
Methoden der Klasse Object
• Monitor vorübergehend freigeben:– Mit der Methode
public final void wait() throws InterruptedExceptionwird der Monitor freigegeben und der Thread geht in Wartezustand, biser von einem anderen Thread durch notify() oder notifyAll()geweckt wird
– Nach Wecken setzt der Thread seine Arbeit an gleicher Stelle fort– Wichtig, um auf nicht freie Resourcen zu warten
=> andere Threads müssen die Chance bekommen, die Resourcenfreizugeben
844
Beispiel: Handshake-Verfahren
• Wenn Daten zwischen Threads ausgetauscht werden sollen,gibt es Synchronisationsprobleme.
• Tunnel-Klasse soll von einem Thread jeweils ein Paket Datenaufnehmen und an einen anderen Thread weitergeben
• Alle Synchronisationsprobleme sollen in dieser Klasse gelöstwerden
• Erzeuger- und Verbraucherklassen sollen in eigenem Threadlaufen
845
Handshake-Verfahren: Tunnelclass Tunnel {
private int inhalt;private boolean verfügbar = false;
public synchronized int nehmen() { // List int aus Tunnelwhile (verfügbar == false) {
try {wait();
} catch (InterruptedException e){}}verfügbar = false;notifyAll();return inhalt;
}public synchronized void geben(int wert) { // Schreibt int in Tunnel
while (verfügbar == true) {try {
wait();} catch (InterruptedException e) {}
}inhalt = wert;verfügbar = true;notifyAll();
}}
846
Handshake-Verfahren: Erzeugerclass Erzeuger extends Thread {
private Tunnel t;
public Erzeuger(Tunnel tunnel) {t = tunnel;
}
public void run() {for (int i=0; i<5; i++) {
t.geben(i);System.out.println("Erzeuger schreibt " + i);try {
Thread.sleep((int)(Math.random() * 100));} catch (InterruptedException e) {}
}}
}
847
Handshake-Verfahren: Verbraucherclass Verbraucher extends Thread {
private Tunnel t;
public Verbraucher(Tunnel tunnel) {t = tunnel;
}
public void run() {int wert = 0;for (int i=0; i<5; i++) {
wert = t.nehmen();System.out.println("Verbraucher liest " + wert);
}}
}
848
Handshake-Verfahren: StartKlasseclass StartKlasse {
public static void main(String[] args) {Tunnel t = new Tunnel();Erzeuger e = new Erzeuger(t);Verbraucher v = new Verbraucher(t);
e.start();v.start();
} Ausgabe:} Erzeuger schreibt 0
Verbraucher liest 0Verbraucher liest 1Erzeuger schreibt 1Verbraucher liest 2Erzeuger schreibt 2Verbraucher liest 3Erzeuger schreibt 3Verbraucher liest 4Erzeuger schreibt 4