5.2 Objekte, Klassen, Kapselung
5.2 Objekte, Klassen, Kapselung
5.2 Objekte, Klassen, Kapselung
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>5.2</strong> <strong>Objekte</strong>, <strong>Klassen</strong>, <strong>Kapselung</strong><br />
Die objektorientierte Modellierung bildet die Grundlage<br />
für die objektorientierte Implementierung eines<br />
Systems.<br />
Dieser Abschnitt beschäftigt sich mit der Umsetzung<br />
der vorgestellten Modellierungskonzepte in objektorientierte<br />
Programmiersprachen, insbesondere Java.<br />
Überblick:<br />
• Beschreibung von <strong>Objekte</strong>n und <strong>Klassen</strong><br />
• Anwendung von <strong>Objekte</strong>n<br />
• Spracherweiterungen: Ausnahmebehandlung<br />
und Initialisierung<br />
• Anwenden und Entwerfen von <strong>Klassen</strong><br />
• Spracherweiterungen: Überladen, <strong>Klassen</strong>attribute<br />
und <strong>Klassen</strong>methoden<br />
• Zusammenwirken der Spracherweiterungen<br />
• Rekursive <strong>Klassen</strong><br />
• Typsystem von Java und parametrische Typen<br />
• <strong>Kapselung</strong> und Strukturieren von <strong>Klassen</strong><br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
493
<strong>5.2</strong>.1 Beschreibung von<br />
<strong>Objekte</strong>n und <strong>Klassen</strong><br />
In der objektorientierten Programmierung betrachtet<br />
man die Ausführung eines Programms als ein<br />
System kooperierender <strong>Objekte</strong>.<br />
Grundsätzlich gibt es zwei Konzepte zur programmiersprachlichen<br />
Beschreibung von <strong>Objekte</strong>n:<br />
• Prototyp-Konzept:<br />
Der Programmierer beschreibt direkt einzelne<br />
<strong>Objekte</strong>. Neue <strong>Objekte</strong> werden durch Klonen<br />
existierender <strong>Objekte</strong> und Verändern ihrer<br />
Eigenschaften zur Laufzeit erzeugt.<br />
• <strong>Klassen</strong>konzept:<br />
Der Programmierer deklariert <strong>Klassen</strong> als<br />
Beschreibung der Eigenschaften, die <strong>Objekte</strong><br />
dieser Klasse haben sollen. Die<br />
Programmiersprache ermöglicht es, zur<br />
Laufzeit <strong>Objekte</strong> der <strong>Klassen</strong> zu erzeugen, aber<br />
nicht, die <strong>Klassen</strong> zu verändern.<br />
Wir betrachten hier nur das <strong>Klassen</strong>konzept.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
494
Die Eigenschaften und das Verhalten eines<br />
(programmiersprachlichen) Objekts ergeben sich<br />
aus seinen möglichen Zuständen und daraus, wie<br />
es auf Nachrichten reagiert.<br />
Eine Objektbeschreibung - insbesondere eine<br />
<strong>Klassen</strong>deklaration - muss daher festlegen:<br />
• welche Zustände ein Objekt annehmen kann,<br />
• auf welche Nachrichten es reagieren kann und<br />
• wie die Methoden aussehen, mit denen ein<br />
Objekt auf den Empfang von Nachrichten<br />
reagieren kann.<br />
Die Menge der möglichen Zustände eines<br />
Objekts entspricht den Wertebereichen seiner<br />
Attribute.<br />
Die Reaktionen eines Objekts auf eintreffende<br />
Nachrichten legen sein dynamisches Verhalten<br />
fest.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
495
Eine einfache <strong>Klassen</strong>deklaration in Java hat<br />
folgende Bestandteile:<br />
class Person {<br />
}<br />
String name;<br />
Person(String n) {<br />
this.name = n;<br />
}<br />
String getName() {<br />
return this.name;<br />
}<br />
<strong>Klassen</strong>name<br />
Attribut<br />
Konstruktor<br />
Methode<br />
Ein Java-Objekt kann genau auf die Nachrichten<br />
reagieren, für die Methoden in seiner Klasse<br />
deklariert sind oder für die es Methoden geerbt hat<br />
(vgl. Abschnitt 5.3).<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
496
Deklaration von <strong>Klassen</strong><br />
<strong>Klassen</strong>name<br />
Direkt hinter dem Schlüsselwort class wird der<br />
Name der Klasse angegeben. Objekt einer<br />
Klasse K nennt man auch Instanzen oder<br />
Ausprägungen von K.<br />
Der <strong>Klassen</strong>name wird gleichzeitig als Typname<br />
für die <strong>Objekte</strong> dieser Klasse verwendet<br />
(<strong>Klassen</strong>typ). Er kann im Programm dann wie<br />
elementare Typen (int, float, usw.) für die<br />
Deklaration von lokalen Variablen, Parametern<br />
und Rückgabewerten verwendet werden.<br />
Beispiel:<br />
Person eineMethode(Person p) {<br />
...<br />
Person vater;<br />
...<br />
}<br />
Außer den <strong>Objekte</strong>n einer Klasse K gehören<br />
auch alle <strong>Objekte</strong> von Unterklassen von K<br />
zum Typ K (siehe Abschnitt 5.3).<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
497
Attribute<br />
Innerhalb einer Klasse K können beliebig viele<br />
Attribute deklariert werden.<br />
Für jedes in K deklarierte Attribut vom Typ T<br />
besitzen die <strong>Objekte</strong> der Klasse K eine<br />
objektlokale Variable vom Typ T. Diese<br />
objektlokalen Variablen nennt man häufig auch<br />
Instanzvariablen.<br />
Die Lebensdauer der Instanzvariablen ist gleich<br />
der Lebensdauer des Objekts.<br />
Klasse:<br />
Person<br />
name : String<br />
getName(): String<br />
Objekt:<br />
name:<br />
: Person<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
498
Methoden<br />
Innerhalb der <strong>Klassen</strong>deklaration können beliebig<br />
viele Methoden deklariert werden.<br />
Methodendeklarationen bestehen aus einer<br />
Signatur und einem Methodenrumpf. Syntaktisch<br />
sind sie wie Prozedurdeklarationen aufgebaut.<br />
Außer den deklarierten Parametern besitzt jede<br />
Methode m eine weiteren, sogenannten impliziten<br />
Parameter vom Typ der Klasse, in dem m<br />
deklariert wurde. Dieser Parameter wird im<br />
Methodenrumpf mit this bezeichnet.<br />
Beispiel:<br />
Die obige Methode in Klasse Person:<br />
String getName() { return this.name; }<br />
hätte in der prozeduralen Programmierung also<br />
die Signatur:<br />
String getName(Person this)<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
499
Neben den prozeduralen Anweisungen kann<br />
eine Methodenrumpf in Java:<br />
- neue <strong>Objekte</strong> erzeugen,<br />
- auf Attribute zugreifen,<br />
- Nachrichten an andere <strong>Objekte</strong> schicken<br />
(Methodenaufruf).<br />
Konstruktoren<br />
Konstruktoren kann man als spezielle Methoden<br />
auffassen, die die Initialisierung von <strong>Objekte</strong>n<br />
beschreiben.<br />
Sie haben den gleichen Namen wie die Klasse, in<br />
der sie deklariert sind.<br />
Beim Start der Ausführung eines Konstruktors ist<br />
das zugehörige Objekt bereits erzeugt, seine<br />
Attribute jedoch nur mit Standardwerten initialisiert.<br />
Konstruktoren liefern als Ergebnis das neu<br />
erzeugte Objekt (bzw. eine Referenz darauf)<br />
zurück.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
500
<strong>5.2</strong>.2 Anwendung von <strong>Objekte</strong>n<br />
Im Allg. umfasst die Anwendung von <strong>Objekte</strong>n vier<br />
Anweisungen:<br />
- <strong>Objekte</strong>rzeugung<br />
- Attributzugriff<br />
- Methodenaufruf<br />
- Objektlöschung (in Java nicht direkt unterstützt)<br />
<strong>Objekte</strong>: Erzeugen und Referenzieren<br />
Syntax in Java:<br />
<strong>Objekte</strong> werden mit Ausdrücken folgender Form<br />
erzeugt (engl. object creation expression):<br />
new ( )<br />
Semantik:<br />
1. Erzeuge ein Objekt / eine Instanz der Klasse, der<br />
der Konstruktor gehört. Dabei werden<br />
insbesondere die Instanzvariablen angelegt.<br />
2. Werte die aktuellen Parameter aus.<br />
3. Rufe den Konstruktor mit den Parametern auf.<br />
Dieser sollte die Instanzvariablen initialisieren.<br />
Ergebnis ist die Referenz des neu erzeugten<br />
Objekts.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
501
Begriffsklärung: (Referenz, Verweis, Zeiger)<br />
Eine Objektreferenz (engl. object reference) ist<br />
eine eindeutige abstrakte Adresse oder Bezeichnung<br />
für ein Objekt. Manchmal spricht man auch von<br />
Verweis (engl. link) oder Zeiger (engl. pointer).<br />
Variablen speichern nicht die <strong>Objekte</strong> als Ganzes,<br />
sondern Objektreferenzen.<br />
Die Auswertung von Ausdrücken eines <strong>Klassen</strong>typs K<br />
liefert Referenzen auf <strong>Objekte</strong> der Klasse K.<br />
Beispiel: (Objektreferenz)<br />
Folgendes Programmfragment verdeutlicht die<br />
Unterscheidung zwischen Objekt und Referenzen:<br />
Person a,b;<br />
a = new Person ("Klaus");<br />
b = a; // a und b speichern dieselbe<br />
// Objektreferenz.<br />
b.getName(); // liefert "Klaus"<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
502
a:<br />
b:<br />
Es gilt also: a.name == b.name<br />
Sprechweisen & Bemerkungen:<br />
: Person<br />
name: "Klaus"<br />
• Häufig spricht man von Referenzen auf ein Objekt.<br />
• Referenzen nennt man auch anonyme Namen<br />
oder Bezeichner. Eine Referenz ist ein Wert.<br />
• Referenzen stellt man graphisch üblicherweise<br />
durch Pfeile dar. Zwei Referenzen sind gleich,<br />
wenn sie auf das gleiche Objekt zeigen.<br />
• Die Unterscheidung Referenz / Objekt hat viele<br />
Analogien:<br />
- Anschrift / Wohnung<br />
- Email-Adresse / Mailbox<br />
- Telefonnummer / Telefonanschluss<br />
- Speicheradresse / Speicherzelle<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
503
Beispiel: (Referenzsemantik)<br />
Wir zeigen ein Programmbeispiel, das verdeutlicht,<br />
warum es wichtig ist, zwischen <strong>Objekte</strong>n und<br />
Referenzen zu unterscheiden:<br />
class EinObjekt {<br />
int meinAttribut;<br />
}<br />
EinObjekt( int n ) {<br />
meinAttribut = n;<br />
}<br />
Anwendung der Klasse EinObjekt:<br />
EinObjekt a, b, c;<br />
a = new EinObjekt(7);<br />
b = a;<br />
c = new EinObjekt(7);<br />
if( a != c ) {<br />
}<br />
a.meinAttribut = 9;<br />
System.out.println( b.meinAttribut );<br />
System.out.println( c.meinAttribut );<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
504
Operationen auf Referenzen in Java:<br />
• Referenzen lassen sich mit „==“ auf Gleichheit<br />
testen bzw. mit „!=“ auf Ungleichheit. Sie sind<br />
genau dann gleich, wenn sie dasselbe Objekt<br />
referenzieren.<br />
Beispiel:<br />
Im obigen Beispiel gilt nach der Zuweisung an c:<br />
a == b und a != c und b != c<br />
• Über Referenzen kann man <strong>Objekte</strong>n Nachrichten<br />
schicke und auf sie zugreifen, d.h. auf ihre<br />
Instanzvariablen.<br />
Bemerkungen:<br />
• <strong>Objekte</strong> können der gleichen Klasse angehören<br />
und den gleichen Zustand haben (gleich sein),<br />
aber trotzdem nicht die gleiche Identität haben<br />
und damit auch unterschiedliche Referenzen<br />
besitzen.<br />
• Variablen von einem <strong>Klassen</strong>typ speichern<br />
Referenzen. Wir sagen deshalb auch vereinfachend,<br />
dass eine Variable ein Objekt referenziert.<br />
• Es ist wichtig zwischen einer Variablen und dem<br />
Objekt, dass sie referenziert zu unterscheiden!<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
505
Die null-Referenz:<br />
Zur Initialisierung von referenzwertigen Variablen<br />
und als Dummy-Wert gibt es die Konstante null.<br />
null gehört zu jedem <strong>Klassen</strong>typ und referenziert<br />
kein Objekt.<br />
Der Versuch, eine Nachricht an null zu schicken,<br />
oder auf eine Instanzvariable von null<br />
zuzugreifen, führt in Java zu einer NullPointer-<br />
Ausnahme.<br />
Beispiel: (Objektreferenz)<br />
Folgendes Programmfragment verdeutlicht die<br />
Unterscheidung zwischen Objekt und Referenzen:<br />
Person a,b;<br />
a = new Person ("Klaus");<br />
b = null; // zulässig<br />
if( a != b ) { // Vergleich ok<br />
}<br />
String s;<br />
s = b.name; // NullPointerException<br />
b.getName(); // NullPointerException<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
506
Begriffsklärung: (Objektgeflecht)<br />
Eine Menge von <strong>Objekte</strong>n, die sich gegenseitig<br />
referenzieren, nennen wir ein Objektgeflecht<br />
(vgl. Folie 345).<br />
Bemerkung:<br />
• Objektgeflechte werden zur Laufzeit aufgebaut<br />
und verändert, sind also dynamische Entitäten.<br />
• <strong>Klassen</strong>diagramme kann man als vereinfachte<br />
statische Approximationen von Objektgeflechten<br />
verstehen.<br />
Lebensdauer von <strong>Objekte</strong>n und<br />
Instanzvariablen:<br />
In Java lassen sich <strong>Objekte</strong> nicht löschen.<br />
Aus Sicht des Programmierers leben <strong>Objekte</strong> und<br />
deren Instanzvariablen von der <strong>Objekte</strong>rzeugung bis<br />
zum Ende der Ausführung des Programms.<br />
Der Speicher nicht erreichbarer <strong>Objekte</strong> wird ggf.<br />
vor Ablauf der Lebensdauer von der automatischen<br />
Speicherbereinigung frei gegeben (vgl. Folien 392ff).<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
507
Attributzugriff<br />
Syntax in Java:<br />
Auf Instanzvariablen von <strong>Objekte</strong>n kann mit<br />
Ausdrücken folgender Form zugegriffen werden:<br />
.<br />
Semantik:<br />
Werte den referenzwertigen Ausdruck aus. Liefert<br />
dieser null, löse eine NullPointerException aus.<br />
Andernfalls liefert er die Referenz auf ein Objekt X;<br />
in dem Fall liefert der gesamte Ausdruck die<br />
Instanzvariable von X zum angegenen Attribut (L-<br />
Wert) oder deren Wert (R-Wert).<br />
Abkürzende Notation:<br />
Der implizite Methodenparameter this kann beim<br />
Zugriff auf eine Attribut a weggelassen werden, d.h.<br />
a<br />
ist gleichbedeutend mit<br />
this.a<br />
innerhalb von <strong>Klassen</strong>, in denen a deklariert ist.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
508
Beispiel: (Attributzugriffe)<br />
class DeinObjekt {<br />
}<br />
MeinObjekt du;<br />
String deinName;<br />
class MeinObjekt {<br />
}<br />
boolean binEingetragen;<br />
String meinName;<br />
void dichInit (DeinObjekt d) {<br />
}<br />
System.out.println( d.deinName );<br />
d.deinName = this.meinName;<br />
this.binEingetragen = true;<br />
meinName = d.du.meinName;<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
509
Methodenaufruf: (engl. method invocation)<br />
Syntax:<br />
Ein Methodenaufruf ist ein Ausdruck ähnlich einem<br />
Prozeduraufruf, allerdings mit einem zusätzlichen<br />
Parameter:<br />
. (<br />
Semantik:<br />
)<br />
Werte den referenzwertigen Ausdruck aus. Liefert<br />
dieser null, löse eine NullPointerException aus.<br />
Andernfalls liefert er die Referenz auf ein Objekt X.<br />
Werte die aktuellen Parameter p1, ..., pn aus.<br />
Führe den Rumpf der angegebenen Methode mit<br />
- X als implizitem Parameter und<br />
- p1, ... , pn als expliziten Parametern aus.<br />
Das Ergebnis des Aufrufs ist der Rückgabewert der<br />
Ausführung des entsprechenden Methodenrumpfes.<br />
Bemerkung:<br />
Eine verfeinerte Semantik wird in 5.3 behandelt.<br />
Dabei wird auch der Zusammenhang zum Senden<br />
von Nachrichten angesprochen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
510
Abkürzende Notation:<br />
Wie beim Attributzugriff kann auch beim Methodenaufruf<br />
der implizite Methodenparameter this weggelassen<br />
werden, also m(...) statt this.m(...) .<br />
Beispiel: (Methodenaufrufe)<br />
class Mensch {<br />
}<br />
Mensch vater, mutter;<br />
String name;<br />
Mensch getOpa (boolean mutterseits) {<br />
}<br />
if ( mutterseits ) {<br />
return mutter.vater;<br />
} else {<br />
}<br />
return vater.vater;<br />
void eineMethode (Mensch m) {<br />
Mensch opaV;<br />
String opaMName;<br />
opaV = m.getOpa(false);<br />
opaMName = m.getOpa(true). name;<br />
}<br />
...<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
511
Objektorientierte Programme<br />
Ein objektorientiertes Java-Programm besteht aus<br />
einer Menge von <strong>Klassen</strong>. Mindestens eine der<br />
<strong>Klassen</strong> muss eine Methode mit Namen main und<br />
folgender Signatur besitzen:<br />
public static void main ( String[] args )<br />
{<br />
...<br />
}<br />
Beim Start von wird die Klasse angegeben, deren<br />
main-Methode ausgeführt werden soll:<br />
java ...<br />
Die Argumente arg1,... werden dabei im Parameter<br />
args als ein Feld von Strings übergeben.<br />
Bei der Ausführung werden die benötigten <strong>Objekte</strong><br />
erzeugt. Diese Bearbeiten ihre Aufträge durch<br />
Ausführung von Methoden.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
512
<strong>5.2</strong>.3 Spracherweiterungen: Initialisierung<br />
und Ausnahmebehandlung<br />
Initialisierung<br />
Attribute und lokale Variablen können direkt an<br />
ihrer Deklarationsstelle initialisiert werden.<br />
Somit sind folgende Programmstücke<br />
gleichbedeutend.<br />
float pi;<br />
pi = 3.141;<br />
float pi = 3.141;<br />
In Java können Attribute und Variablen durch das<br />
Schlüsselwort final als unveränderlich<br />
deklariert werden.<br />
In diesem Fall muss die Initialisierung an der<br />
Deklarationsstelle erfolgen.<br />
class Mathe {<br />
...<br />
final float pi = 3.141; // Konstante<br />
...<br />
}<br />
Die Initialisierung von Attributen erfolgt vor dem<br />
Eintritt in den Konstruktorrumpf.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
513
Beispiel: (Initialisieren von Attributen)<br />
Folgendes Programm mit Initialisierung<br />
class C {<br />
int ax = 7, ay = 9;<br />
}<br />
C(){<br />
m();<br />
}<br />
void m(){<br />
int v1 = 4848, v2 = -3; ...<br />
}<br />
ist äquivalent zu folgendem Programm<br />
class C {<br />
int ax, ay;<br />
}<br />
C(){<br />
ax = 7;<br />
ay = 9;<br />
m();<br />
}<br />
void m(){<br />
int v1, v2;<br />
v1 = 4848; v2 = -3; ...<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
514
Ausnahmebehandlung<br />
Wie in 3.4.1., Folie 235, bereits angesprochen,<br />
kann die Auswertung eines Ausdrucks bzw.<br />
die Ausführung einer Anweisung:<br />
- normal terminieren<br />
- in eine Ausnahmesituation kommen und abrupt<br />
terminieren<br />
- nicht terminieren<br />
Es gibt drei Arten von Ausnahmesituationen:<br />
1. Vom Programmierer schwer zu kontrollierende<br />
und zu beseitigende Situtationen (Speichermangel)<br />
2. Programmierfehler (Nulldereferenzierung, Verletzung<br />
von Indexgrenzen<br />
3. Zeitweise nicht verfügbare Ressourcen, anwendungsspezifische<br />
Ausnahmen, die behebbar<br />
sind.<br />
Ausnahmesituationen werden in Programmiersprachen<br />
unterschiedlich behandelt:<br />
- Programmabbruch (engl. abortion)<br />
- Ausnahmebehandlung<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
515
Java bietet Sprachmittel für die Ausnahmebehandlung<br />
(engl. exception handling).<br />
Dabei spielen drei Fragen eine Rolle:<br />
1. Wann/wie werden Ausnahmen ausgelöst?<br />
2. Wie kann man sie abfangen?<br />
3. Wie kann man neue Ausnahmetypen deklarieren?<br />
Auslösen von Ausnahmen:<br />
Das Auslösen einer Ausnahme kann<br />
- sprachdefiniert (z.B. NullPointer, IndexOutOfBounds)<br />
- oder durch eine Anweisung spezifiziert sein.<br />
In Java gibt es zum Auslösen von Ausnahmen die<br />
throw-Anweisung.<br />
Syntax:<br />
Die throw-Anweisung hat die Form:<br />
throw ;<br />
wobei der Ausdruck ein Ausnahmeobjekt als<br />
Ergebnis liefern muss. (Die throw-Anweisung<br />
entspricht dem raise-Ausdruck in ML.)<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
516
Semantik:<br />
Werte den Ausdruck aus.<br />
Löst die Auswertung eine Ausnahme aus, ist dies<br />
die Ausnahme, die von der Anweisung ausgelöst<br />
wird.<br />
Andernfalls löse die Ausnahme aus, die das<br />
Ergebnis des Ausdrucks ist.<br />
Abfangen von Ausnahmen:<br />
Die try-catch-Anweisung dient dem Abfangen<br />
und Behandeln von Ausnahmen (entspricht<br />
dem handle-Ausdruck in ML):<br />
void myMethod (String[] sfeld)<br />
{<br />
try {<br />
myPrint( sfeld[0] );<br />
myPrint( sfeld[1] );<br />
}<br />
} catch (NullPointerException e) {<br />
myPrintln("sfeld is null");<br />
} catch (IndexOutOfBoundsException e){<br />
myPrintln("sfeld too small");<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
517
Tritt eine Ausnahme vom Typ A im try-Block auf, wird ein<br />
A-Objekt X erzeugt.<br />
Ist der Typ A in der Liste der catch-Klauseln aufgeführt,<br />
- wird die Ausnahme gefangen,<br />
- X an den Bezeichner der entsprechenden catch-<br />
Klausel gebunden und<br />
- diese catch-Klausel ausgeführt (Verfeinerung in 5.3).<br />
Benutzerdefinierte Ausnahmetypen:<br />
Die Deklaration von Exception-<strong>Klassen</strong> behandeln<br />
wir in Abschnitt 5.3.<br />
Bemerkung:<br />
Java verlangt die Deklaration derjenigen Ausnahmetypen<br />
in der Signatur einer Methoden m, die nicht von<br />
m abgefangen werden (Genaueres in 5.3).<br />
Beispiel:<br />
int m( int i ) throws SomeException {<br />
if( i
Beispiel: (Ausnahmebehandlung)<br />
class Try {<br />
}<br />
public static void main( String[] argf ){<br />
long maxint = 2147483647L;<br />
try{<br />
int m, n, ergebnis = 0 ;<br />
m = Integer.parseInt( argf[0] );<br />
n = Integer.parseInt( argf[1] );<br />
long aux = (long)m + (long)n;<br />
if( aux > maxint ) throw new Ueberlauf();<br />
ergebnis = (int)aux ;<br />
} catch ( IndexOutOfBoundsException e ) {<br />
System.out.println("Falsche Argumente");<br />
} catch ( NumberFormatException e ) {<br />
System.out.println(<br />
"Element in argf keine int-Konstante");<br />
} catch ( Ueberlauf e ) {<br />
}<br />
System.out.println("Ueberlauf");<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
519
<strong>5.2</strong>.4 Anwenden und Entwerfen von <strong>Klassen</strong><br />
<strong>Klassen</strong> bilden das zentrale Sprachkonstrukt von Java.<br />
Dementsprechend stehen beim Programmentwurf<br />
zwei Fragen im Mittelpunkt:<br />
• Welche existierenden <strong>Klassen</strong> können für den<br />
Programmentwurf herangezogen werden?<br />
• Welche <strong>Klassen</strong> müssen neu entworfen werden?<br />
Zur Diskussion dieser Aspekte betrachten wir ein<br />
kleines Beispiel.<br />
Aufgabenstellung:<br />
Ein rudimentäres Browser-Programm soll realisiert<br />
werden, mit dem einfache W3Seiten bei einem<br />
Server geholt und in einem Fenster angezeigt<br />
werden können.<br />
Wir gehen davon aus, dass die folgenden <strong>Klassen</strong><br />
existieren:<br />
- W3Seite: Implementiert W3Seiten.<br />
- W3Server: Implementiert W3Server bzw. ihre<br />
Schnittstelle.<br />
- Textfenster: Kann W3-Seiten anzeigen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
520
<strong>Klassen</strong>diagramm zur Lösung der Aufgabenstellung:<br />
Browser<br />
aktSeite: W3Seite<br />
laden(...)<br />
1<br />
1.. *<br />
Textfenster<br />
anzeigen(...)<br />
* *<br />
W3Server<br />
ablegen(String,W3Seite)<br />
W3Seite holen(String)<br />
W3Seite<br />
Schnittstellen der gegebenen <strong>Klassen</strong>:<br />
*<br />
String getTitel()<br />
String getInhalt()<br />
class W3Server {<br />
W3Server() { ... }<br />
void ablegenSeite( String adr, W3Seite s ){<br />
...<br />
}<br />
W3Seite holenSeite( String adr ) { ... }<br />
}<br />
class TextFenster ... {<br />
...<br />
TextFenster() { ... }<br />
void anzeigen(String tzeile,String text){<br />
...<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
521<br />
1
Die vollständige Klasse W3Seiten:<br />
/**<br />
* <strong>Objekte</strong> repräsentieren triviale<br />
* Web-Seiten mit Titelzeile und Inhalt<br />
*/<br />
class W3Seite {<br />
String titel;<br />
String inhalt;<br />
}<br />
W3Seite ( String t, String i ) {<br />
titel = t;<br />
this.inhalt = i;<br />
}<br />
String getTitel() {<br />
return this.titel;<br />
}<br />
String getInhalt() {<br />
return inhalt;<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
522
Wichtige Implementierungsteile einer rudimentären<br />
Browser-Klasse:<br />
class Browser {<br />
}<br />
W3Server meinServer;<br />
TextFenster oberfl;<br />
W3Seite aktSeite; // aktuelle Seite<br />
Browser( W3Server server ){<br />
}<br />
meinServer = server;<br />
oberfl = new TextFenster();<br />
laden( new W3Seite("Startseite",<br />
"NetzSurfer: Keiner ist kleiner") );<br />
interaktiveSteuerung();<br />
void laden( W3Seite s ){<br />
}<br />
aktSeite = s;<br />
oberfl.anzeigen( aktSeite.getTitel(),<br />
aktSeite.getInhalt());<br />
void interaktiveSteuerung() { ... }<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
523
<strong>5.2</strong>.5 Spracherweiterungen: Überladen,<br />
<strong>Klassen</strong>variablen und -methoden<br />
Überladen<br />
In Java ist es erlaubt, innerhalb einer Klasse mehrere<br />
Methoden mit dem gleichen Namen zu deklarieren,<br />
d.h. es gibt zwei Bindungen mit gleichem Namen.<br />
Eine derartige Mehrfachverwendung nennt man<br />
Überladen eines Namens. Methoden mit gleichen<br />
Namen müssen sich in der Anzahl oder in den Typen<br />
der Parameter unterscheiden.<br />
Durch die unterschiedliche Signatur kann der<br />
Übersetzer die Überladung auflösen, d.h. für jede<br />
Aufrufstelle ermitteln, welche von den Methoden<br />
gleichen Namens an der Aufrufstelle gemeint ist.<br />
Entsprechend dem Überladen von Methodennamen<br />
erlaubt Java auch das Überladen bei Konstruktoren.<br />
Beispiel: (Überladen)<br />
Die Java-Bibliothek bietet viele Beispiele für<br />
Überladung. Wir betrachten die Klasse String<br />
(hier nur unvollständig wiedergegeben):<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
524
class String {<br />
/** The value is used for character storage */<br />
char[] value;<br />
/** The offset is the first index of the used storage*/<br />
int offset;<br />
/** The count is the number of characters in the ... */<br />
int count;<br />
String() { value = new char[0]; }<br />
String( String value ) { ... }<br />
String( char[] value ) {<br />
this.count = value.length;<br />
this.value = new char[count];<br />
System.arraycopy(value,0,this.value,0,count);<br />
}<br />
...<br />
int indexOf(int ch) { return indexOf(ch, 0);}<br />
int indexOf(int ch, int fromIndex) { ... }<br />
int indexOf(String str) { ...}<br />
int indexOf(String str, int fromIndex) {...}<br />
int length() { return count; }<br />
char charAt(int index) {<br />
if ((index < 0) || (index >= count)) {<br />
throw<br />
new StringIndexOutOfBoundsException(index);<br />
}<br />
return value[index + offset];<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
525
<strong>Klassen</strong>attribute und <strong>Klassen</strong>methoden<br />
Die Deklaration eines <strong>Klassen</strong>attributs liefert eine<br />
klassenlokale Variable. Syntax:<br />
static ;<br />
<strong>Klassen</strong>attribute/-variablen werden häufig auch als<br />
statische Attribute/Variablen bezeichnet.<br />
Die Variable kann innerhalb der Klasse mit dem<br />
Attributnamen, außerhalb mittels<br />
. <br />
angesprochen werden. Die Lebensdauer der<br />
Variablen entspricht der Lebensdauer der Klasse.<br />
Bemerkung:<br />
<strong>Klassen</strong>variablen verhalten sich ähnlich wie globale<br />
Variablen in der prozeduralen Programmierung.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
526
Beispiel: (<strong>Klassen</strong>attribut)<br />
class InstanceCount {<br />
}<br />
static int instCount = 0;<br />
InstanceCount(){<br />
instCount++;<br />
...<br />
} ...<br />
Die Deklaration einer <strong>Klassen</strong>methode entspricht<br />
der Deklaration einer Prozedur. <strong>Klassen</strong>methoden<br />
besitzen keinen impliziten Parameter. Sie können<br />
nur auf <strong>Klassen</strong>attribute, Parameter und lokale<br />
Variable zugreifen. Syntax:<br />
static <br />
<strong>Klassen</strong>methoden werden häufig auch als<br />
statische Methoden bezeichnet.<br />
<strong>Klassen</strong>methoden werden mit folgender Syntax<br />
aufgerufen:<br />
. ( ... )<br />
Innerhalb der Klasse kann der <strong>Klassen</strong>name entfallen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
527
Beispiel: (<strong>Klassen</strong>-, statische Methoden)<br />
Deklaration:<br />
class String {<br />
...<br />
static String valueOf( long l ) { ... }<br />
static String valueOf( float f ) { ... }<br />
...<br />
}<br />
Anwendung/Aufruf:<br />
String.valueOf( (float)(7./9.) )<br />
liefert die Zeichenreihe: "0.7777778"<br />
Bemerkung:<br />
In Kapitel 4 wurden <strong>Klassen</strong>methoden zur<br />
prozeduralen Programmierung in Java genutzt.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
528
Beispiele: (<strong>Klassen</strong>attribute u. -methoden)<br />
1. Charakteristische Beispiele für <strong>Klassen</strong>attribute und<br />
-methoden liefert die Klasse System, die eine Schnittstelle<br />
von Programmen zur Umgebung bereitstellt:<br />
class System {<br />
}<br />
final static InputStream in = ...;<br />
final static PrintStream out = ...;<br />
static void exit(int status) { ... }<br />
static native void arraycopy(<br />
Object src,int src_position,<br />
Object dst,int dst_position, int length);<br />
Die Klasse PrintStream besitzt Methoden print und<br />
println:<br />
System.out.print("Das klaert die Syntax");<br />
System.out.println(" von Printaufrufen");<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
529
2. Unsere Klasse InputOutput liefert auch schöne<br />
Beispiele für statische Methoden und Überladung:<br />
public class InputOutput {<br />
public static int readInt(){...}<br />
}<br />
public static String readString(){...}<br />
public static char readChar(){...}<br />
public static void print(int i){<br />
System.out.print(i);<br />
}<br />
public static void println(int i){<br />
System.out.println(i);<br />
}<br />
public static void print(char c){<br />
System.out.print(c);<br />
}<br />
public static void println(char c){<br />
System.out.println(c);<br />
}<br />
public static void print(String s){<br />
System.out.print(s);<br />
}<br />
public static void println(String s){<br />
System.out.println(s);<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
530
<strong>5.2</strong>.6 Zusammenwirken der<br />
Spracherweiterungen<br />
Das Zusammenwirken der eingeführten Sprachelemente<br />
erlaubt bereits, recht komplexe Programme<br />
zu schreiben.<br />
Folgendes Programmbeispiel mischt prozedurale<br />
und objektorientierte Sprachelemente. Es dient<br />
zum Studium des Zusammenwirkens der<br />
Spracherweiterungen.<br />
Beispiel: (Zusammenwirken von Sprachel.)<br />
Wir erweitern das Browserbeispiel von <strong>5.2</strong>.4:<br />
- Unterstützung mehrerer Browserfenster<br />
- Interaktive Steuerung über die Konsole<br />
class Konsole {<br />
}<br />
static String readString() { ... }<br />
static void writeString( String s ) {...}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
531
Entwurf der Implementierung:<br />
- Die gemeinsamen Teile aller Browserfenster<br />
werden durch <strong>Klassen</strong>attribute und –methoden<br />
realisiert.<br />
- Es gibt zwei Konstruktoren: Einer startet das<br />
erste Browserobjekt; der andere weitere<br />
Browserobjekte.<br />
- Die gemeinsamen Teile der Konstruktoren<br />
werden von der Methode initialisieren<br />
erledigt.<br />
- Die interaktive Steuerung von der Konsole<br />
wird durch eine statische Methode implementiert.<br />
- Zur einfacheren Handhabung steht eine<br />
<strong>Klassen</strong>methode start zur Verfügung, die den<br />
W3Server als Argument bekommt:<br />
...<br />
Browser.start( testServer );<br />
...<br />
- Die Browserfenster werden in einem Feld auf<br />
<strong>Klassen</strong>ebene verwaltet.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
532
class Browser {<br />
TextFenster oberfl;<br />
W3Seite aktSeite;<br />
static W3Server meinServer;<br />
static final int MAX_ANZAHL = 4;<br />
static Browser[] gestarteteBrowser =<br />
new Browser[MAX_ANZAHL];<br />
static int naechsterFreierIndex = 0;<br />
static int aktBrowserIndex;<br />
static W3Seite startseite =<br />
new W3Seite("Startseite",<br />
"NetzSurfer: Keiner ist kleiner");<br />
// Konstruktor für ersten Browsers<br />
Browser( W3Server server ) {<br />
if( naechsterFreierIndex != 0 ) {<br />
System.out.println("Browser gestartet");<br />
} else {<br />
meinServer = server;<br />
initialisieren();<br />
}<br />
}<br />
// Konstruktor für weiterere Browserfenster<br />
Browser() {<br />
if( naechsterFreierIndex == MAX_ANZAHL ) {<br />
System.out.print("Maximale Anzahl ");<br />
System.out.println(" Browser erreicht");<br />
} else {<br />
initialisieren();<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
533
static void start( W3Server server ) {<br />
new Browser(server);<br />
Browser.interaktiveSteuerung();<br />
}<br />
void initialisieren() {<br />
oberfl = new TextFenster();<br />
gestarteteBrowser[ naechsterFreierIndex ]<br />
= this;<br />
aktBrowserIndex = naechsterFreierIndex;<br />
naechsterFreierIndex++ ;<br />
laden( startseite );<br />
}<br />
void laden( W3Seite s ){<br />
aktSeite = s;<br />
oberfl.anzeigen(aktSeite.getTitel(),<br />
aktSeite.getInhalt());<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
534
}<br />
static void interaktiveSteuerung() {<br />
char steuerzeichen = '0';<br />
do {<br />
Konsole.writeString("Steuerzeichen [lnwe]: ");<br />
try {<br />
String eingabe = Konsole.readString();<br />
if( eingabe.equals("") )<br />
steuerzeichen = '0';<br />
else<br />
steuerzeichen = eingabe.charAt(0);<br />
} catch( Exception e ) {<br />
System.exit( 0 );<br />
}<br />
switch( steuerzeichen ){<br />
case 'l':<br />
String seitenadr;<br />
Konsole.writeString("Seitenadresse: ");<br />
seitenadr = Konsole.readString();<br />
gestarteteBrowser[aktBrowserIndex] .<br />
laden( meinServer.holenSeite( seitenadr ) );<br />
break;<br />
case 'n': new Browser(); break;<br />
case 'w':<br />
aktBrowserIndex =<br />
(aktBrowserIndex+1) % naechsterFreierIndex;<br />
break;<br />
case 'e':<br />
System.exit( 0 );<br />
default:<br />
Konsole.writeString("falsche Eingabe\n");<br />
}<br />
} while( true );<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
535
<strong>5.2</strong>.7 Rekursive <strong>Klassen</strong><br />
Definition: (rekursive <strong>Klassen</strong>deklarationen)<br />
Eine <strong>Klassen</strong>deklaration K heißt direkt rekursiv,<br />
wenn Attribute von K den Typ K haben.<br />
Eine Menge von <strong>Klassen</strong>deklarationen heißt<br />
verschränkt rekursiv oder indirekt rekursiv<br />
(engl. mutually recursive), wenn die Deklarationen<br />
gegenseitig voneinander abhängen.<br />
Eine <strong>Klassen</strong>deklaration heißt rekursiv, wenn<br />
sie direkt rekursiv ist oder Element einer Menge<br />
verschränkt rekursiver <strong>Klassen</strong>deklarationen ist.<br />
Bemerkung:<br />
• Wir identifizieren <strong>Klassen</strong> mit ihren Deklarationen.<br />
• Wichtige Anwendung rekursiver <strong>Klassen</strong> ist die<br />
Implementierung von Listen-, Baum- und Graphstrukturen.<br />
Implementierung von Listen<br />
Im Folgenden betrachten wir rekursive <strong>Klassen</strong><br />
für Listen. Dabei variieren wir die Programmierstile<br />
und die bereitgestellten Schnittstellen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
536
Prozedurale Datenstrukturen:<br />
In der prozeduralen Programmierung sind<br />
Datentypen und Prozeduren zunächst getrennt<br />
(Zusammenfassung erst auf Modulebene).<br />
Beispiel: (Einfachverkettete Listen)<br />
Bei einfachverketteten Listen gibt es für jedes<br />
Listenelement ein Objekt mit zwei Instanzvariablen:<br />
- zum Speichern des Elements<br />
- zum Speichern der Referenz auf den Rest der Liste.<br />
: ProcList<br />
head: 6<br />
tail:<br />
class ProcList {<br />
int head;<br />
ProcList tail;<br />
}<br />
: ProcList : ProcList<br />
head: -3<br />
tail:<br />
head: 84<br />
tail:<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
537
class ProcListMain {<br />
}<br />
static boolean sortiert(ProcList l){<br />
if( l == null || l.tail == null ) {<br />
return true;<br />
} else if( l.head
Diskussion:<br />
Die prozedurale Fassung erlaubt es jedem,<br />
der eine Referenz auf ein Listenknoten hat,<br />
das Objektgeflecht unkontrolliert zu verändern.<br />
Zum Beispiel könnte man Listen in ein zyklisches<br />
Geflecht verändern und damit Invarianten<br />
verletzen.<br />
Funktionale Datenstrukturen:<br />
Unterbindet man den beliebigen Zugriff auf<br />
die Attribute und bietet nur Methoden an, um<br />
Listen auf- und abzubauen, kann man ein<br />
Verhalten wie in der funktionalen Programmierung<br />
erreichen.<br />
Das Mehr an Garantien wird durch weniger<br />
Flexibilität bezahlt. Insbesondere ist das direkte<br />
Einfügen und Modifizieren in der „Mitte“ einer<br />
Datenstruktur nicht mehr möglich.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
539
Beispiel: (Zugriff nur über Methoden)<br />
class FunctionalList {<br />
private int head;<br />
private FunctionalList tail;<br />
}<br />
static FunctionalList empty() {<br />
return new FunctionalList();<br />
}<br />
boolean isempty(){<br />
return tail == null;<br />
}<br />
int head(){<br />
if( isempty() ){<br />
throw new NoSuchElementException();<br />
}<br />
return head;<br />
}<br />
FunctionalList tail(){<br />
if( isempty() ){<br />
throw new NoSuchElementException();<br />
}<br />
return tail;<br />
}<br />
FunctionalList cons( int i ) {<br />
FunctionalList aux = new FunctionalList();<br />
aux.head = i;<br />
aux.tail = this;<br />
return aux;<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
540
class FunctionalListMain {<br />
}<br />
static boolean sortiert( FunctionalList l ){<br />
if( l.isempty() || l.tail().isempty() ) {<br />
return true;<br />
} else if( l.head()
Beispiel: (Liste als Behälter)<br />
Zunächst die Schnittstelle und Anwendung der Klasse:<br />
class SLinkedList {<br />
// Liefert das erste Element der Liste,<br />
// ohne diese Liste zu veraendern<br />
int getFirst(){ ... }<br />
}<br />
// Fügt vorne ein neues Element an diese<br />
// Liste an<br />
void addFirst( int n ) { ... }<br />
// Löscht das erste Element dieser Liste<br />
// und liefert es als Ergebnis<br />
int removeFirst() { ... }<br />
// Liefert die Elementanzahl dieser Liste<br />
int size() { ... }<br />
class SLinkedListMain {<br />
public static void main( String[] argf ){<br />
SLinkedList l = new SLinkedList();<br />
l.addFirst(3);<br />
l.addFirst(2);<br />
l.addFirst(1);<br />
System.out.println( l.removeFirst() );<br />
System.out.println( l.size() );<br />
System.out.println( l.removeFirst() );<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
542
Und nun Teile der Implementierung von SLinkedList:<br />
import java.util.NoSuchElementException;<br />
class SEntry {<br />
int head;<br />
SEntry tail;<br />
}<br />
class SLinkedList {<br />
}<br />
private SEntry entries = null;<br />
private int size = 0;<br />
int getFirst(){<br />
if( size == 0 ){<br />
throw new NoSuchElementException();<br />
}<br />
return entries.head;<br />
}<br />
void addFirst( int n ) {<br />
size++;<br />
SEntry auxe = new SEntry();<br />
auxe.head = n;<br />
auxe.tail = entries;<br />
entries = auxe;<br />
}<br />
...<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
543
Problem bei der erläuterten Implementierung:<br />
Rekursives oder iteratives Durchlaufen durch die<br />
Liste ist nicht möglich (Abhilfe: s.u.).<br />
Andere Formen von Listenimplementierungen<br />
speichern die Elemente in Feldern oder nutzen eine<br />
doppelte Verkettung der Eintragsknoten:<br />
:LinkedList<br />
header:<br />
size: 3<br />
: Entry<br />
element:<br />
next:<br />
previous:<br />
: Entry<br />
element:<br />
next:<br />
previous:<br />
: Entry<br />
element:<br />
next:<br />
previous:<br />
: Entry<br />
element:<br />
next:<br />
previous:<br />
... ... ...<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
544
Implementierung von Bäumen<br />
Binäre Bäume sind wichtige Datenstrukturen, z.B.<br />
zur Darstellung von Mengen.<br />
Beispiel: (Bäume)<br />
class BinTree {<br />
private int elem;<br />
private BinTree left, right;<br />
BinTree( int e ) {<br />
elem = e;<br />
}<br />
void sorted_insert( int e ) {<br />
if( e < elem ) {<br />
if( left == null ) {<br />
left = new BinTree(e);<br />
} else {<br />
left.sorted_insert(e);<br />
}<br />
} else if( elem < e ) {<br />
if( right == null ) {<br />
right = new BinTree(e);<br />
} else {<br />
right.sorted_insert(e);<br />
}<br />
}<br />
}<br />
// weiter auf nächster Folie<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
545
}<br />
boolean contains( int e ) {<br />
if( e < elem && left != null ) {<br />
return left.contains(e);<br />
} else if( elem > e && right != null ) {<br />
return right.contains(e);<br />
} else {<br />
return e==elem;<br />
}<br />
}<br />
void printTree() {<br />
if( left != null ) left.printTree();<br />
System.out.println(elem);<br />
if( right != null ) right.printTree();<br />
}<br />
class BinTreeMain {<br />
public static void main( String[] argf ){<br />
BinTree bt = new BinTree(12);<br />
bt.sorted_insert(3);<br />
bt.sorted_insert(12);<br />
bt.sorted_insert(11);<br />
bt.sorted_insert(12343);<br />
bt.sorted_insert(-2343);<br />
bt.sorted_insert(233);<br />
bt.printTree();<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
546
Iteratoren<br />
Iteratoren erlauben es, schrittweise über Behälter-<br />
Datenstrukturen zu laufen, so dass alle Elemente<br />
der Reihe nach besucht werden. Im Zusammenhang<br />
mit <strong>Kapselung</strong> (s.u.) sind sie unverzichtbar.<br />
Beispiel: (Iteratoren)<br />
Wir reichern die Klasse SLinkedList mit Iteratoren<br />
an und zeigen deren Anwendung.<br />
class Iterator {<br />
SEntry current;<br />
}<br />
Iterator( SEntry se ) {<br />
current = se;<br />
}<br />
boolean hasNext() {<br />
return current!=null;<br />
}<br />
int next() {<br />
if( current==null ){<br />
throw new NoSuchElementException();<br />
}<br />
int res = current.head;<br />
current = current.tail;<br />
return res;<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
547
class SLinkedList {<br />
private SEntry entries = null;<br />
...<br />
Iterator iterator() {<br />
return new Iterator( entries );<br />
}<br />
}<br />
class SLinkedListMain {<br />
public static void main( String[] argf ){<br />
SLinkedList l = new SLinkedList();<br />
l.addFirst(3);<br />
l.addFirst(2);<br />
l.addFirst(4);<br />
}<br />
}<br />
Iterator iter = l.iterator();<br />
while( iter.hasNext() ) {<br />
System.out.println( iter.next() );<br />
}<br />
Bemerkung:<br />
Der Iterator muss Zugriff auf die interne Repräsentation<br />
der Datenstruktur haben, über die er iteriert.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
548
<strong>5.2</strong>.8 Typsystem von Java und<br />
parametrische Typen<br />
Typsystem von Java<br />
Werte in Java sind<br />
- die Elemente der elementaren Datentypen,<br />
- Referenzen auf <strong>Objekte</strong>,<br />
- der Wert null.<br />
Jeder Wert in Java gehört zu mindestens einem Typ.<br />
Vordefinierte und benutzerdeklarierte Typen sind<br />
- die vordefinierten elementaren Typen,<br />
- die durch <strong>Klassen</strong> deklarierten Typen,<br />
- die durch Schnittstellen deklarierten Typen (s.u.).<br />
Implizit deklariert sind die Feldtypen zu den <strong>Klassen</strong>und<br />
Schnittstellentypen (Typkonstruktor „[]“ ).<br />
Feld-, <strong>Klassen</strong>- und Schnittstellentypen fasst man<br />
unter dem Namen Referenztypen zusammen.<br />
(null gehört zu allen Referenztypen.)<br />
<strong>Klassen</strong>- und Schnittstellentypen beschreiben, welche<br />
Nachrichten ihre <strong>Objekte</strong> verstehen bzw. welche<br />
Methoden sie besitzen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
549
Bemerkung:<br />
In typisierten objektorientierten Sprachen können<br />
Werte zu mehreren Typen gehören (Subtypen).<br />
Parametrische Typen<br />
Auch objektorientierte Sprachen unterstützen<br />
parametrische Typsysteme wie in ML. Für Java ist<br />
eine derartige Unterstützung ab Version 1.5<br />
verfügbar.<br />
Beispiel: (Parametrische Typen)<br />
Wir betrachten eine parametrische Fassung der<br />
Klasse SLinkedList:<br />
class SLinkedList {<br />
}<br />
A getFirst(){ ... }<br />
void addFirst( A n ) { ... }<br />
A removeFirst() { ... }<br />
int size() { ... }<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
550
In Java 5 ist die Instanzierung der Typ-<br />
Parameter nur durch Referenztypen gestattet:<br />
class Test {<br />
public static void main( String[] argf ){<br />
}<br />
}<br />
SLinkedList l1<br />
= new SLinkedList();<br />
l1.addFirst("Die Ersten werden");<br />
l1.addFirst("die Letzten sein");<br />
int i = l1.getFirst().indexOf("sein");<br />
// liefert 13<br />
SLinkedList l2<br />
= new SLinkedList();<br />
l2.addFirst(new W3Seite("Titel","Inhalt"));<br />
l2.addFirst(new W3Seite("Title","Content"));<br />
int i = l2.getFirst().indexOf("sein");<br />
// liefert Übersetzungsfehler<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
551
<strong>5.2</strong>.9 <strong>Kapselung</strong> und Strukturieren<br />
von <strong>Klassen</strong><br />
Zwei Aspekte zur weiteren Strukturierung<br />
objektorientierter Programme:<br />
- Schnittstellenbildung und <strong>Kapselung</strong><br />
- Schachtelung von <strong>Klassen</strong> und Pakete<br />
Schnittstellenbildung und <strong>Kapselung</strong><br />
<strong>Objekte</strong> stellen eine bestimmte Funktionalität bzw.<br />
bestimmte Dienste zur Verfügung:<br />
- Anwendersicht: Nachrichten schicken, Ergebnisse<br />
empfangen.<br />
- Implementierungssicht: Realisierung der Zustände<br />
und Funktionalität durch<br />
objektlokale Attribute,<br />
Referenzen auf andere <strong>Objekte</strong>,<br />
Implementierung von Methoden.<br />
Ziel:<br />
- Lege die Anwendungsschnittstelle genau fest.<br />
- Verhindere Zugriff „von außen“ auf Implementierungsteile,<br />
die nur für internen Gebrauch bestimmt<br />
sind.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
552
Begriffsklärung: (Anwendungsschnittstelle)<br />
Die Anwendungsschnittstelle eines Objekts bzw.<br />
eines Referenztyps besteht aus<br />
- den Nachrichten, die es für Anwender zur<br />
Verfügung stellt;<br />
- den Attributen, die für den direkten Zugriff von<br />
Anwendern bestimmt sind.<br />
Bemerkung:<br />
• Die Festlegung von Anwendungsschnittstellen ist<br />
eine Entwurfsentscheidung.<br />
• Direkter Zugriff auf Attribute muss nicht gewährt<br />
werden, sondern kann mit Nachrichten/Methoden<br />
realisiert werden.<br />
Beispiel:<br />
class MitDirektemAttributZugriff {<br />
}<br />
public int attr;<br />
class AttributZugriffueberMethoden {<br />
}<br />
private int attr;<br />
int getAttr() { return attr; }<br />
void setAttr( int a ) { attr = a; }<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
553
Begriffsklärung: (Information Hiding)<br />
Das Prinzip des Information Hiding (deutsch meist<br />
Geheimnisprinzip) besagt, dass<br />
- Anwendern nur die Informationen zur Verfügung<br />
stehen sollen, die zur Anwendungsschnittstelle<br />
gehören,<br />
- alle anderen Informationen und Implementierungsdetails<br />
für ihn verborgen und möglichst nicht<br />
zugreifbar sind.<br />
Gründe für Information Hiding:<br />
• Vermeiden unsachgemäßer Anwendung<br />
• Vereinfachen von Software durch Reduktion<br />
der Abhängigkeiten zwischen ihren Teilen<br />
• Austausch von Implementierungsteilen<br />
Javas Sprachmittel für Information Hiding:<br />
Java ermöglicht es für Programmelemente<br />
sogenannte Zugriffsbereiche zu deklarieren.<br />
Vereinfachend gesagt, kann ein Programmelement<br />
nur innerhalb seines Zugriffsbereichs verwendet<br />
werden.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
554
Java unterscheidet vier Arten von Zugriffsbereichen:<br />
- nur innerhalb der eigenen Klasse<br />
(Modifikator private)<br />
- nur innerhalb der eigenen Pakets (ohne Modifikator)<br />
- nur innerhalb des eigenen Pakets und in Subklassen<br />
(Modifikator protected)<br />
- ohne Zugriffsbeschränkung (Modifikator public)<br />
Generell können <strong>Klassen</strong>, Attribute, Methoden und<br />
Konstruktoren mit den Zugriffsmodifikatoren deklariert<br />
werden.<br />
Beispiel: (Vermeiden falscher Anwendung)<br />
public class SLinkedList {<br />
private SEntry entries = null;<br />
private int size = 0;<br />
}<br />
public int getFirst(){ ... }<br />
...<br />
Außerhalb der Klasse SLinkedList kann das<br />
Attribut size nicht mehr verändert werden, so dass<br />
inkonsistente Zustände, in denen size nicht die<br />
Anzahl der Elemente enthält, vermieden werden<br />
können.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
555
Beispiel: (Austausch von Implementierungen)<br />
public class W3Seite {<br />
private String titel;<br />
private String inhalt;<br />
}<br />
public W3Seite ( String t, String i ) {<br />
titel = t;<br />
inhalt = i;<br />
}<br />
public String getTitel() { return titel; }<br />
public String getInhalt(){ return inhalt;}<br />
Die obige Klasse kann ersetzt werden durch die folgende,<br />
ohne dass Anwender der Klasse davon tangiert werden:<br />
public class W3Seite {<br />
private String seite;<br />
}<br />
public W3Seite( String t, String i ) {<br />
seite = "" + t + "" + i ;<br />
}<br />
public String getTitel(){<br />
int ix = seite.indexOf("")-7;<br />
return new String(seite.toCharArray(),7,ix);<br />
}<br />
public String getInhalt(){<br />
int ix = seite.indexOf("") + 8;<br />
return new String( seite.toCharArray(), ix,<br />
seite.length() – ix );<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
556
Bemerkung:<br />
• Information Hiding erlaubt insbesondere:<br />
- konsistente Namensänderungen in versteckten<br />
Implementierungsteilen.<br />
- Verändern versteckter Implementierungsteile,<br />
soweit sie keine Auswirkungen auf die öffentliche<br />
Funktionalität haben (kritisch).<br />
Beispiel:<br />
Die zweite Implementierung von W3Seite kann nur<br />
dann anstelle der ersten benutzt werden, wenn<br />
Titel die Zeichenreihe "" nicht enthalten.<br />
• Attribute sollten tendenziell privat sein und<br />
nur in Ausnahmefällen öffentlich.<br />
Begriffsklärung: (<strong>Kapselung</strong>)<br />
Wir verstehen unter <strong>Kapselung</strong> eine verschärfte<br />
Form des Information Hiding, die es dem Anwender<br />
unmöglich macht, auf interne Eigenschaften<br />
gekapselter <strong>Objekte</strong> zuzugreifen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
557
Bemerkung:<br />
• Die Verwendung von „private“ führt nicht<br />
automatisch zur <strong>Kapselung</strong>.<br />
• Um <strong>Kapselung</strong> zu erreichen, bedarf es im Allg.<br />
eines Zusammenwirkens unterschiedlicher<br />
Sprachmittel und Programmiertechniken.<br />
Beispiel: (zur <strong>Kapselung</strong>)<br />
1. Der private Zugriffsbereich bezieht sich auf die<br />
Klasse und im Allg. nicht auf einzelne <strong>Objekte</strong>:<br />
public class FamilienMitglied {<br />
private int a;<br />
private FamilienMitglied geschwister;<br />
}<br />
public void incrA(){<br />
a++;<br />
geschwister.a++;<br />
}<br />
Die Methode incrA modifiziert nicht nur das Objekt,<br />
auf dem sie aufgerufen wurde, sondern auch das<br />
private Attribut a des Geschwisterobjekts.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
558
2. Wenn <strong>Objekte</strong> andere <strong>Objekte</strong> zur Realisierung<br />
ihrer Funktionalität nutzen, müssen sie die<br />
Kontrolle über diese <strong>Objekte</strong> behalten:<br />
public class MyFaultyString {<br />
private char[] value;<br />
}<br />
public MyFaultyString( String s ) {<br />
value = s.toCharArray();<br />
}<br />
//...<br />
public char[] toCharArray() {<br />
return value;<br />
}<br />
public class Main {<br />
public static void main( String[] args ) {<br />
}<br />
}<br />
MyFaultyString mfs =<br />
new MyFaultyString("Staatssicherheit");<br />
char[] inhalt = mfs.toCharArray();<br />
// ... später im Programm:<br />
inhalt[3] = 't';<br />
inhalt[5] = ' ';<br />
inhalt[6] = 'S';<br />
// mfs noch unverändert?<br />
System.out.println( mfs.toCharArray() );<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
559
Es reicht also im Allg. nicht, die Attribute als privat<br />
zu deklarieren, um <strong>Kapselung</strong> zu erreichen. Es<br />
muss auch verhindert werden, dass Referenzen<br />
auf interne <strong>Objekte</strong> herausgegeben werden.<br />
Schachtelung von <strong>Klassen</strong> und Pakete<br />
Java-Quellprogramme bestehen aus<br />
Typdeklarationen, d.h. <strong>Klassen</strong>- und Schnittstellendeklarationen<br />
(s.u.). Es gibt drei Sprachkonstrukte<br />
zur Strukturierung der Typdeklarationen:<br />
- Schachtelung von <strong>Klassen</strong><br />
- Gruppierung von <strong>Klassen</strong> zu Übersetzungseinheiten<br />
- Gruppierung von Übersetzungseinheiten zu Paketen<br />
Übersetzungseinheiten entsprechen einer Datei und<br />
können mehrere Typdeklarationen zusammenfassen,<br />
wobei maximal eine öffentlich sein darf.<br />
Syntax:<br />
package ;<br />
<br />
<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
560
Ausführbare Java-Programme sind Ansammlungen<br />
von übersetzten Typdeklarationen. Die Gruppierung<br />
in Übersetzungseinheiten und die Schachtelung von<br />
<strong>Klassen</strong>deklarationen existiert auf der Ebene nicht<br />
mehr.<br />
Schachtelung von <strong>Klassen</strong>:<br />
<strong>Klassen</strong> integrieren zwei Aufgaben:<br />
- Sie beschreiben <strong>Objekte</strong> (Typaspekt).<br />
- Sie gruppieren Daten und Methoden, bilden einen<br />
Gültigkeitsbereich und unterstützen Information<br />
Hiding (Modulaspekt).<br />
Mehrere objektorientierte Sprachen verstärken den<br />
zweiten Aspekt, indem sie die Schachtelung von<br />
<strong>Klassen</strong> unterstützen.<br />
Vorteile:<br />
- Mehr Flexibilität bzgl. Sichtbarkeit und Information<br />
Hiding<br />
- <strong>Klassen</strong>deklaration dichter bei ihren Anwendungen<br />
- Erlaubt syntaktische Abkürzungen<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
561
Eine Klasse heißt in Java geschachtelt (engl.<br />
nested), wenn sie innerhalb der Deklaration einer<br />
anderen Klasse deklariert ist:<br />
- als Komponente (ähnlich einem Attribut),<br />
- als lokale <strong>Klassen</strong> (ähnlich einer lokalen Variablen)<br />
- als anonyme <strong>Klassen</strong> bei der <strong>Objekte</strong>rzeugung.<br />
Ist eine Klasse nicht geschachtelt, nennen wir sie<br />
global (engl. top-level).<br />
Java unterscheidet statische und innere <strong>Klassen</strong>.<br />
Statische <strong>Klassen</strong>:<br />
Geschachtelte <strong>Klassen</strong> heißen statisch, wenn sie<br />
mit dem Modifikator static deklariert sind.<br />
Statische Klasse haben die gleiche Bedeutung wie<br />
globale <strong>Klassen</strong>. Allerdings ergeben sich andere<br />
Sichtbarkeits- und Zugriffsbereiche. Insbesondere:<br />
- Geschachtelte <strong>Klassen</strong> können als privat deklariert<br />
werden, so dass sie außerhalb der umfassenden<br />
Klasse nicht verwendet werden können.<br />
- Geschachtelte <strong>Klassen</strong> können auf private Attribute<br />
und Methoden der umfassenden Klasse zugreifen.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
562
Beispiel: (statische <strong>Klassen</strong>)<br />
public class SLinkedList2 {<br />
private SEntry entries = null;<br />
private int size = 0;<br />
}<br />
private static class SEntry {<br />
int head;<br />
SEntry tail;<br />
}<br />
int getFirst() { ... }<br />
...<br />
Der Typ SEntry ist nur innerhalb von SLinkedList2<br />
sichtbar und zugreifbar.<br />
Bemerkung:<br />
• Die Zugriffs- und Sichtbarkeitsregeln im<br />
Zusammenhang mit geschachtelten <strong>Klassen</strong><br />
sind recht komplex (siehe folgendes Beispiel).<br />
• Zugreifbare geschachtelte <strong>Klassen</strong> können<br />
über zusammengesetzte Namen außerhalb der<br />
umfassenden Klasse angesprochen werden<br />
( z.B. SLinkedList2.SEntry ).<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
563
Beispiel: (mehrfach geschachtelte <strong>Klassen</strong>)<br />
public class MyClassIsMyCastle {<br />
private static int streetno = 169;<br />
private static class FirstFloor {<br />
private static class DiningRoom {<br />
private static int size = 36;<br />
private static void mymessage(){<br />
System.out.print("Access to streetno");<br />
System.out.println(": "+ streetno );<br />
}<br />
}<br />
}<br />
private static class SecondFloor {<br />
private static class BathRoom {<br />
private static int size = 16;<br />
private static void mymess(){<br />
System.out.print("I can access the ");<br />
System.out.print("dining room size: ");<br />
System.out.println(<br />
FirstFloor.DiningRoom.size );<br />
}<br />
}<br />
}<br />
public static void main( String[] argv ) {<br />
FirstFloor.DiningRoom.mymessage();<br />
SecondFloor.BathRoom.mymess();<br />
}<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
564
ml:<br />
Innere <strong>Klassen</strong>:<br />
Geschachtelte Klasse, die nicht statisch sind, heißen<br />
innere <strong>Klassen</strong>.<br />
Sei K eine Klasse und INN eine direkte innere Klasse<br />
von K. Dann bekommt jedes INN-Objekt eine<br />
Referenz auf das K-Objekt, in deren Kontext es<br />
erzeugt wurde.<br />
Beispiel: (innere <strong>Klassen</strong>)<br />
Wir betrachten einfach verkettete Listen:<br />
- SLinkedListIter: Listen mit Iteratoren<br />
- SEntry: die <strong>Objekte</strong> für die Verkettung<br />
- Iterator: die Iterator-<strong>Objekte</strong> als innere <strong>Objekte</strong> zu<br />
SLinkedListIter-<strong>Objekte</strong>n<br />
:SLinkedListIter<br />
size:<br />
entries:<br />
:SEntry<br />
head:<br />
tail:<br />
4<br />
3<br />
:SEntry<br />
head:<br />
tail:<br />
:Iterator<br />
this$0:<br />
current:<br />
iter:<br />
:SEntry<br />
head:<br />
tail:<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
565<br />
2<br />
8<br />
•
import java.util.NoSuchElementException;<br />
class SLinkedListIter {<br />
private int size = 0;<br />
private SEntry entries = null;<br />
}<br />
private static class SEntry { ... }<br />
int getFirst(){ ... }<br />
...<br />
public class Iterator {<br />
private SEntry current;<br />
Iterator() {<br />
current = entries;<br />
}<br />
boolean hasNext() {<br />
return current != null;<br />
}<br />
int next() {<br />
if( current == null ) {<br />
throw new NoSuchElementException();<br />
}<br />
int res = current.head;<br />
current = current.tail;<br />
return res;<br />
}<br />
}<br />
public Iterator createIterator() {<br />
return new Iterator();<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
566
class SLinkedListIterMain {<br />
public static void main( String[] argf ){<br />
SLinkedListIter ml = new SLinkedListIter();<br />
ml.addFirst(8);<br />
ml.addFirst(2);<br />
ml.addFirst(4);<br />
}<br />
}<br />
Pakete:<br />
SLinkedListIter.Iterator iter<br />
= ml.createIterator();<br />
while( iter.hasNext() ) {<br />
System.out.println( iter.next() );<br />
}<br />
Große Programme bestehen aus hunderten und<br />
tausenden von Typen/<strong>Klassen</strong>, die von unterschiedlichen<br />
EntwicklerInnen und Institutionen realisiert und<br />
verwaltet werden.<br />
Es ist von großer Bedeutung, diese <strong>Klassen</strong> geeignet zu<br />
gruppieren und einzuteilen. Wichtige Aspekte:<br />
- Auffinden, Verstehen des Zusammenhangs<br />
- Übersetzungs-, Installationsorganisation<br />
- Zugriffsrechte, Namensräume<br />
- Pflege, Wartung<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
567
Für diese Aufgabenbereiche gibt es Modulkonzepte.<br />
Javas Pakete bieten ein relativ einfache Lösung dafür:<br />
- Ein Paket hat einen Namen P. Der Name besteht<br />
ggf. aus mehreren Teilen.<br />
- Ein Paket P ist üblicherweise in einem Dateiver-<br />
zeichnis mit Namen P abgelegt.<br />
Beispiel:<br />
Paket java.lang ist abgelegt in .../java/lang<br />
- Ein Paket ist eine endl. Menge von Übersetzungseinheiten;<br />
der Paketname erscheint am Anfang der<br />
Übersetzungseinheiten.<br />
- Pakete stellen einen Zugriffsbereich dar: Alle<br />
ohne Zugriffsmodifikator deklarierten Programmelemente<br />
sind paketweit zugreifbar.<br />
- Pakete bilden Namensräume: Ist P ein Paket, dann<br />
können alle <strong>Klassen</strong> K in P mittels P.K angesprochen<br />
werden (vollständiger Name).<br />
- Es gibt keine Paket-Hierarchie/Unterpakete.<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
568
Beispiel: (Anwendung von Paketen)<br />
Wir benutzen die Listenklasse LinkedList aus<br />
dem Paket java.util in unserem Paket kalau.<br />
package kalau;<br />
public class AufEinWort {<br />
public static void main( String[] argf ){<br />
}<br />
}<br />
java.util.LinkedList ml =<br />
ml.addLast("Urin");<br />
ml.addLast("stinkt");<br />
new java.util.LinkedList();<br />
java.util.Iterator iter = ml.iterator();<br />
while( iter.hasNext() ) {<br />
System.out.print( iter.next() );<br />
}<br />
System.out.println();<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
569
Variante mit Import der angegebenen Typnamen:<br />
package kalau;<br />
import java.util.LinkedList;<br />
import java.util.Iterator;<br />
public class AufEinWort {<br />
public static void main( String[] argf ){<br />
}<br />
LinkedList ml = new LinkedList();<br />
ml.addLast("Urin");<br />
ml.addLast("stinkt");<br />
Iterator iter = ml.iterator();<br />
...<br />
Variante mit Import aller Typnamen des Pakets java.util:<br />
package kalau;<br />
import java.util.*;<br />
public class AufEinWort {<br />
...<br />
}<br />
21.01.2008 © A. Poetzsch-Heffter, TU Kaiserslautern<br />
570