Objektorientierte
Programmiersprachen (in Arbeit)
© Günter Riedewald
Die Folien sind eine Ergänzung zur
Vorlesung und nur für den internen
Gebrauch konzipiert.
Literatur
Abadi, Martin, Cardelli, Luca: A Theory of Objects
Springer, 1996
Bruce, K. B.:Foundations of Object-Oriented Programming Languages: Types and
Semantics
The MIT Press, 2002
Budd, Timothy: An Introduction to Object-Oriented Programming
Addison-Wesley, 2002
Brügge, B., Dutoit, A. H.: Objektorientierte Softwaretechnik mit UML,
Entwurfsmustern und Java
Pearson Studium, 2004
Poetzsch-Heffter, Arnd: Konzepte objektorientierter Programmierung
Springer, 2000
Diverse Literatur zu objektorientierten
Sprachen, z.B.:
Bishop, Judith: Java lernen
Addison-Wesley, 2001
Deitel, H. M., Deitel, P. J.: C++ How to Program
Prentice Hall, 1994
Goldberg, A., Robson, D.: Smalltalk-80: The Language
Addison-Wesley, 1989
Gore, Jacob: Object Structures
Building Object-Oriented Software Components with Eiffel
Addison-Wesley, 1996
Kratzer, Klaus Peter: ADA Eine Einführung für Programmierer
Hanser, 1996
Lamprecht, G.: SIMULA – Einführung in die Programmiersprache
Vieweg, 1988
Schiedermeier, R.: Programmieren mit Java
Eine methodische Einführung
Pearson Studium, 2005
Bücher über Konzepte von
Programmiersprachen, z.B.:
Louden, Kenneth, C.: Programmiersprachen
Grundlagen, Konzepte, Entwurf
International Thomson Publishing, 1994
Objektorientierte Prototypsprachen
Blaschek, Günther:
Object-Oriented Programming with Prototypes
Springer, 1994
Entwurfsmuster in OOPS
Gamma, E., Helm, R., Johnson, R., Vlissides, J.:
Design Pattern: Elements of Reusable Object-Oriented Software
Addison-Wesley, 1995
Beispiel:
BEGIN CLASS liste;
BEGIN INTEGER wert; REF(liste) nachf; END;
REF(liste) l;
l :- NEW liste;
l.wert := 1; l.nachf :- NEW liste;
l.nachf.wert := l.wert + 1;
END
Beispiel: komplexe Zahlen in Simula
CLASS Complex(x,y);
REAL x,y;
BEGIN
REAL re,im;
REAL PROCEDURE realpart;
BEGIN
realpart := re;
END realpart;
REAL PROCEDURE imaginarypart;
BEGIN
imaginarypart := im;
END imaginarypart;
PROCEDURE add(y); REF(Complex) y;
BEGIN
re := re + y.realpart;
im := im + y.imaginarypart;
END add;
...
comment – Initialisierungscode;
re := x;
im := y;
END Complex;
Beispiel: abstrakte Syntaxbäume arithmetischer
Ausdrücke (Kantorovič-Bäume)
Wurzel eines Teilbaumes: Operationssymbol
(codiert)
Blätter eines Teilbaums: Operanden (Konstante,
Variable, Teilbaum)
 CLASS form; BEGIN END;
form CLASS const(val); REAL val; BEGIN END;
form CLASS var(nam, val); TEXT nam; REAL val;
BEGIN END;
form CLASS triple(lop, op, rop);
REF(form) lop, rop; INTEGER op; BEGIN END;
REF(form) f, g, h;
f :- NEW const(10);
g :- NEW var(´g´, 9);
h :- NEW triple(NEW triple(f, plus, g), plus, f);
Liefert
+
+
10
10
g
Beispiel als Verbund (Record)
10.0  f
lop
op plus
rop
plus
nam ´g´  g
val 9.0
Vereinigung von Verbunden mit nichtleerer
Oberklasse - Beispiel
CLASS klasse(a,b); REAL a, b;
BEGIN REAL x, y; ... END;
klasse CLASS klasse1(c, d); REAL c, d;
BEGIN REAL u, v;
u := c + d; v := x + y;
END;
Definitionsschachtel für NEW klasse1(1, 2, 3, 4)
a 1.0
b 2.0
x w1
y w2
c 3.0
d 4.0
u 7.0
v w1+w2
Klassendefinition circle
CLASS circle(center, radius);
REF(point) center; REAL radius;
BEGIN
REAL PROCEDURE area;
BEGIN
area := pi * radius * radius;
END area;
…
END circle;
Klassendefinition rectangle
CLASS rectangle(center, width, height);
REF(point) center; REAL width, height;
BEGIN
REAL PROCEDURE area;
BEGIN
area := width * height;
END area;
…
END rectangle;
Oberklasse closedFigure
CLASS closedFigure(center);
REF(point) center;
VIRTUAL:
REAL PROCEDURE area;
BEGIN
…
END closedFigure;
Neudefinition von circle
closedFigure CLASS circle(radius);
REAL radius;
BEGIN
REAL PROCEDURE area;
BEGIN
area := pi * radius * radius;
END area;
…
END circle;
Neudefinition von rectangle
closedFigure CLASS rectangle(width, height);
REAL width, height;
BEGIN
REAL PROCEDURE area;
BEGIN
area := width * height;
END area;
…
END rectangle;
Programmstück
REF(point) x,y; REF(closedFigure) f; REF(rectangle) s; REF(circle) c;
x :- NEW point(0.0,0.0);
y :- NEW point(1.0,-1.0);
s :- NEW rectangle(x,1.0,1.0);
c :- NEW circle(y,1.0);
f :-s;
f.area;
f :-c;
f.area;
Allgemeine Beziehungen zwischen Objekten
Ein Objekt X benutzt ein Objekt Y, wenn
- eine Methode von X eine Nachricht an Y schickt:
mX: ...Y.n ...
- Eine Methode von X das Objekt Y
a) erzeugt: mX: ...GY ... (Generator G)
b) als Parameter übergeben bekommt: X.mX(Y...)
c) als Ergebnis zurückgibt: mX: ... return Y
Hat-ein-Beziehung:
Ein Objekt X hat ein Attribut, das das Objekt Y oder eine
Referenz darauf als Wert hat.
Teil-von-Beziehung: Spezialfall der Hat-ein-Beziehung,
wobei Y als Teil von X betrachtet wird.
Erreichbarkeitsbeziehung: transitive Hülle der Hat-einBeziehung
Ist-ein-Beziehung: Jedes Objekt o einer Klasse U ist
gleichzeitig Objekt einer Oberklasse zu u.
Beispiel: Personenstruktur an der Uni
Studenten: Name, Geburtsdatum, Adresse, Immatrikulationsdatum,
Immatrikulationsnummer, Fachbereich, Studiengang, Fachsemester,
wahrscheinliches Abschlussdatum
Wissenschaftliche Mitarbeiter: Name, Geburtsdatum, Adresse,
Einstellungsdatum, Beschäftigungsnummer, befristet/unbefristet,
wahrscheinliches Beschäftigungsende, Fachbereich
Nichtwissenschaftliche Mitarbeiter: Name, Geburtsdatum, Adresse,
Einstellungsdatum, Beschäftigungsnummer, Fachbereich
Hochschullehrer: Name, Geburtsdatum, Adresse, Berufungsdatum,
Beschäftigungsnummer, Kategorie, Fachbereich
Person
Name, Geburtsdatum, Adresse, Beschäftigungsbeginn, FB
Student
+ Imm.-Nr., Studiengang,
Fachsemester, wahrsch.
Abschlußdatum
Wissen. Mitarbeiter
+ Befristung, wahr.
Beschäftigungsende
Angestellte
+ Beschäftigungsnr.
Nichtwiss. Mit.
HSL
+ Kategorie
Polymorphismus
Einteilung nach Stansifer:
Überladung
ad hoc
implizite Umwandlung
Polymorphismus
Untertyp
universell
parametrisiert
Polymorphismus nach Programmiersprachen:
1. Nichtobjektorientiert:
- Überladene Operatoren: gleicher Name,
unterschiedliche Operation
- Polymorphe Operatoren: gleicher Name,
gleiche Operation auf unterschiedlichen
Datentypen
- Implizite Umwandlung: automatische
Typkonvertierung von Operanden gemäß
syntaktischer Position
- Einschließender Polymorphismus: Operation für
gegebenen Typ schließt auch Daten eines abgeleiteten Typs
ein
- Parametrischer Polymorphismus: Operation für
unterschiedliche Datentypen mit Typparameter
2. Objektorientiert
- Gleiche Nachricht an Objekte unterschiedlicher Klassen
löst unterschiedliche Operationen aus
- Gleicher Variabler können Objekte unterschiedlicher
Typen eines „Vererbungspfades“ zugewiesen werden 
unterschiedliche Operationen bei gleicher Nachricht
(dynamisches Binden)
Erscheinungsformen in OOPS:
• Ad hoc:
a) Gleicher Name für Methoden in voneinander
unabhängigen Klassen
A
B
a.m
m
m
a
b
b.m
b) Gleicher Name für zwei unterschiedliche
Methoden in gleicher Klasse (mit
unterschiedlicher Signatur)
c) Überschriebene geerbte Operation
(Konkretisierung bei Übergang von abstrakter zu
konkreter Klasse, Verfeinerung, völlig neue
Implementation)
• Einschließender Polymorphismus
(Vererbungspolymorphismus): Eine in einer
Oberklasse definierte Methode wird auch auf die
Objekte der abgeleiteten Klassen angewendet.
• Typparameter in generischen Einheiten
Statisches und dynamisches Binden
Kovarianz und Kontravarianz
Binden:
Hier: Zuordnung von Methoden (Operationen) zu
Methodennamen (Operationssymbolen)
Statisches Binden: Binden zur Übersetzungszeit
Dynamisches Binden: Binden zur Laufzeit
Beispiel: Kovarianz, Kontravarianz
Tier
TIER
Ok
OK
F(Tier t)
Katze KATZE
HUND Hund
Uk
UK
F(Katze t)
Ok einObjekt = NEW Uk(...);
Hund einHund = NEW Hund;
einObjekt.F(einHund);
1. Fall:
Statisches Binden: Da einObjekt vom Typ Ok ist
(Vereinbarung), muss F aus der Klasse OK
genommen werden. Daher ist der Parameter vom
Typ Tier. Der aktuelle Parameter einHund ist vom
Typ Hund und damit Untertyp von Tier.
Dynamisches Binden: einObjekt referiert zur
Laufzeit zu einem Objekt des Typs Uk (Klasse
UK). Dynamisch wird deshalb F von UK mit dem
formalen Parameter vom Typ Katze ausgewählt.
Der Typ des aktuellen Parameters einHund ist aber
Hund, welches kein Untertyp von Katze ist.
Demzufolge wird ein Laufzeitfehler gemeldet.
2. Fall:
Im Programmteil wird die erste Anweisung
ausgetauscht gegen
Ok einObjekt = NEW Ok(...);
 Keine Differenz in den Sichten bei statischer und
dynamischer Bindung
3. Fall:
Änderung des 1. Falles: F in OK bekommt den
Parametertyp Katze und F in UK den
Parametertyp Tier
Statisches Binden liefert einen Typfehler zur
Übersetzungszeit (Auswahl von F aus Ok mit
gefordertem Parametertyp Katze; Typ des
aktuellen Parameters ist aber Hund). Dynamisches
Binden ergibt keine Probleme (Auswahl von F aus
Uk mit gefordertem Parametertyp Tier; Typ des
aktuellen Parameters ist der Untertyp von Tier
Hund).
Während bei den Klassen von der „größeren“ zur
„kleineren“ Klasse übergegangen wird, geschieht
das beim Parameter von F genau umgekehrt.
 Kontravarianz
Beispiel:
OK
Ok einObjekt = NEW Uk(...);
Katze Ergebnis = einObjekt.g(...);
Katze g(...)
UK
Tier g(...)
 Für Ergebnistypen von Methoden
gilt bei dynamischer Bindung das
Prinzip der Kovarianz.
Smalltalk
Grundprinzipien:
• Jedes Ding ist ein Objekt.
• Jedes Objekt ist eine Instanz einer Klasse.
• Jede Klasse ist Unterklasse einer anderen Klasse.
• Jedes Objekt wird durch Nachrichten aktiviert.
Klassen sind Objekte und damit Instanzen von
Metaklassen.
Festlegung von Object als oberste Klasse
(Durchbrechung der unendlichen Definition)
Charakteristika von Smalltalk-Klassen:
• Enthalten streng private Instanzvariablen
(Speicherung des Objektzustands)
• Enthalten ein Nachrichtenprotokoll
(Nachrichtenschnittstelle): Methoden zur
Änderung oder zum Lesen des Objektzustands
• Enthalten Oberklasse
• Objekterzeugung durch new
• Objektzugriff über Zeiger
Beispiel: Definition der Klasse COMPLEX
Class name: COMPLEX
Superclass: Object
Instance variables: re im
Methods :
realPart
 re
imagPart
 im
setReal : x
re  x
setImag : y
im  y
+y
 (COMPLEX new setReal : (re + (y realPart)))
setImag: (im + (y imagPart))
...
x  (COMPLEX new setReal: 1.0) setImag: 1.0
y  (COMPLEX new setReal: 1.0) setImag: - 1.0
zx+y
Klassenstruktur Boolean – True – False
Boolean
ifTrue:
ifFalse:
xor:
True
False
ifTrue: ifFalse:
ifTrue: ifFalse:
not
not
or:
or:
and:
and:
true
false
Methodenidentifikation:
Vor.: Nachricht m an Objekt o der Klasse K
a) Suche von m in K:
Erfolg, wenn m gefunden wurde
b) Fortsetzung der Suche in der Oberklasse:
Erfolg, wenn m dort vorhanden ist
Bei Misserfolg Fortsetzung in weiterer Oberklasse
c) Suche erreicht Object und m ist nicht vorhanden:
Nachricht DoesNotUnderstand: m an Objekt o und
Identifikationsprozess mit DoesNotUnderstand
d) Wird erneut Object erreicht, erfolgt eine
Standardfehlermeldung
Beispiel: Fachbereichscodes
Class name: Fachbereichscodes
Superclass: Object
Instance variables: names, codes
Methods :
´´Create an instance´´
new
 super new.
´´Create initial empty arrays´´
initialise
[names  Array new: 0
codes  Array new: 0].
´´Test for empty´´
isEmpty
 names isEmpty.
´´Test for inclusion of a given name´´
include: name
 (self indexOf: name) ~= 0.
´´Create a new entry with the given name and return index´´
newIndexOf: name
[self grow
names at: names size put: name
 names size].
´´Stretch table by one element and put in new name´´
grow
[oldNames oldCodes
oldNames  names
oldCodes  codes
names  Array new: names size + 1
codes  Array new: codes size + 1
names replaceFrom: 1 to: oldNames size with: oldNames
codes replaceFrom: 1 to: oldNames size with: oldCodes].
´´Number of table entries´´
size
 names size.
´´Fetch the code for a department´´
at: name
[indexindex  self indexOf: name
index = 0
ifTrue: [self error: ‘Error—Name not in table’]
ifFalse: [ codes at: index]].
´´Install a new code; create entry if necessary´´
at: name put: code
[index
index  self indexOf: name
index = 0
ifTrue: [index  self newIndexOf: name]
 codes at: index put: code].
´´Look-up index of a given department name´´
indexOf: name
[1 to: names size do:
[:index (names at: index) = name ifTrue: [ index]]
 0].
´´Ausdrücke´´
dCodes  Fachbereichscodes new
dCodes initialise
dCodes isEmpty
dCodes at: ´Physics´ put: 100
dCodes at: ´Chemistry´ put: 110
dCodes at: ´Biology´ put: 120
dCodes isEmpty
dCodes size
dCodes at: ´Chemistry´
dCodes includes ´Physics´
dCodes includes ´Computing´
erzeugt neue Instanz
initialisiert names und codes
names und codes sind leer
Physics wird mit 100,
Chemistry mit 110 und
Biology mit 120 eingetragen
die Tabelle ist nicht leer
sie enthält 3 Eintragungen
liefert 110
liefert true
liefert false
Object
MetaClass
Class
ZClass
Z
AClass
A
erben von
Metaklassen
Instanz sein von
Klassen
Eiffel
Charakteristische Prinzipien und Konstrukte:
• Eiffel ist streng getypt:
- Festlegung von Typen durch Deklaration
- Statische Kompatibilität
- Eindeutig bestimmbarer Typ
• Typen:
- Referenztypen: Zeiger auf Objekte
- Erweiterte Typen: Objekttypen
- Basistypen: INTEGER, REAL, DOUBLE,
CHARACTER, BOOLEAN
• Klassen als Implementation von ADTs und
Grundlage für Objekttypen
• Klasse als Ding der Übersetzungszeit, Objekt als
Ding der Laufzeit
• Vor- und Nachbedingungen für Methoden als
Basis der Methode des Programming (Design) by
Contract:
„{V} q {N}, p ruft q auf“ bedeutet „Wenn p die
Gültigkeit der Vorbedingung V garantiert, dann
garantiert auch q die Gültigkeit der
Nachbedingung N.“
• Klasseninvariante, Schleifeninvariante
• Sprachkonstrukt für Ausnahmebehandlung
• Mehrfachvererbung
• Generische Klassen als Implementierung
parametrisierter ADTs
• Abstrakte Klassen in Form zurückgestellter
Klassen
• Gezielte Verdeckung von Merkmalen
Klassenstruktur:
[<Indexierung>]
<Klassenkopf>
[<formale generische Parameter>]
[<veraltete Klasse>]
[<Vererbung>]
[<Erzeugung>]
[<Merkmale>]
[<Invariante>]
end [--class <Klassenname>]
Beispiel: generische Klasse für Hashtabellen hash-fähiger Elemente
indexing
names: h_table;
access: key,direct;
representation: array;
size: fixed, resizable
class HASH_TABLE[T, V  HASHABLE]
inherit TABLE[T, V]
redefine
load
end
creation
make
feature
remove(k: V) is
--Remove entry of key k
require
valid_key: is_valid(k)
do
…
ensure
not has(k)
end; --remove
make(n: INTEGER): BOOLEAN is
--Allocate space for n items
…
end; --make
load …
ok: BOOLEAN is
--Was last operation successful?
do
Result := control = 0
end; --ok
control: INTEGER;
Max_control: INTEGER is 5;
…
invariant
0<= control; control <= Max_control
end –class HASH_TABLE
Anpassung ererbter Merkmale:
•
Überschreibung:
– Überschreibbar: Signatur, Implementation,
Spezifikation (Vor- und Nachbedingung)
Bedingung: Eine überschriebene Signatur muss
entsprechend Konformitätsregeln konform zur alten
Signatur sein; „Beachtung“ der Bedingungen.
– Gründe für ein Überschreiben: Unvollständigkeit
oder Inkorrektheit für die neue Klasse oder
ungenügende Effizienz
– Ankündigung durch
redefine <Merkmalsliste>
•
Umbenennung:
- rename <alter Merkmalsname> as
<neuer Merkmalsname>
- Ziele:
Vermeidung von Namenskonflikten, die
Ermöglichung des Zugriffs zu
gleichnamigen aber unterschiedlichen
Merkmalen und die Einführung
sprechender Bezeichnungen
•
•
Implementation von in den Elternklassen
zurückgestellten Merkmalen:
Kennzeichnung in Elternklassen mit deferred
als abstrakt und Spezifikation mit abstrakten
Eigenschaften; Implementierung unter
Beachtung der Typkonformitätsregel und der
Bedingungen
Löschen der Implementation eines geerbten
Merkmals:
undefine <Liste von Merkmalsnamen>
Die angeführten Merkmale werden als
zurückgestellt (in der Elternklasse) betrachtet.
Beispiel: Umbenennung
class C
inherit
A
rename f as g
end;
B
feature
…
h(x,y:T) is
do
g(x,y)
Verwendung von f aus A
f(y)
Verwendung von f aus B
…
end
end –class C
Beispiel: abstrakte Klasse
deferred class COMPARABLE
feature
infix ´´<´´(other: like current):
BOOLEAN is
deferred
end
…
end –class COMPARABLE
class STRING
inherit
COMPARABLE
redefine ´´<´´
end
feature
infix´´<´´(other: like current):
BOOLEAN is
…
end
…
end –class STRING
Vererbungshierarchie:
GENERAL
PLATFORM
ANY
...
NONE
Vererbungsrelationen:
B
Eltern
C
Kind (Erbe)
A
A, B, C sind Vorgänger (Vorfahren) von C
A, B, C sind Nachfolger (Nachfahren) von
B
A
A, B sind echte Vorgänger von C
C
B, C sind echte Nachfolger von A
Beispiel:
inherit
C
rename
...
export {D,E,F} Die Merkmale f, g und h der Klasse C werden
f,g,h
an die Klassen D, E und F „weitergegeben“.
{M,N}
Die Merkmale k, l und m der Klasse C werden
k,l,m
an die Klassen M und N „weitergegeben“.
redefine
...
end
Situationen mit Beachtung der Konformität:
• x := y : Der Typ von y muss konform zum Typ von x sein.
• Typen aktueller Parameter müssen konform zu den Typen
der entsprechenden formalen Parameter sein.
• Das Überschreiben eines ererbten Attributs muss so
geschehen, dass der neue Typ konform zum alten Typ ist
(Kovarianz).
• Beim Überschreiben einer Funktion muss der neue
Ergebnistyp konform zum alten Ergebnistyp sein.
• Beim Überschreiben einer Routine müssen die neuen
Argumenttypen konform zu den entsprechenden alten
Argumenttypen sein.
Beispiele: Mehrfachvererbung (wiederholte
Vererbung)
• Einfache wiederholte Vererbung
class B
inherit
A; A
feature
...
end –class B
Festlegung: A wird nur einfach geerbt.
• Ererbte Routine wird modifiziert und unter altem Namen
bereitgestellt, während die alte Version einen neuen Namen
bekommt
class B
inherit
A
...
feature
rename
make is
make as A_make
do
end;
A_make
A
…
redefine
make
select
make
end
end
…
end –class B
A
A
make
make
ererbt und
B
umbenannt
ererbt und
überschrieben
A_make
make
• Auswahl eines Merkmals bei Ringstruktur
A
f
B
f
C
ererbt und
überschrieben
ererbt und
D
umbenannt
f
ererbt und
umbenannt
bf
cf
a: A; b: B; c: C; d: D;
...
b := d; c := d; a := d;
-- erlaubt wegen Konformität
b.f;
-- Aufruf von bf
c.f;
-- Aufruf von cf
a.f;
-- Aufruf von bf oder cf?
Auswahl durch select-Klausel in D:
class D
inherit B
rename f as bf
select bf
...
end;
Varianten der Objekterzeugung:
Voraussetzung: Klasse C definiert Objekttyp T, x sei
vom Typ T
• C enthalte keine Erzeugungsprozedur:
!!x bedeutet
a) Erzeugung eines neuen Objekts als Instanz vom
Typ T
b) Initialisierung aller Objektkomponenten durch
Standardwerte
c) Setzen der Referenz von x auf das Objekt
• C enthalte eine Erzeugungsroutine cp:
!!x.cp(...) bedeutet
a) Erzeugung eines neuen Objekts als Instanz vom
Typ T
b) Initialisierung aller Objektkomponenten durch
Standardwerte
c) Aufruf von cp(...) angewendet auf das Objekt
d) Setzen der Referenz von x auf das Objekt
• Erzeugung eines Objekts vom Typ V konform mit
T: !V!x oder !V!x.cp(...)
Beachte folgende Situationen:
• Klassendefinition enthält keine creation-Klausel:
!!<Variable> mit Standardinitialisierung wird genutzt.
• Klassendefinition enthält leere creation-Klausel (besteht
nur aus creation): Es können keine Objekte als Instanzen
dieser Klasse erzeugt werden.
• Auf Klienten zugeschnittene creation-Klausel (wie featureKlausel).
• Eine Erzeugungsroutine verliert beim Vererben ihren
Erzeugungscharakter, wenn sie nicht explizit in der
creation-Klausel der abgeleiteten Klasse steht.
Beispiel: komplexe Zahlen
class COMPLEX
creation
makeComplex
feature {NONE}
re, im: REAL;
feature
makeComplex(x, y:REAL) is
do
re := x;
im := y;
end; --makeComplex
-- nicht exportiert
realPart: REAL is
do Result := re end;
imaginaryPart: REAL is
do Result := im end;
add(y: COMPLEX) is
do
re := re + y.realPart;
im := im + y.imaginaryPart;
end; --add
subtract(y: COMPLEX) is
do
re := re - y.realPart;
im := im - y.imaginaryPart;
end; --subtract
negate is
do
re := -re;
im := -im;
end; --negate
multiply(y: COMPLEX) is
local r, i: REAL;
do
r := re * y.realPart – im * y.imaginaryPart;
i := im * y.realPart + re * y.imaginaryPart;
re := r; im := i;
end; --multiply
divide(y: COMPLEX) is ...
end; --class COMPLEX
x, y, z: COMPLEX;
…
!!x.makeComplex(1.0, 1.0) ; --erzeuge ein Objekt mit der komplexen Zahl
--1.0 + i 1.0 und setze eine Referenz von x zu
--ihm
!!y.makeComplex(2.0, -1.0); --erzeuge ein Objekt mit der komplexen Zahl
--2.0 – i1.0 und setze eine Referenz von y zu ihm
z := clone(x);
--z zeigt auf eine Kopie des von x gezeigten
--Objekts
z.add(y);
--z zeigt auf die Summe der von x und y
--gezeigten komplexen Zahlen
Zusicherungen in Eiffel:
• Klasseninvariante: Eigenschaften aller Objekte
der Klasse zu stabilen Situationen
• Schleifeninvariante:
- Zweck der Schleife in Form von Beziehungen
zwischen Programmvariablen
- gilt vom Eintritt bis zum Verlassen der Schleife
(bei Verlassen gilt zusätzlich Abbruchbedingung)
- variant-Klausel kontrolliert über IntegerAusdruck Erreichung des Schleifenendes
(Verminderung in jedem Durchlauf, aber nie
negativ)
- Schleifenstruktur:
from
...
Initialisierung
invariant
...
Schleifeninvariante
variant
...
Variant-Klausel
until
...
Bedingung für Schleifenende
loop
...
end
Schleifenkörper
• check-Klausel: an allen Anweisungsstellen erlaubt
zur Formulierung von lokalen Eigenschaften
• Vor- und Nachbedingungen für Routinen
Prozedurdefinition:
<Prozedurname>(<Argumente>) is
require
...
Vorbedingung
local
...
Deklaration lokaler Elemente
do
...
Prozedurkörper
ensure
...
end
Nachbedingung
Ausnahmesituationen:
• Falscher Alarm: Meldung einer Ausnahme ohne
Einfluss auf weitere Abarbeitung  normale
Fortsetzung
• Wiederaufnahme: Softwarekomponente mit
vorbedachten Alternativen für den Ausnahmefall
 Fortsetzung nach ausgewählter Alternative
• Organisierte Panik: keine Möglichkeit der
Vertragserfüllung  Objekte werden in
akzeptablen Zustand versetzt und es erfolgt eine
Misserfolgsmeldung an Kunden
try_once_or_twice is
--Solve problem using method 1 or, if unsuccessful, method 2
local
already_tried: BOOLEAN;
do
if not already_tried then method_1 else method_2 end
rescue
if not already_tried then already_tried := true;
retry
end
end –try_once_or_twice
try_and_record is
--Attempt to solve problem using method 1 or, if unsuccessful, method 2.
--Set impossible to true if neither method succeeded, false otherwise.
local
already_tried: BOOLEAN;
do
if not already_tried then method_1
elseif not impossible then method_2
end
rescue
if already_tried then impossible := true end;
already_tried := true;
retry
end –try_and_record
Java
Ziele und Charakteristika:
• Softwareaustausch zwischen unterschiedlicher
Hardware
• Als selbständige OOPS entwickelt, aber mit
imperativen Sprachkonstrukten
• Elementare Datentypen wie in imperativen
Sprachen, aber in Klassen einpackbar (wrapper)
• Gewisse Möglichkeiten der Metaprogrammierung
• Parallelarbeit durch Ausführungsstränge (threads)
• Objektlokale und klassenlokale Variablen und
Methoden
• Schnittstellenkonzept
• Applet-Nutzung
• Netzprogrammierung
Klasse, Objekt
Klasse: neuer Objekttyp + Implementierung
Aufbau einer Klasse:
[<Modifikatorenliste>] class <Klassenname>
{<Liste von Attribut-, Konstruktor- und
Methodendeklarationen>}
Methodendeklaration:
[<Modifikatorenliste>] <Ergebnistyp> <Methodenname>
([<Parameterliste>])
[<throws-Deklaration>] <Methodenrumpf>
Konstruktor:
• Dient der Erzeugung von Objekten und der
Initialisierung der objektlokalen Variablen
• Konstruktorname = Klassenname
• Bereitstellung durch Nutzer oder Standard
• Aufruf: new <Klassenname> (<aktuelle
Parameter>)
Programm:
• Kollektion von Klassen
• Eine Klasse enthält Klassenmethode main:
public static void main (String[ ] argf) {...}
Imperative Konstrukte
Werte, Variablen, Ausdrücke
Werte:
• Elemente eines Datentyps
• Objektreferenzen
• Referenz null
Operationen:
• Auf Objekten oder deren Referenzen
• Auf Basisdatentypen
• Auf allen Datentypen (z.B. ==, !=, =)
Zuweisung <Variable> = <Ausdruck>:
• Berechnung des Ausdruckwertes und Zuweisung
zur Variablen auf der linken Seite
• Wert der Zuweisung = Wert des Ausdrucks
Operandentypen: bei ungleichen Typen
• Implizite Konvertierung: ganzahlige Typen in
größere Bereiche oder Gleitkomma
• Explizite Konvertierung:
(<gewünschter Typ>) <Ausdruck>
(Gewünschter Typ und Ausdruckstyp müssen
miteinander vereinbar sein.)
Imperative Konstrukte
Anweisungen, Blöcke
Anweisungen:
• Ausdruck (Zuweisung, Methodenaufruf,
arithmetischer Ausdruck, logischer Ausdruck)
• Bedingte Anweisungen:
- if (<logischer Ausdruck>) <Anweisung>
- if (<logischer Ausdruck>)
<Anweisung1> else <Anweisung2>
• Mehrfache Alternative (switch-Anweisung)
• Schleifen:
- while (<logischer Ausdruck>) <Anweisung>
- do <Anweisung> while (<logischer Ausdruck>)
- for (<Init-Ausdruck>; <logischer Ausdruck>;
<Ausdruck>) <Anweisung>
Block:
• Variablendeklarationen und Anweisungen
gemischt und eingeschlossen in { }
• Zählt als zusammengesetzte Anweisung
Beispiele:
• result = 1;
for (i = 2; i <=n; i = i + 1) result = result * i;
• i = 2;
while (i <= n)
{result = result * i; i = i + 1;}
• switch (n) {
case 0:...; break;
case 1:...; break;
...
case 10:...; break;
default:...; }
Spezielle Anweisungen:
• break: Verlassen der umfassenden Anweisung
(Beispiel siehe oben)
• return [<Ausdruck>]: Verlassen eines
Methodenrumpfes mit eventuellem Ergebnis
Ausnahmebehandlung
Aufbau der try-Anweisung:
try
<Block>
enthält Anweisungen, die eine
Ausnahme verursachen
könnten
catch (<Ausnahmetyp> <Bezeichner>) <Block>
...
catch (<Ausnahmetyp> <Bezeichner>) <Block>
[finally <Block>]
Beispiel:
• int m;
String str = ´´007L´´;
try {
m = Integer.parseInt(str);
}
catch (NumberFormatException e) {
System.out.println(´´str keine int-Konstante´´);
m = 0}
System.out.println(m);
Allgemeine Abarbeitung der try-Anweisung:
• Fehlerfreie Ausführung des try-Blocks:
- Ausführung des finally-Blocks
- Normale Terminierung der try-Anweisung und
Fortsetzung mit nachfolgender Anweisung
• Abrupte Beendigung des try-Blocks durch
Ausnahme Ex:
- Passender catch-Block existiert:
1. Ausführung des catch-Blocks
2. Ausführung des finally-Blocks
3. Normale Terminierung der try-Anweisung
und Fortsetzung mit nachfolgender Anweisung
- Sonst (kein passender catch-Block):
1. Ausführung des finally-Blocks
2. Wird die try-Anweisung von weiterer tryAnweisung umfasst, erfolgt Weitergabe von
Ex an sie; ansonsten erfolgt abrupte
Terminierung mit Ausnahme Ex.
Direkte Auslösung einer Ausnahme mit throwAusdruck.
try-Block
Ausnahme
Keine Ausnahme
catch-Block
finally-Block
Propagierung von Ausnahmen:
• Innerhalb von Hierarchien von ThrowBlöcken zum unmittelbar umfassenden
throw-Block
• Von aufgerufener Methode zum Aufrufer
durch throws-Deklaration im Methodenkopf
[<Modifikatorenliste>] <Ergebnistyp>
<Methodenname> ([<Parameterliste>])
[<throws-Deklaration>] <Methodenrumpf>
Strukturen mit Klassen, Sichtbarkeit
Strukturen:
• Paket als Zusammenfassung logisch
zusammengehöriger Klassen
• Vererbungsstruktur für Klassifikation
• Verschachtelung von Klassen (innere Klassen) zur
Erleichterung der Handhabung
Anwendungaspekte für Pakete:
• Gute Strukturierung
• Einteilung in Namensräume und Festlegung von
Zugriffsrechten
• Separate Übersetzung
• Wiederverwendung von Klassen
Steuerung des Zugriffs zu Konstrukten eines Pakets:
• Kein Modifikator (default access): paketlokaler Zugriff
• public: uneingeschränkte Nutzung
• private: klassenlokaler Zugriff
• protected: Zugriff durch abgeleitete Klassen
Person
Druckbar
Student
Angestellte
wissMitarbeiter nwMitarbeiter
HSL
class Person {...}
interface Druckbar {void drucken();}
class Student extends Person
implements Druckbar {...}
class Angestellte extends Person
implements Druckbar {...}
class wissMitarbeiter extends Angestellte
implements Druckbar {...}
class nwMitarbeiter extends Angestellte
implements Druckbar {...}
class HSL extends Angestellte
implements Druckbar {...}
Typen
Basisdatentypen
Referenz- oder Objekttypen
Klassentypen Schnittstellentypen
Feldtypen
Beispiel: Dynamisches Binden für Untertypen des
Schnittstellentyps Druckbar
class NumDruck{
private static int Nummer = 1;
private static void DruckMitNum(Druckbar d){
System.out.println(´´Posten´´+Nummer+´´:´´);
d.drucken(); Nummer ++;
}
}
Vererbung:
• Geerbt werden alle Attribute, Methoden und inneren
Klassen der Oberklassen, falls ein Zugriff erlaubt ist
Spezialfall Konstruktoren:
Im Unterklassenkonstruktor kann direkt auf den
Oberklassenkonstruktor durch super(<Parameter>) oder
implizit als erste Anweisung des Unterklassenkonstruktors
auf den parameterlosen Oberklassenkonstruktor
zugegriffen werden.
• Anpassung einer geerbten Methode: Ersetzen durch
Methode gleicher Signatur oder Zugriff auf Methode der
Oberklasse durch super.<Methodenname>(<Parameter>)
mit Ergänzung
• Zusätzliche Attribute, Methoden und innere Klassen
class LinkedList{
private Entry header = new Entry(null, null, null);
private int size = 0;
LinkedList(){
header.next = header;
header.previous = header;
}
ListElem getLast(){…}
ListElem removeLast(){…}
void addLast(ListElem e){…}
int size(){…}
private static class Entry{
private ListElem element;
private Entry next;
private Entry previous;
Entry(ListElem element, Entry next,
Entry previous){…}
}
}
LinkedList
Entry
header
size
3
element null
next
previous
Entry
Entry
Entry
element
next
previous
element
next
previous
element
next
previous
ListElem
ListElem
ListElem
class MyClassIsMyCastle {
private static int streetno = 169;
private static class FirstFloor {
private static class DiningRoom {
private static int size = 36;
private static void mymessage() {
System.out.print(´´I can access streetno´´);
System.out.println(´´:´´+streetno);
}
}
}
private static class SecondFloor {
private static class Bathroom {
private static int size = 16;
private static void mymess() {
System.out.print(´´I can access the ´´);
System.out.print(´´dining room size: ´´);
System.out.println(´´ ´´+FirstFloor.DiningRoom.size);
}
}
}
public static void main(String[] argv){
FirstFloor.DiningRoom.mymessage();
SecondFloor.Bathroom.mymess();
}
}
MyClassIsMyCastle
streetno 169
MyClassIsMyCastle
FirstFloor
DiningRoom
FirstFloor
SecondFloor
DiningRoom
BathRoom
size 36
mymessage
SecondFloor
BathRoom
size 16
mymess
main
class LinkedList {
private Entry header = new Entry(null, null, null);
private int size = 0;
…
private static class Entry {
…
}
class ListIterator {
private int nextIndex = 0;
private Entry next = header.next;
boolean hasNext(){
return nextIndex != size;
}
ListElem next(){
if (nextIndex == size)
throw new NoSuchElementException();
ListElem elem = next.element;
next = next.next;
nextIndex ++;
return elem;
}
}
ListIterator listIterator(){
Return new ListIterator();
}
}
LinkedList
header element null
next
null
previous null
size
0
Entry
ListIterator
nextIndex
0
next
element
next
previous
hasNext
next
listIterator
Beispiel: Anwendung des Schnittstellenkonzepts auf
die Implementierung des Beobachtermusters (nach
A. Poetzsch-Heffter: Konzepte objektorientierter
Programmierung)
Schnittstelle:
interface Beobachter {
void steigen(Aktie a);
void fallen(Aktie a);
}
Aktienklasse:
import java.util.*;
public class Aktie {
private String name;
private int kurswert;
private ArrayList beobachterliste;
Aktie(String n, int anfangswert){
name = n;
kurswert = anfangswert;
beobachterliste = new ArrayList();
}
public void anmeldenBeobachter(Beobachter b) {
beobachterliste.add(b);
}
public String getName() {
return name;
}
public int getKurswert() {
return kurswert;
}
void setKurswert(int neuerWert) {
int alterWert = kursWert;
kursWert = neuerWert>0 ? neuerWert : 1;
ListIterator it = beobachterliste.listIterator();
if(kursWert > alterWert) {
while(it.hasNext() ) {
Beobachter b = (Beobachter)it.next();
b.steigen(this);} }
else {
while(it.hasNext() ) {
Beobachter b = (Beobachter) it.next();
b.fallen(this);}
}
}
}
Aktieninteressent:
class Kunde1 implements Beobachter {
private boolean besitzt = false;
public void fallen(Aktie a) {
if(a.getKurswert() < 300 && !besitzt) {
System.out.println(´´Kauf von ´´+a.getName() );
besitzt = true;
}}
public void steigen(Aktie a) {
if(a.getKurswert() > 400 && besitzt) {
System.out.println(´´Verkauf von ´´+a.getName() );
besitzt = false;
}}
Schlafend
interrupt
E/A beendet
Zeit abgelaufen
E/A-blockiert
E/A
sleep
yield
Neu
start
Rechenbereit
Rechnend
terminiert
Scheduling
Tot
wait
interrupt
notify/
notifyAll
Wartend
Monitor besetzt
Monitor
frei
Monitor-blockiert
Prozesszustände und -übergänge
Erzeugung von Strängen:
1. Ableitung einer neuen Thread-Klasse K aus der
Klasse Thread mit Überschreiben der Methode
run:
class K extends Thread{
...
public void run(){
...
}
}
Thread meinThread = new K();
...
meinThread.start();
2. Ableitung einer neuen Klasse K von einer
beliebigen Klasse O mit gleichzeitiger
Implementierung der Schnittstelle Runnable:
class K extends O
implements Runnable
...
public void run(){
...
}
}
Runnable meinZiel = new K();
Thread meinThread = new Thread(meinZiel);
...
meinThread.start();
PACKAGE Keller_Verwaltung IS
-- Typvereinbarungen
TYPE Keller IS PRIVATE;
-- Unterprogrammvereinbarungen
FUNCTION Leer (K: Keller) RETURN Boolean;
-- Leer zeigt an, ob der Keller leer ist.
PROCEDURE Push (K: IN OUT Keller; Was: IN Integer);
-- Ein Element wird in den Keller gefuellt.
PROCEDURE Pop (K: IN OUT Keller);
-- Das Element an der Kellerspitze wird entfernt.
FUNCTION Read (K: Keller) RETURN Integer;
-- Das Element an der Kellerspitze wird gelesen.
FUNCTION Groesse (K: Keller) RETURN Natural;
-- Gibt die Anzahl der Kellerelemente an.
-- Ausnahmesituationen
Kellerueberlauf: EXCEPTION RENAMES Storage_Error
Leerer_Keller: EXCEPTION;
PRIVATE
TYPE Komponente;
TYPE Komponenten_Zeiger IS ACCESS Komponente;
TYPE Komponente IS RECORD
Information: Integer;
Weiter: Komponenten_Zeiger;
END RECORD;
TYPE Keller IS RECORD
Anker: Komponenten_Zeiger := 0;
Groesse: Natural := 0;
END RECORD;
END Keller_Verwaltung;
Paket X
Deklarationen
öffentlich
privat
Körper
Kindpaket X.Y
öffentlich
privat
GENERIC
Size: Positive;
TYPE Item IS PRIVATE;
PACKAGE Stack IS
PROCEDURE Push (E: IN Item);
PROCEDURE Read (E: OUT Item);
Overflow, Underflow: EXCEPTION;
END Stack;
PACKAGE BODY Stack IS
TYPE Table IS ARRAY (Positive RANGE <>) OF Item;
Space: Table (1..Size);
Index: Natural := 0;
PROCEDURE Push (E: Item) IS
BEGIN IF Index >= Size Then RAISE Overflow END IF;
Index := Index + 1;
Space (Index) := E;
END Push;
PROCEDURE Read (E: OUT Item) IS
BEGIN IF Index = 0 THEN RAISE Underflow; END IF;
E := Space(Index);
Index := Index – 1;
END Read;
END Stack;
-
TYPE Tastenart IS (Zeichen, Funktion, Pfeil, Unbekannt);
TYPE F_Nummer IS RANGE 1..10;
TYPE Richtung IS (N, O, S, W);
TYPE Taste (Art: Tastenart := Unbekannt) IS
RECORD
CASE Art IS
WHEN Zeichen  Z: Character;
WHEN Funktion  F: F_Nummer;
WHEN Pfeil  R: Richtung;
WHEN Unbekannt  NULL;
END CASE;
END RECORD;
WITH Calendar, People;
PACKAGE Alert_System IS
TYPE Alert IS TAGGED
RECORD
Time_Of_Arrival: Calendar.Time;
Message: Text;
END RECORD;
PROCEDURE Display(A: IN Alert);
PROCEDURE Handle(A: IN OUT Alert);
PROCEDURE Log(A: IN Alert);
TYPE
Low_Alert
IS
NEW
Alert
WITH NULL
RECORD;
TYPE Medium_Alert IS NEW Alert WITH
RECORD
Action_Officer: People.Person;
END RECORD;
-- neue Handle-Operation
PROCEDURE Handle(MA: IN OUT Medium_Alert);
TYPE High_Alert IS NEW Medium_Alert WITH
RECORD
Ring_Alarm_At: Calendar.Time;
END RECORD;
-- neue Handle-Operation
PROCEDURE Handle(HA: IN OUT High_Alert);
PROCEDURE Set_Alarm(HA: IN High_Alert);
END Alert_System;
Alert
Low_Alert
Medium_Alert
High_Alert
PACKAGE Sets IS
SUBTYPE Element_Type IS Natural;
TYPE Set IS ABSTRACT TAGGED NULL RECORD;
FUNCTION Empty RETURN Set IS ABSTRACT;
FUNCTION Union (Left, Right: Set) RETURN Set IS ABSTRACT;
FUNCTION Intersection (Left, Right: Set) RETURN Set IS
ABSTRACT;
FUNCTION Unit_Set (Element: Element_Type) RETURN Set IS
ABSTRACT;
PROCEDURE Take (Element: OUT Element_Type;
From: IN OUT Set) IS ABSTRACT;
END Sets;
-- Private Vereinbarung des Typs Geometrisches_Objekt im Paket Geo
PACKAGE Geo IS
TYPE Geometrisches_Objekt IS ABSTRACT TAGGED PRIVATE;
TYPE Pixel_Koordinaten IS
RECORD
X, Y: Integer;
END RECORD ;
TYPE Bildschirmfarbe IS RANGE 0..15 ;
PROCEDURE Verlagere (Was: IN OUT Geometrisches_Objekt;
Wohin: IN Pixel_Koordinaten);
PROCEDURE Zeige (Was: IN Geometrisches_Objekt) IS Abstract;
PRIVATE
TYPE Geometrisches_Objekt IS TAGGED
RECORD
Farbe: Bildschirmfarbe;
Bezugspunkt: Pixel_Koordinaten;
END RECORD;
END Geo;
-- Private Vereinbarung des Typs Flaechenobjekt im Paket
-- Geo.Flaechenobjekte
PACKAGE Geo.Flaechenobjekte IS
TYPE Flaechenobjekt IS ABSTRACT NEW
Geometrisches_Objekt WITH PRIVATE;
PRIVATE
TYPE Flaechenobjekt IS ABSTRACT NEW
Geometrisches_Objekt WITH
RECORD
Gefuellt: Boolean;
END RECORD;
END Geo_Flaechenobjekte;
-- Private Vereinbarung des Typs Kreis im Paket
-- Geo.Flaechenobjekte.Kreise
PACKAGE Geo.Flaechenobjekte.Kreise IS
TYPE Kreis IS ABSTRACT NEW Flaechenobjekt
WITH PRIVATE;
PRIVATE
TYPE Kreis IS ABSTRACT NEW Flaechenobjekt
WITH
RECORD
Radius: Float;
END RECORD;
END Geo.Flaechenobjekte.Kreise;
-- Private Vereinbarung des Typs Rechteck im Paket
-- Geo.Flaechenobjekte.Rechtecke
PACKAGE Geo.Flaechenobjekte.Rechtecke IS
TYPE Rechteck IS ABSTRACT NEW
Flaechenobjekt WITH PRIVATE;
PRIVATE
TYPE Rechteck IS ABSTRACT NEW
Flaechenobjekt WITH
RECORD
Eckpunkt_2: Pixel_Koordinaten;
END RECORD;
END Geo.Flaechenobjekte.Rechtecke;
Paketstruktur
Geo
Flaechenobjekte
Kreise
Rechtecke
Typstruktur
Kreis
Geometrisches_Objekt
Farbe
Bezugspunkt
Flaechenobjekt
Farbe
Bezugspunkt
Gefuellt
Farbe
Bezugspunkt
Gefuellt
Radius
Rechteck
Farbe
Bezugspunkt
Gefuellt
Eckpunkt_2
Anwendung des Pakets Geo
-- Ausgabe einer Reihung geometrischer Objekte
WITH Geo;
PACKAGE Geo_Reihungen IS
TYPE
Geo_Zeiger
IS
ACCESS
Geo.Geometrisches_Objekt´Class;
TYPE Geo_Reihung IS ARRAY (Positive RANGE <>) OF
Geo_Zeiger;
PROCEDURE Zeige (Was: IN Geo_Reihung);
END Geo_Reihungen;
WITH Geo; USE Geo;
PACKAGE BODY Geo_Reihungen IS
PROCEDURE Zeige (Was: IN Geo_Reihung) IS
BEGIN
FOR I IN Was´Range LOOP
Zeige (Was (I).ALL);
END LOOP;
END Zeige;
END Geo_Reihungen;
b
a
parent
x
y
parent
y
z
c
parent
y
z
Merkmalsobjekt
Allgemeines Merkmalsobjekt
parent
+
-
a
y
z
clone
print
parent
b
y
z
parent
c
y
z
parent
c
x
y
m1
n
15
4
c.clone  n
x
n REMOVE y
15
m1
x
y
m1
15
4
n ADDS
VAR z
10  z
METHOD m2 … ;
ENDADDS
x
m1
m2
15
z
10
Prototyp P
P-Objekt P1
Klasse P
Eltern
P-Objekt P2
Kind
Prototyp N
Kind
Klasse N
N-Objekt n

end