Sie sind auf Seite 1von 94

Lsungen zu den bungen des Buches

Java lernen mit BlueJ Eine Einfhrung in die objektorientierte Programmierung


von David J. Barnes, Michael Klling ISBN-10: 3-8273-7152-X Pearson Education Deutschland, 2006 Deutsche bersetzung: Bettina von Stockfleth Axel Schmolitzky

Teil 1: Grundlagen der Objektorientierung


Kapitel 1
bung 1.9 Das Haus:

Erstellen Sie ein neues Objekt Quadrat Rufen Sie dessen Methode sichtbarMachen() auf Vergrern Sie das Quadrat, indem Sie die Methode groesseAendern(neueGroesse) aufrufen. (100 ist ein guter Wert) Bewegen Sie das Quadrat nach unten, indem Sie die Methode vertikalBewegen (entfernung) aufrufen. (Hier ist 80 ein guter Wert)

Das Fenster:

Erstellen Sie ein neues Objekt Quadrat Rufen Sie dessen Methode sichtbarMachen() auf ndern Sie seine Farbe durch den Aufruf von farbeAendern() Schreiben Sie "schwarz" in das Pop-up-Fenster Bewegen Sie das Quadrat nach unten, indem Sie die Methode vertikalBewegen(entfernung) aufrufen (100 ist ein guter Wert) Bewegen Sie es nach rechts, indem Sie nachRechtsBewegen() aufrufen

Das Dach:

Erstellen Sie ein neues Objekt Dreieck Rufen Sie dessen Methode sichtbarMachen() auf ndern Sie seine Gre mit groesseAendern(neueHoehe, neueBreite) (50,140)
vertikalBewegen(70) horizontalBewegen(60)

Die Sonne:

Erstellen Sie ein neues Objekt Kreis Rufen Sie dessen Methode sichtbarMachen() auf ndern Sie seine Farbe durch den Aufruf von farbeAendern() (schreiben Sie "gelb" in das Pop-up-Fenster) ndern Sie wahlweise seine Gre mit
groesseAendern(60)

Bewegen Sie es nach rechts, indem Sie horizontalBewegen(180) aufrufen

bung 1.11

Sie verwendet die Objekte der Klassen Kreis, Quadrat und Dreieck

Dann bewegt sie diese Objekte an die richtigen Stellen und verndert deren Gren und Farben, wobei grundstzlich dieselben Methoden wie in bung 1.9 aufgerufen werden.

bung 1.15 Fgen Sie nach der Zeile sonne.sichtbarMachen() Folgendes ein:
sonne.langsamVertikalBewegen(250); Kompilieren Sie die Klasse Zeichnung (geben Sie den Compile-Befehl im

Editor-Fenster) Erstellen Sie eine Instanz der Klasse Zeichnung und rufen Sie dessen Methode zeichne() auf

bung 1.16 Entfernen Sie diese Zeile (falls Sie diese in der vorherigen bung eingefgt haben): langsamVertikalBewegen(250); rechts unterhalb des letzten } nach der Methode zeichne() fgen Sie die Methode sonnenuntergang() hinzu:
/** * Lsst die Sonne untergehen. */ public void sonnenuntergang() { sonne.langsamVertikalBewegen(250); }

Kompilieren Sie! Und lassen Sie das Programm ablaufen. bung 1.18 Wenn Sie die Method gibName() aufrufen, wird der Name des Studenten in einem Pop-up-Fenster angezeigt. Bei dem angezeigten Namen handelt es sich um den Namen, der beim Erzeugen des Objektes eingegeben wurde. bung 1.20 Sie zeigt die Zahl der Studenten in dem Laborkurs an, die Null ist. bung 1.27
0 int "hallo" String 101 int -1 int true boolean "33" String 3.1415 double

bung 1.28 Zunchst mssen Sie entscheiden, welchen Typ das Datenfeld haben soll. String wre ein gut geeigneter Typ, um einen Namen zu enthalten, also fgen wir der Quelltext-Datei von Kreis die folgende Zeile hinzu:
private String name;

Diese Zeile knnte nach der folgenden Zeile in Kreis.java platziert werden:
private boolean istSichtbar;

bung 1.29
public void senden(String nachricht)

bung 1.30
public int mittelwert(int ersteZahl, int zweiteZahl)

bung 1.31 Das Buch ist ein Objekt. Die Klasse knnte Buch sein. bung 1.32 Ja, ein Objekt kann verschiedene Klassen haben. Eines der bekanntesten Beispiele ist der Platypus, der sowohl ein Sugetier ist als auch Eier legend.

Kapitel 2
bung 2.2 Null. bung 2.3 Wenn zu viel Geld eingeworfen wird, nimmt der Automat das gesamte Geld an ohne den berzahlten Betrag herauszugeben. Wenn nicht genug Geld eingeworfen wird, druckt er dennoch das Ticket. bung 2.5 Es sieht genauso aus. Nur der Preis auf dem Ticket ist ein anderer.

bung 2.6 Die ueren Klammern der Klasse Student:


public class Student {}

Die ueren Klammern der Klasse Laborkurs:


public class Laborkurs{}

bung 2.7 Ja, die Reihenfolge von public und class ist wichtig. bung 2.8 Ja, es ist mglich das Wort public wegzulassen. bung 2.9 Datenfelder:
preis bisherGezahlt gesamtsumme

Konstruktoren:
Ticketautomat

Methoden:
gibPreis gibBisherGezahltenBetrag geldEinwerfen ticketDrucken

bung 2.10 Er hat keine Rckgabetyp. Der Name des Konstruktors ist derselbe wie der Name der Klasse. bung 2.11
int Student Server

bung 2.12
lebendig tutor spiel

bung 2.13 Die Reihenfolge ist wichtig.

bung 2.14 Ja, es muss immer ein Semikolon am Ende einer Datenfelddeklaration stehen. bung 2.15
private int status;

bung 2.16 Er gehrt zu der Klasse Student. bung 2.17 2 Parameter, einer vom Typ String, einer vom Typ double bung 2.18 Es macht Sinn anzunehmen, dass die Typen mit den beiden Parametern (String und double) identisch sind. In Bezug auf die Namen knnen nicht wirklich Vermutungen gemacht werden, aber wahrscheinlich etwas wie titel und preis. bung 2.19
name = seinName;

bung 2.20 Es wird eine neue Variable preis im Konstruktor deklariert (weil hier ein int vorangestellt ist). Das bewirkt, dass wir ticketpreis der lokalen Variable preis zuweisen, nicht dem Datenfeld preis. bung 2.21 Der einzige Unterschied zwischen ihnen ist, dass gibPreis() den Preis und gibBisherGezahltenBetrag den bisher gezahlten Betrag liefert. bung 2.22 Welchen Geldbetrag habe ich bisher in den Automat eingeworfen? bung 2.23 Nein. bung 2.24
public int gibGesamtsumme() { return gesamtsumme; }

bung 2.25 Die Rckgabeanweisung fehlt. bung 2.26 Die Signatur fr gibPreis() hat int als Rckgabetyp. Die Signatur fr ticketDrucken hat void als Rckgabetyp. bung 2.27 Nein. Weil sie nichts zurckgeben mssen. Ja. Beide Kpfe haben void als Rckgabetyp. bung 2.29 Er hat einen Rckgabetyp (void), und Konstruktoren haben keine Rckgabetypen. bung 2.30
preis = ticketpreis;

bung 2.31
punktestand = punktestand + punkte;

bung 2.32
preis = preis - betrag;

bung 2.33
public void meldung() { System.out.println("Bitte werfen Sie den passenden Geldbetrag ein."); }

bung 2.34
public void preisAusgeben() { System.out.println("Der Preis eines Tickets betrgt " + preis + " Cent"); }

bung 2.35 Sie liefern unterschiedliche Preise. Dies liegt daran, dass jedes Objekt Ticketautomat seinen eigenen Preis hat. Der Preis, der fr einen Ticketautomaten festgelegt wurde, hat keinen Einfluss auf die Preise der anderen Ticketautomaten.

bung 2.36 Anstatt den tatschlichen Ticketpreis auszudrucken, wrde nur das Wort "preis" ausgedruckt werden. bung 2.37 Es wird genau derselbe String wie in bung 2.36 ausgedruckt. bung 2.38 Nein, denn keine von ihnen zeigt tatschlich den Ticketpreis an. bung 2.39
public Ticketautomat() { preis = 1000; bisherGezahlt = 0; gesamtsumme = 0; }

Die Tickets kosten immer 1000. bung 2.40


public void leeren() { gesamtsumme = 0; }

Diese Methode bentigt keine Parameter. Es handelt sich um eine verndernde Methode. bung 2.41
public void preisSetzen(int neuerPreis) { preis = neuerPreis; }

Es handelt sich um eine verndernde Methode. bung 2.42


public Ticketautomat() { preis = 1000; bisherGezahlt = 0; gesamtsumme = 0; } public Ticketautomat(int ticketpreis) { preis = ticketpreis; bisherGezahlt = 0; gesamtsumme = 0; }

bung 2.43
bisherGezahlt ndert sich nicht, wenn eine Fehlermeldung gedruckt wird.

Die Eingabe von 0 fhrt zu einer Fehlermeldung. bung 2.44 Es wird keine Fehlermeldung gedruckt. Das Verhalten der Methode wird nicht verndert. bung 2.45 Bei dem Datenfeld handelt es sich um istSichtbar. Die Eigenschaft gibt vor, ob der Kreis sichtbar ist oder nicht. Ja. Da der Kreis entweder sichtbar ist oder nicht, wurden nur zwei Zustnde (Werte) bentigt. bung 2.46 Bei der Methode ticketAusgeben in Listing 2.8 erhht sich die Gesamtsumme um den Preis des Tickets und nicht der bisher gezahlte Betrag. Der bisher gezahlte Betrag wird dann um den Preis reduziert. bung 2.49
ersparnis = preis * rabatt;

bung 2.50
durchschnitt = gesamt / anzahl;

bung 2.51
if(preis > budget) { System.out.println("zu teuer."); } else { System.out.println("passt."); }

bung 2.52
if(preis > budget) { System.out.println("zu teuer. Ihr Budget betrgt nur: " + budget); } else { System.out.println("passt."); }

bung 2.53 Weil der bisher gezahlte Betrag auf Null gesetzt wird und dieser Wert dann ausgegeben wird. Diese Methode wird stets Null zurckgeben. Das kann getestet werden, indem ein Betrag eingeworfen wird und anschlieend wechselgeldAuszahlen() aufgerufen wird. Das Original wrde dann den eingeworfenen Betrag zurckgeben, aber die neue Methode gibt Null zurck.

bung 2.54 Eine Fehlermeldung wird gedruckt: "unreachable statement", also "nicht erreichbare Anweisung". Eine Rckgabeanweisung beendet (verlsst) die Methode. Quelltext, der auf eine Rckgabeanweisung folgt, kann daher nie ausgefhrt werden. bung 2.55
public int entleeren() { int gesamtsummeAlt = gesamtsumme; gesamtsumme = 0; return gesamtsummeAlt; }

bung 2.56 Sie ist beides: eine sondierende und verndernde Methode. bung 2.57
public void ticketAusgeben() { int nochZuZahlen = preis - bisherGezahlt; if(nochZuZahlen <= 0) { // Simuliere den Druck eines Tickets. System.out.println("##################"); System.out.println("# The BlueJ Line"); System.out.println("# Ticket"); System.out.println("# " + preis + " Cent."); System.out.println("##################"); System.out.println(); // Aktualisiere die Gesamtsumme unter Bercksichtigung des Preises. gesamtsumme += preis; // Reduziere den bisher gezahlten Betrag um den Preis. bisherGezahlt -= preis; } else { System.out.println("Sie mssen mindestens noch zahlen: " + nochZuZahlen + " Cent."); nochZuZahlen + " Cent."); } }

bung 2.58 Sie wrden Datenfelder bentigen, um die Preise fr jede Ticketpreisklasse zu speichern, die der Automat ausgeben kann. Sie wrden eine Methode bentigen, um den von Ihnen gewnschten Tickettyp aussuchen zu knnen. Es ist nicht erforderlich, viele der existierenden Methoden zu ndern, sofern das Datenfeld fr den Preis jedes Mal aktualisiert wird, wenn Sie einen neuen Tickettyp whlen. Sie mssten wahrscheinlich den Konstruktor ndern, um mehrere Ticketpreise zuzulassen.

bung 2.59 Name: gibName Ergebnistyp: String bung 2.60 Name: setzeKreditrahmen Parametername: rahmen Parametertyp: int bung 2.61
public class Person{}

bung 2.62
private private private private String name; int alter; String nummer; int kreditrahmen;

bung 2.63
public Modul(String modulnummer) { nummer = modulnummer; }

bung 2.64
public Person(String meinName, int meinAlter) { name = meinName; alter = meinAlter; }

bung 2.65
public int gibAlter() { return alter; }

bung 2.66
public String gibName() { return name; }

bung 2.67
public void setzeAlter(int neuesAlter) { alter = neuesAlter; }

bung 2.68
public void detailsAusgeben() { System.out.println("Der Name dieser Person ist " + name); }

bung 2.69
student1: Student name: Benjamin Johnson matrikelnummer: 738321 scheine: 0

bung 2.70 "Henr557" bung 2.71 Der Editor mit dem Quelltext der Klasse Student wird geffnet. Es wird folgende Meldung angezeigt: StringIndexOutOfBoundsException Das passiert, weil die Methode gibLoginName davon ausgeht, dass der Name mindestens 4 Zeichen lang ist und djb aber nur 3 Zeichen hat. bung 2.72
public Student(String vollerName, String matrNR) { if(vollerName.length() < 4) { System.out.println("Fehler! Der Name muss mindestens 4 Zeichen lang sein"); } if(matrNR.length() < 3) { System.out.println("Fehler! Die Studenten-ID muss mindestens 3 Zeichen lang sein"); } name = vollerName; matrikelnummer = matrNR; scheine = 0; }

bung 2.73
public String gibLoginName() { String loginNamensteil; if(name.length() < 4) { loginNamensteil = name; } else { loginNamensteil = name.substring(0,4); } String loginMatrikelnummer; if(matrikelnummer.length() < 3) { loginMatrikelnummer = id; } else { loginMatrikelnummer = id.substring(0,3); } return loginNamensteil + loginMatrikelnummer; }

bung 2.74
/** * Liefert den Autor dieses Buches zurck. */ public String gibAutor() { return autor; } /** * Liefert den Titel dieses Buches zurck. */ public String gibTitel() { return titel; }

bung 2.75
/** * Gibt den Namen des Autors auf der Konsole aus. */ public void autorAusgeben() { System.out.println("Autor: " + autor); } /** * Gibt den Titel des Buches auf der Konsole aus. */ public void titelAusgeben() { System.out.println("Titel: " + titel); }

bung 2.76 Lschen Sie den Konstruktor und fgen Sie Folgendes ein:
private int seiten; /** * Setzt die Datenfelder autor und titel, nachdem dieses Objekt * erzeugt wurde. */ public Buch(String buchautor, String buchtitel, int buchSeiten) { autor = buchautor; titel = buchtitel; seiten = buchSeiten; } /** * Liefert die Seitenzahl dieses Buches zurck. */ public int gibSeiten() { return seiten; }

bung 2.77
public void printDetails() { System.out.println("Title: " + title); System.out.println("Autor: " + autor); System.out.println("Seiten: " + seiten); }

bung 2.78 Lschen Sie den Konstruktor und fgen Sie ein:
private String refNummer; /** * Gibt die Datenfelder autor und titel vor, wenn dieses Objekt * konstruiert wurde. */ public Buch(String buchautor, String buchtitel, int buchSeiten) { autor = buchautor; titel = buchtitel; seiten = buchSeiten; refNummer = ""; }

/** * Setzt die Referenznummer fr dieses Buch */ public void setzeRefNummer(String ref) { refNummer = ref; } /** * Gibt die Referenznummer fr dieses Buch aus */ public String gibRefNummer() { return refNummer; }

bung 2.79
public void detailsAusgeben() { System.out.println("Titel: " + titel); System.out.println("Autor: " + autor); System.out.println("Seiten: " + seiten); String refNummerString; if(refNummer.length() > 0) { refNummerString = refNummer; } else { refNummerString = "ZZZ"; } System.out.println("Referenznummer: " + refNummerString); }

bung 2.80
public void setzeRefNummer(String ref) { if(ref.length() > 2) { refNummer = ref; } else { System.out.println("Fehler! Die Referenznummer muss mindestens 3 Zeichen lang sein."); } }

bung 2.81 Fgen Sie das Datenfeld hinzu:


private int ausgeliehen;

Fgen Sie die Methoden hinzu:


/** * Verleiht das Buch. zhlt, wie oft das Buch ausgeliehen wurde. */ public void ausleihen() { ausgeliehen++; }

/** * Gibt an, wie oft das Buch ausgeliehen wurde. */ public int gibAusgeliehen() { return ausgeliehen; }

Fgen Sie diese Zeile zur Methode detailsAusgeben hinzu:


System.out.println("Ausgeliehen: " + ausgeliehen);

bung 2.82
public class Heizung { private int temperatur; /** * Erstellt eine neue Heizung mit einer Anfangstemperatur von 15. */ public Heizung () { temperatur = 15; } /** * Erhht die Temperatur um 5 Grad */ public void waermer() { temperatur += 5; } /** * Senkt die Temperatur um 5 Grad */ public void kuehler() { temperatur -= 5; } /** * Gibt die derzeitige Temperatur der Heizung aus */ public int gibTemperatur() { return temperatur; } }

bung 2.83
public class Heizung { private int temperatur; private int min; private int max; private int schrittweite;

/** * Erstellt eine neue Heizung mit einer Anfangstemperatur von 15. */ public Heizung(int minimum, int maximum) { min = minimum; max = maximum; temperatur = 15; schrittweite = 5; } /** * Erhht die Temperatur */ public void waermer() { int neueTemperatur = temperatur + schrittweite; if(neueTemperatur <= max) { temperatur = neueTemperatur; } } /** * Senkt die Temperatur */ public void kuehler() { int neueTemperatur = temperatur - schrittweite; if(neueTemperatur >= min) { temperatur = neueTemperatur; } } /** * Setzt die Schrittweite, die bestimmt, um wie viel die zwei * Methoden waermer() und kuehler() die Temperatur verndern. */ public void setzeSchrittweite(int inc) { if(inc >= 0) { schrittweite = inc; } } /** * Gibt die derzeitige Temperatur der Heizung aus */ public int gibTemperatur() { return temperatur; } }

Wenn die Methode setzeSchrittweite nicht auf negative Werte hin prft und ein negativer Wert bergeben wird, wird das Programm nicht wie gewnscht funktionieren. Die Minimal- und Maximalwerte knnen unter- bzw. berschritten werden.

Kapitel 3
bung 3.1 Das Klassendiagramm enthlt nur zwei Elemente: Laborkurs und Student. Das Objektdiagramm enthlt 4 Elemente: ein Objekt der Klasse Laborkurs und drei Objekte der Klasse Student. bung 3.2 Ein Klassendiagramm ndert sich, wenn Sie den Quelltext modifizieren. Dies geschieht, indem die Beziehungen zwischen den Klassen verndert werden oder Klassen neu erstellt bzw. gelscht werden. bung 3.3 Ein Objektdiagramm ndert sich, sobald das Programm luft. Es kann sich durch das Erstellen neuer Objekte oder den Aufruf von Methoden verndern. bung 3.4
private Lehrender tutor;

bung 3.6 Nichts passiert. Nein. Es sollte eine Fehlermeldung ausgegeben werden. bung 3.7 Ein Wert von Null wre nicht zulssig. bung 3.8 Der Test wrde das Ergebnis true liefern, falls eine der Bedingungen true ist. Das Ergebnis wre immer true, solange limit grer oder gleich Null ist. bung 3.9
false true false false true

bung 3.10
a==b

bung 3.11
(a || b) && (a != b)

bung 3.12
!(!a || !b)

bung 3.13 Nein. Die Methode unterstellt, dass der Wert nur zwei Stellen haben kann. bung 3.14 Nein. bung 3.15 Die genaue Definition kann nachgelesen werden in Abschnitt 15.17.3 von: The Java Language Specification Second Edition http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#239829 bung 3.16
2

bung 3.17
-4, -3, -2, -1, 0, 1, 2, 3, 4

bung 3.18
]-m,m[ (die Spanne von -(m-1) bis (m-1) )

bung 3.19 Solange der Wert niedriger ist als das Limit, wird er um 1 erhht (der Modulo kann ignoriert werden). Wenn der Wert das Limit erreicht, setzt die Modulo-Operation den Wert auf 0. Also erhht die Methode erhoehen den Wert um 1, bis das Limit erreicht ist. An diesem Punkt beginnt sie wieder bei 0.

bung 3.20
public void erhoehen() { wert = wert + 1; if(wert >= limit) { wert = 0; } }

Beide Wege der schrittweisen Erhhung sind gleich gut. bung 3.22 Die Voreinstellung der Zeit ist 00:00. Der Konstruktor erstellt zwei neue Instanzen Nummernanzeige, welche auf 0 initialisiert werden (im Konstruktor fr Nummernanzeige) bung 3.23 Sechzig Mal. Indem die Methode setzeUhrzeit() an dem Objekt verwendet wird. bung 3.24
public Editor(String fileName, int nummer)

bung 3.25
Rechteck fenster = new Rechteck(3,6);

bung 3.26 Er initialisiert die Zeit auf die Werte, die der Methode bergeben werden. Er verwendet die Methode setzeUhrzeit, um die Zeit auf den Ausgangswert zu setzen. bung 3.27 Beide Konstruktoren erstellen zwei neue Instanzen von Nummernanzeige. Der erste Konstruktor ruft anzeigeAktualisieren auf und der zweite setzeUhrzeit(stunde, minute). Im zweiten Konstruktor gibt es keinen Aufruf an anzeigeAktualisieren, weil dies in der Methode setzeUhrzeit geschieht.

bung 3.28
d1.drucke("datei1.txt", true); d1.drucke("datei2.txt", false); int status1 = d1.gibStatus(12); int status2 = d1.gibStatus(34);

bung 3.29, 3.30 1) ndern Sie anzeigeAktualisieren in Uhrenanzeige wie folgt:


/** * Aktualisieren Sie den internen String, der die Anzeige reprsentiert. */ private void anzeigeAktualisieren() { int stunde = stunden.gibWert(); String suffix = "am"; if(stunde >= 12) { stunde = stunde - 12; suffix = "pm"; } if(stunde == 0) { stunde = 12; } zeitanzeige = stunde + "." + minuten.gibAnzeigeWert() + suffix; }

2)
public Uhrenanzeige() { stunden = new Uhrenanzeige (12); //geaendert Minuten = new Uhrenanzeige (60); anzeigeAktualisieren(); } public Uhrenanzeige (int hour, int minute) { stunden = new Uhrenanzeige (12); //geaendert minuten = new Uhrenanzeige (60); setzeUhrzeit(stunde, minute); } private void anzeigeAktualisieren() { int stunde = stunden.gibWert(); if(stunde == 0) { stunde = 12; } zeitanzeige = stunde + "." + minuten.gibAnzeigeWert(); }

bung 3.36 Der Debugger zeigt an:


Nachricht nachricht = <Object reference> So wird darauf hingewiesen, dass nachricht nicht null ist. Die nchste Zeile, die markiert sein wird, ist nachricht.ausgeben().

bung 3.37 Diese Mal ist nachricht null. Die if-Anweisung wird anschlieend die folgende Zeile ausfhren: System.out.println("Keine neue Nachricht."); bung 3.38 Nachdem Sie Schritt hinein und anschlieend Schritt gedrckt haben, erfolgt diese Ausgabe: Von: Sophie Nach dem nchsten Schritt wird ausgegeben: An: Juan Und nach einem weiteren Schritt: Nachricht: Hi Juan! Schritt hinein geht in die Methode ausgeben(). Von da an wird jede ausgegebene Zeile ausgefhrt, indem jeweils Schritt gedrckt wird. Als Ergebnis wird jeweils eine Zeile nach der anderen gedruckt anstatt alle drei Zeilen hintereinander wie zuvor. bung 3.44
Bildschirm bildschirm = new Bildschirm(1024, 768); if(bildschirm.anzahlBildpunkte() > 2000000) { bildschirm.loeschen(true); }

Kapitel 4
bung 4.2
private ArrayList<Buch> bibliothek;

bung 4.3
10

bung 4.4
elemente.get(4);

bung 4.5
14

bung 4.6
notizen.add(treffen);

bung 4.7
verabredungen.remove(2);

bung 4.8
5

bung 4.9
public void entferneNotiz(int notiznummer) { if(notiznummer < 0) { // Keine gltige Nummer, nichts zu tun. } else if(notiznummer < anzahlNotizen()) { // Die Nummer ist gltig, wir knnen die Notiz entfernen. notizen.remove(notiznummer); } else { // Keine gltige Nummer, nichts zu tun. } }

bung 4.10
public void alleNotizenAusgeben()

bung 4.11 Nein. Wir haben keine Ahnung, wie viele Zeilen wir bentigen wrden.

bung 4.15
public void zeigeNotiz(int notiznummer) { if(notiznummer < 0) { System.out.println("Dies ist keine gltige Nummer"); } else if(notiznummer <= anzahlNotizen()) { // Die Nummer ist gltig, wir knnen die Notiz ausgeben. System.out.println(notizen.get(notiznummer)); } else { System.out.println("Dies ist keine gltige Nummer"); } }

bung 4.16
public void test() { int i = 10; while(i <= 95) { System.out.println(i); i = i + 5; }}

bung 4.17
public void summieren(int a, int b) { int nummer = a + 1; int summieren = 0; while(nummer < b) { summieren = summieren + nummer; nummer = nummer + 1; } System.out.println(summieren); }

bung 4.18
public boolean istPrim(int n) { int divisor = 2; while(divisor < n ) { if(n % divisor != 0) { return false; } divisor = divisor + 1; } return true; }

bung 4.19
public boolean suche(String suchbegriff) { int index = 0; boolean gefunden = false; while(index < notizen.size() && !gefunden) { String notiz = notizen.get(index); if(notiz.contains(suchbegriff)) { gefunden = true; } else { index++; } } if(gefunden) { System.out.println("Suchbegriff in Notiz gefunden: " + notiz.get(index)); } else { System.out.println("Suchbegriff nicht gefunden."); } }

bung 4.20
public void alleNotizenAusgeben() { int index = 0; for(String notiz : notizen) { System.out.println(index + ": " + notiz); index++; } }

bung 4.21 Der Wert verndert sich nicht.


public boolean suche(String suchbegriff) { int index = 0; boolean gefunden = false; int size = notizen.size(); while(index < size && !gefunden) { String notiz = notizen.get(index); if(notiz.contains(suchbegriff)) { gefunden = true; } else { index++; } } if(gefunden) { System.out.println("Suchbegriff in Notiz gefunden: " + notizen.get(index)); } else { System.out.println("Suchbegriff nicht gefunden."); } }

bung 4.22
/** * Zeige eine Notiz an. * @param notiznummer Die Nummer der anzuzeigenden Notiz. */ public void zeigeNotiz(int notiznummer) { if(notiznummer < 1) { // Keine gltige Nummer, nichts zu tun. } else if(notiznummer <= anzahlNotizen()) { // Die Nummer ist gltig, wir knnen die Notiz ausgeben. System.out.println(notizen.get(notiznummer - 1)); } else { // Keine gltige Nummer, nichts zu tun. } } /** * Gib alle Notizen dieses Notizbuches aus. */ public void alleNotizenAusgeben() { int index = 0; for(String notiz : notizen) { System.out.println((index + 1) + ": " + notiz); index++; } } /** * Entfernen Sie eine Notiz aus dem Notizbuch, falls diese existiert. * @param notiznummer Die Nummer der Notiz, die entfernt werden soll. */ public void entferneNotiz(int notiznummer) { if(notiznummer < 1) { // Keine gltige Nummer, nichts zu tun. } else if(notiznummer < anzahlNotizen()) { // Dies ist keine gltige Nummer. notizen.remove(notiznummer -1); } else { // Keine gltige Nummer, nichts zu tun. } }

bung 4.23-4.25
import java.util.ArrayList; /** * Speichere Details von Vereinsmitgliedschaften. * * @author (Ihr Name) * @version (eine Versionsnummer oder ein Datum) */ public class Verein { ArrayList<Mitgliedschaft> mitglieder; /** * Konstruktor fr Objekte der Klasse Verein */ public Verein() { mitglieder = new ArrayList<Mitgliedschaft>(); } /** * Fge ein neues Mitglied in die Mitgliederliste ein. * @param mitglied Infos ber das einzufgende Mitglied. */ public void beitreten(Mitgliedschaft mitglied) { mitglieder.add(mitglied); } /** * @return Die Zahl der Mitglieder (Mitgliedschaft-Objekte) des * Vereins. */ public int anzahlMitglieder() { return mitglieder.size(); } }

bung 4.26
public void beenden(){ for(Posten posten : postenliste) { System.out.println(posten.gibNummer() + ": " + posten.gibBeschreibung()); // Enthlt smtliche Details eines Hchstgebots. Gebot hoechstesGebot = posten.gibHoechstesGebot(); if( hoechstesGebot != null) { System.out.println(" Hchstbietender: " + hoechstesGebot.gibBieter().gibName()); System.out.println(" Gebot: " + hoechstesGebot.gibHoehe()); } else { System.out.println(" Unverkauft"); } } }

bung 4.27
/** * Gibt eine Liste unverkaufter Posten zurck */ public ArrayList<Posten> gibUnverkaufte() { ArrayList<Posten> unverkauftePosten = new ArrayList<Posten>(); for(Posten posten : postenliste) { Gebot hoechstesGebot = lot.gibHoechstesGebot(); if(hoechstesGebot == null) { unverkauftePosten.add(posten); } } return unverkauftePosten; }

bung 4.28 Wenn die Methode gibPosten mit einer Postennummer aufgerufen wird, die entfernt wurde, wird folgende Meldung auf der Konsole ausgegeben: Interner Fehler: Falscher Posten zurckgegeben. Nummer: 1 bung 4.29
/** * Gib den Posten mit der gegebenen Nummer wieder. Gib null aus, falls * es einen Posten mit dieser Nummer nicht gibt. * @param number Die Nummer des zurckzuliefernden Postens. */ public Lot gibPosten(int nummer) { for(Posten posten : postenliste) { if(posten.gibNummer() == nummer) { return posten; } else if (posten.gibNummer() > nummer) { System.out.println("Posten Nummer: " + nummer + " existiert nicht."); return null; } } return null; //wenn es gar keine Posten gibt }

bung 4.30
/** * Entferne den Posten mit der gegebenen Postennummer. * @param nummer Die Nummer des Postens, der entfernt werden soll * @return Den Posten mit der gegebenen Nummer, oder null, falls * es einen solchen Posten nicht gibt. */ public Posten entfernePosten(int nummer) { //Zuerst finden wir den Posten mit der gegebenen Nummer Posten posten = gibPosten(nummer); if(posten != null) { //Dann knnen wir die Methode entfernePosten mit posten als Argument verwenden postenliste.remove(posten); } return posten; }

bung 4.31 Die Dokumentation der Klasse LinkedList finden Sie hier: http://java.sun.com/j2se/1.5.0/docs/api/java/util/LinkedList.html
LinkedList hat die folgenden Methoden, die ArrayList nicht hat: void addFirst(E o) void addLast(E o) E getFirst() E getLast() ListIterator<E> listIterator(int index) E removeFirst() E removeLast()

Die Klasse ArrayList hat die folgenden Methoden, die LinkedList nicht hat:
void ensureCapacity(int minCapacity) protected void removeRange(int fromIndex, int toIndex) void trimToSize()

bung 4.32
/** * Liefere die Anzahl der Mitglieder, die im angegebenen Monat * Mitglied geworden sind * @param monat Der Monat des Beitritts. * @return Die Anzahl der Mitglieder. */ public int beigetretenInMonat(int monat) { if(monat < 1 || monat > 12) { System.out.println("Monat " + monat + " auerhalb des gltigen Bereichs. Muss sich im Bereich 1 ... 12 befinden"); } int count = 0; while(Mitgliedschaft mitglied : mitglieder) { if(mitglied.gibMonat() == monat) { anzahl++; } } return anzahl; }

bung 4.33
public ArrayList entfernen(int monat, int jahr) { if(monat < 1 || monat > 12) { System.out.println("Monat " + monat + " auerhalb des gltigen Bereichs. Muss sich im Bereich 1 ... 12" befinden); } ArrayList<Mitgliedschaft> entfernt = new ArrayList<Mitgliedschaft>(); Iterator<Mitgliedschaft> it = mitglieder.iterator(); while(it.hasNext()) { Mitgliedschaft mitglieder = it.next(); if(mitglied.gibMonat() == monat && mitglied.gibJahr() == jahr) { // Muss die Methode entfernen des Iterators verwenden. // Sehen Sie in der Dokumentation fr den Iterator nach, um sich nher zu informieren. it.remove(); entfernt.add(mitglied); } } return entfernt; }

bung 4.34
public void alleArtikelAnzeigen() { for(Artikel artikel : lager) { System.out.println(artikel); } }

bung 4.35
public Artikel findeArtikel(int nummer) { for(Artikel artikel : lager) { if(artikel.gibNummer() == nummer) { return artikel; } } return null; }

bung 4.36
public int mengeImBestand(int nummer) { Artikel artikel = findeArtikel(nummer); if(artikel != null) { return artikel.gibBestand(); } else { return 0; } }

bung 4.37
public void aufnehmen(int nummer, int menge) { Artikel artikel = findeArtikel(nummer); if(artikel != null) { artikel.erhoeheBestand(menge); } }

bung 4.38
/** * Gib Details aller Artikel aus, deren Bestand unter * den gegebenen Minimalwert gesunken ist */ public void niedrigenArtikelbestandAusgeben(int minimum) { for(Artikel artikel : lager) { if(artikel.gibBestand() < minimum) { System.out.println(artikel); } } } /** * Fge der Liste einen Artikel hinzu. * @param item Hinzuzufgender Artikel. */ public void neuerArtikel(Artikel artikel) { if( ! lager.contains(artikel)) { lager.add(artikel); } }

/** * Versuche im Bestand einen Artikel mit dem gegebenen Namen zu finden. * @return Den identifizierten Artikel oder Null, falls es keinen * mit einem bereinstimmenden Namen gibt. */ public Artikel findeArtikel(String name) { for(Artikel artikel : lager) { if(artikel.gibName().equals(name)) { return artikel; } } return null; }

bung 4.39 Die aktivste Zeit des Tages: die 18. Stunde. bung 4.40
Person[] leute;

bung 4.41
boolean[] verfuegbar;

bung 4.43
int[] zaehler; boolean[] belegt = new boolean[5000];

bung 4.44
temperaturen = new double[60]; urls = new String[90]; automaten = new Ticketautomat[5];

bung 4.45 Keine. Es wird nur ein Array zum Halten von String-Objekten erzeugt. bung 4.46
double[] preise = new double[50];

bung 4.47 Es wird eine ArrayIndexOutOfBoundsException: 24 geworfen

bung 4.48
/** * Gib die Anzahl der Zugriffe in den Stunden eines * Tages nach Stunden sortiert auf der Konsole aus. * Diese Werte sollten zuerst mit einem Aufruf von * 'analysiereStundendaten' berechnet werden. */ public void analysiereStundendaten() { System.out.println("Stunde: Zugriffe"); int stunde = 0; while(stunde<zugriffeInStunde.length) { System.out.println(stunde + ": " + zugriffeInStunde[stunde]); stunde++; } }

bung 4.49
public void hoehereAusgeben(double[] noten, double mittelwert) { for(int index = 0; index < noten.length; index++) { if(noten[index] > mittelwert) { System.out.println(noten[index]); } } }

bung 4.50
public void notizenAusgeben() { for(int index=0; index < notizen.size(); index++) { System.out.println(notizen.get(index)); } }

bung 4.51
public void notizenAusgeben() { for(String notiz : notizen) { System.out.println(notiz); } }

bung 4.52
/** * Liefere die Anzahl aller Zugriffe, die in der Logdatei * protokolliert sind. */ public int anzahlZugriffe() { int gesamt = 0; // Addiere den Wert jedes Elements in zugriffeInStunde // zu gesamt hinzu. for(int zugriffe : zugriffeInStunde) { gesamt = gesamt + zugriffe; } return gesamt; }

bung 4.54
/** * Liefere die aktivste Stunde des Tages */ public int aktivsteStunde() { int aktivsteStunde = 0; for(int stunde = 1; stunde < zugriffeInStunde.length; stunde++) { if( zugriffeInStunde[stunde] > zugriffeInStunde[aktivsteStunde]) { aktivsteStunde = stunde; } } return aktivsteStunde; }

bung 4.55
/** * Liefere die ruhigste Stunde des Tages */ public int ruhigsteStunde() { int ruhigsteStunde = 0; for(int stunde = 1; stunde < zugriffeInStunde.length; stunde++) { if( zugriffeInStunde[stunde] < zugriffeInStunde[ruhigsteStunde]) { ruhigsteStunde = stunde; } } return ruhigsteStunde; }

bung 4.56 In der oben genannen Implementierung ist dies die erste Stunde, in der der hchste Wert gefunden wird.

bung 4.57
/** * Liefere den aktivsten zweistndigen Abschnitt. */ public int aktivsterZweistundenAbschnitt() { int aktivsterAbschnitt = 0; int zugriffeImAktivstenAbschnitt = 0; for(int stunde = 0; stunde < zugriffeInStunde.length-1; stunde++) { int zugriffeImAbschnitt = zugriffeInStunde[stunde] + zugriffeInStunde[stunde+1]; if(zugriffeImAbschnitt > zugriffeImAktivstenAbschnitt) { aktivsterAbschnitt = stunde; zugriffeImAktivstenAbschnitt = zugriffeImAbschnitt; } } return aktivsterAbschnitt; }

bung 4.63
public void listnotizen() { int index = 0; do{ if(!notizen.isEmpty()) { System.out.println(notizen.get(index)); index++; } } while(index < notizen.size()); }

Kapitel 5
bung 5.2 Die Dokumentation enthlt die folgenden Abschnitte:

Eine allgemeine Beschreibung der Klasse, ihres Zwecks und wie sie verwendet wird Eine kurze Zusammenfassung der Datenfelder Eine kurze Zusammenfassung der Konstruktoren Eine kurze Zusammenfassung der Methoden Eine detaillierte Beschreibung der Datenfelder Eine detaillierte Beschreibung der Konstruktoren Eine detaillierte Beschreibung der Methoden

bung 5.4 Ja: public boolean endsWith(String suffix) bung 5.5 Ja: public int length() bung 5.7 Signatur: public String trim() Beispiel: String trimmedText = text.trim(); Kontrollzeichen werden wie Leerzeichen behandelt: "...it trims all ASCII control characters as well" bung 5.8 Fgen Sie die Zeile
eingabe = eingabe.trim();

zur Methode starten() des Kundendienstsystems hinzu. bung 5.9 Fgen Sie die Zeile
eingabe = eingabe.toLowerCase(); zur Methode starten() des Kundendienstsystems hinzu.

bung 5.10
boolean

bung 5.11
if(input.equals("ade")) { fertig = true; }

bung 5.12 Package: java.util Sie generiert Zufallszahlen Eine Instanz wird erzeugt, indem einer dieser beiden Konstruktoren verwendet wird:
Random zufallsgenerator = Random(); Random zufallsgenerator = Random(long seed);

Um eine Zufallszahl zu erzeugen:


random.nextInt();

bung 5.13
Random zufallsgenerator = new Random(); random.nextInt();

bung 5.14
import java.util.Random;

public class ZufallszahlenTester { private Random zufallsgenerator;

// der Zufallszahlengenerator

public RandomTester() { zufallsgenerator = new Random(); } public void eineZufallszahlAusgeben() { System.out.println(zufallsgenerator.nextInt()); } public void zufallszahlenAusgeben(int anzahl) { for(int i=0; i<anzahl; i++) { eineZufallszahlAusgeben(); } } }

bung 5.15
0,1,2,...,99,100

bung 5.16
public int wuerfeln() { return zufallsgenerator.nextInt(6) + 1; }

bung 5.17
public String gibAntwort() { int antwort = zufallsgenerator.nextInt(3); if(antwort == 0) { return "ja"; } else if(antwort == 1) { return "nein"; } else { return "vielleicht"; } }

bung 5.18
private ArrayList antworten; public ZufallszahlenTester() // Konstruktor { antworten = new ArrayList(); antworten.add("ja"); antworten.add("wei nicht"); ... } public String gibAntwort() { return antworten.get(zufallsgenerator.nextInt(antworten.size())); }

bung 5.19
public int liefereEineZufallszahl(int max) { return zufallsgenerator.nextInt(max) + 1; }

bung 5.20
public int liefereEineZufallszahl(int min, int max) { return zufallsgenerator.nextInt(max - min + 1) + min; } public int liefereEineZufallszahl(int max) { return liefereEineZufallszahl(1, max); }

bung 5.21 Siehe modifizierter Beantworter in: Listing 5.3, Seite 182-183.

bung 5.22 Wenn Sie weitere Antworten hinzufgen, werden diese ebenfalls zufllig angezeigt, und zwar zusammen mit den bereits existierenden Antworten. Das liegt daran, dass die Lnge der Antwortliste zum Generieren der Zufallszahl verwendet wird. bung 5.23 Siehe http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html und den restlichen Abschnitt 5.6 in diesem Buch. bung 5.24 Methoden in HashMap, die vom Typparameter abhngig sind:
Set<Map.Entry<K,V>> entrySet() V get(Object key) Set<K> keySet() V put(K key, V value) void putAll(Map<? extends K,? extends V> m) V remove(Object key) Collection<V> values()

Ja, derselbe Typ knnte fr beide Parameter eingesetzt werden. bung 5.25
public class MapTester { private HashMap<String,String> telefonbuch = new HashMap<String,String>(); public MapTester() { telefonbuch.put("Homer Jay Simpson", "(531) 9392 4587"); telefonbuch.put("Charles Montgomery Burns", "(531) 5432 1945"); telefonbuch.put("Apu Nahasapeemapetilon", "(531) 4234 4418"); } public void nummerEintragen(String name, String nummer) { telefonbuch.put(name, nummer); } public String nummerSuchen(String name) { return telefonbuch.get(name); } }

bung 5.26 Der neue Eintrag berschreibt den bestehenden.

bung 5.27 Beide Werte verbleiben in der Abbildung. HashMap verwendet den Schlssel nur, um Eintrge zu unterscheiden, nicht die Werte. bung 5.28
telefonbuch.containsKey("Homer Jay Simpson");

bung 5.29 Es wird null zurckgeliefert. bung 5.30


telefonbuch.size()

bung 5.28 Siehe modifizierter Beantworter in: Listing 5.4, Seite 189-190. bung 5.32 Gemeinsamkeiten von HashSet und ArrayList: Beide enthalten eine Sammlung von Objekten. Es ist mglich Objekte hinzuzufgen (mit der Methode add). Es ist mglich Objekte zu entfernen (mit der Methode remove method). Beide haben eine Methode fr die Gre (size()). Beide bieten eine Methode iterator(), um ber alle Elemente iterieren zu knnen. Unterschiede: In HashSet kann jedes Objekt nur einmal in der Menge vorkommen (weil es sich bei der Menge um ein Set handelt). In einer ArrayList kann ein Objekt mehrfach vorkommen. Eine ArrayList ist geordnet. Ein HashSet ist nicht geordnet. bung 5.33 Sie knnen regulre Ausdrcke verwenden um zu defininieren, wie ein String aufgeteilt sein sollte. Hier ist Einiges an regulren Ausdrcken in Java dokumentiert: http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html#sum bung 5.34
String[] woerter = s.split("[ \t]");

bung 5.35 Die Verwendung von HashSet garantiert, dass es keine doppelten Elemente gibt, aber die Reihenfolge der Wrter wird nicht beibehalten.

bung 5.36 Es werden leere Strings erzeugt, was wahrscheinlich nicht beabsichtigt war. Um dies zu beheben, knnen wir wie folgt Abhilfe schaffen:
String[] woerter = s.split("[ \t]+");

bung 5.38 Siehe die modifizierte Methode start() des Kundendienstsystems in Listing 5.6, Seite 194-195 sowie das modifizierte generiereAntwort() in Beantworter in Listing 5.7, Seite 195. bung 5.40 Die in der Klasse Beantworter im Projekt Technischer-Kundendienst-komplett notwendigen Modifikationen: Fgen Sie ein neues Feld hinzu:
private HashMap<String,String> synonymMap;

Initialisieren Sie es im Konstruktor:


synonymMap = new HashMap<String,String>();

Fgen Sie dies zur Methode generiereAntwort direkt hinter dem if-Block hinzu:
else { //Prfe, ob es sich um ein Synonym handelt String synonym = synonymMap.get(wort); if(synonym != null) { return antwortMap.get(synonym); } }

Um ein Beispiel zu erstellen, ersetzen Sie


antwortMap.put("abstrzt","Tja,...); durch synonymMap.put("abstrzt", "absturz");

bung 5.44 Beispiele fr Schlsselwrter:


@author @version @param @return

Diese Schlsselwrter werden besonders beachtet, weshalb sie in der Dokumentation hervorgehoben sind.

bung 5.48 Sie erzeugen einen Canvas, indem Sie einen der drei Konstruktoren aufrufen. Sie machen ihn sichtbar, indem Sie die diese Methode aufrufen: setVisible(true); Mit dieser Methode zeichnen Sie eine Linie: drawLine(int x1, int y1, int x2,
int y2)

Sie lschen etwas mittels einer dieser vier verschiedenen Methoden:


erase() eraseCircle(int xPos, int yPos, int diameter) eraseRectangle(int xPos, int yPos, int width, int height) erase(Shape shape)

Die Methode draw zeichnet lediglich die Kontur einer Figur, whrend die Methode fill das Innere der Figur mit einer Farbe fllt.
wait(int milliseconds) wartet eine festgelegte Zahl von Millisekunden bis zur

Fertigstellung. bung 5.50+5.51


public void zeichneRahmen() { int rahmenbreite = 20; Dimension flaeche = leinwand.getSize(); Rectangle r = new Rectangle(rahmenbreite, rahmenbreite, (int) flaeche.getWidth() - 2*rahmenbreite, (int) flaeche.getHeight() 2*borderSize); leinwand.draw(r); }

bung 5.52
public void springenLassen(int anzahlBaelle) { int boden = 400; // Position der Bodenlinie leinwand.setVisible(true); // Den Boden zeichnen leinwand.drawLine(50, boden, 550, boden); // Baelle erzeugen und anzeigen HashSet<Ball> baelle = new HashSet<Ball>(); for(int i=0; i< anzahlBaelle; i++) { Ball ball = new Ball(50+32*i, 50, 16, Color.blue, boden, leinwand); baelle.add(ball); ball.zeichnen(); } // die Blle springen lassen boolean fertig = false; while(!fertig) { leinwand.wait(50); // kurze Pause for(Ball ball : baelle) { ball.bewegen(); // Stoppen, sobald Ball weit genug gesprungen if(ball.getXPosition() >= 550 + 32*anzahlBaelle) { fertig = true; } } } for(Ball ball : baelle) { ball.loeschen(); } }

bung 5.53
HashSet ist am besten geeignet, weil es gewhrleistet, dass wir von jedem Ball nur ein Exemplar in der Sammlung haben. HashMap knnte ebenfalls zu diesem Zweck

eingesetzt werden, aber wir bentigen keine Abbildung, daher wre dies eine schlechte Wahl. bung 5.54
// Baelle erzeugen und anzeigen Random random = new Random(); HashSet<Ball> baelle = new HashSet<Ball>(); for(int i=0; i<anzahlBaelle; i++) { Dimension flaeche = myCanvas.getSize(); int x = random.nextInt((int) flaeche.getWidth()); int y = random.nextInt((int) flaeche.getHeight()); Ball ball = new Ball(x, y, 16, Color.blue, boden, leinwand); baelle.add(ball); ball.zeichnen(); }

bung 5.55+5.56 Laden Sie sich folgende Datei herunter (leider nur in Englisch): balls-inabox.zip bung 5.58
public static final double TOLERANZ = 0.001; private static final int BESTEHEN_GRENZE = 40; public static final char HILFETASTE = 'h';

bung 5.59 Die Konstanten werden verwendet, um die Positionen von Daten in einem String zu indizieren. Es handelt sich um eine gute Nutzung von Konstanten. bung 5.60 Sie mssten lediglich die Werte der Konstanten modifizieren, die alle an einer Stelle definiert sind. Wenn diese Zahlen nicht als Konstanten definiert wren, sondern direkt verwendet wrden, wren nderungen an vielen Stellen im Quelltext erforderlich. bung 5.61
public class Namensgenerator { public String generiereStarWarsNamen(String vorname, String nachname, String maedchennameDerMutter, String geburtsort) { String swVorname = nachname.substring(0,3) + vorname.substring(0,2); String swNachname = maedchennameDerMutter.substring(0,2) + geburtsort.substring(0,3); return swVorname + " " + swNachname; } }

bung 5.62 Strings sind unvernderlich und knnen daher nicht modifiziert werden. Die aufgerufene Methode verndert nicht die Instanz 's', sondern liefert ein neues Objekt, bei dem der String in Grobuchstaben gesetzt wird. Die korrekte Art, dies umzusetzen ist:
String allesGrossS = s.toUpperCase(); System.out.println(allesGrossS);

bung 5.63 Die Variablen a und b enthalten Werte. Wenn diese Werte als Argumente an die Methode weitergegeben werden, werden sie in die Variablen i1 und i2 kopiert. In der Methode vertauschen wir nun die Werte von i1 und i2. Dies hat keine Auswirkungen auerhalb der Methode, da i1 und i2 lokale Variablen innerhalb der Methode sind. Nach dem Aufruf der Methode werden die Variablen a und b immer noch dieselben Werte enthalten wie vor dem Aufruf.

Kapitel 6
bung 6.6 Es reicht aus, nur einige der Mglichkeiten auszuprobieren. Hierbei ist es sinnvoll sowohl die Grenzbereiche zu prfen als auch einen Wert, der nicht den Grenzbereich betrifft. Beispiele fr Uhrzeiten, die getestet werden knnen, sind: 9, 13, 17. bung 6.7 Ja, es ist mglich, dieselbe Verabredung fr verschiedene Uhrzeiten innerhalb eines einzigen Tages zu verwenden. Die Tests besitzen dann nicht mehr die gleiche Aussagekraft, weil wir den Unterschied zwischen den Objekten nicht mehr erkennen knnen (es gibt nmlich keinen), und daher knnen wir nicht sicher sein, dass die Verabredungen den korrekten Zeitabschnitten zugeordnet sind. Es wrde Sinn machen, dieselbe Verabredung zu verwenden, wenn es einen regelmig wiederkehrenden Termin gbe, z.B. wenn Sie ein tglich stattfindendes Meeting mit jemandem htten. bung 6.8 Diverse Tests werden fehlschlagen.
vereinbareTermin verwendet nur den Beginn einer Verabredung um zu prfen, ob

der Zeitabschnitt zur Verfgung steht und kann daher die anderen Verabredungen berschreiben oder den Grenzbereich berschreiten (was zu einer Exception fhrt). bung 6.9 Positive Testflle Negative Testflle 6.1 6.2 6.3 6.4 6.5 6.6 X X X X X X

Andere negative Tests: - Testen, wie die Anwendung reagiert, wenn null statt einer Verabredung bergeben wird. - Null und negative Werte fr die Dauer und Zeit testen. Ein positiver Test knnte darin bestehen zu testen, ob Verabredungen von mehr als einer Stunde die korrekte Dauer haben, nachem sie eingegeben wurden.

bung 6.13 Der Regressionstest, den wir bisher durchgefhrt haben, erfordert immer noch eine manuelle Inspektion der Ausgabe. Dies wre sehr schwierig und zeitraubend, wenn wir mehrere hunderte oder tausende von Tests bruchten. bung 6.15 Eine Testklasse enthlt zunchst folgende Methoden: Den Konstruktor
setUp() tearDown()

bung 6.15 1. Beginnen Sie mit der Aufzeichnung einer neuen Testmethode namens testFindSpace10. 2. Erzeugen Sie ein Tag-Objekt. 3. Erzeugen Sie eine Verabredung mit einstndiger Dauer. 4. Vereinbaren Sie diese Verabredung fr 9:00 Uhr an dem Tag-Objekt. 5. Vergewissern Sie sich, dass das Ergebnis gleich true ist. 6. Erzeugen Sie eine weitere Verabredung mit einstndiger Dauer. 7. Rufen Sie die Methode findePlatz an dem Tag-Objekt mit der neuen Verabredung auf. 8. Vergewissern Sie sich, dass das Ergebnis gleich 10 ist. bung 6.19 Das Fenster mit dem Testergebnis meldet einen Fehlschlag und zeigt eine groe rote Leiste an. bung 6.21 Das Konsolenfenster zeigt Folgendes an:
Testen der Addition. Ergebnis ist: 7 Testen der Subtraktion. Ergebnis ist: 5 Alle Tests erfolgreich.

Es gibt keine Mglichkeit (nur aus der Ausgabe der Tests) den Schluss zu ziehen, dass die Tests bestanden wurden. Wir erhalten nur den Testergebniswert, dem wir nicht vertrauen sollten.

bung 6.22 Der Aufruf von testPlus() liefert den Wert 1 zurck. Es ist nicht das gleiche Ergebnis wie das, das allesTesten() zurckgeliefert hat. Ein weiterer Aufruf von testPlus() liefert 7 zurck. Es sollte immer die gleiche Antwort geliefert werden. Gem dem Quelltext sollte 7 geliefert werden. bung 6.23 Nein. bung 6.24 Die Methode testMinus() hnelt in ihrer Struktur der Methode testPlus(). Nach einer manuellen Ausfhrung von testMinus() mchten wir uns die Methode minus() einmal nher ansehen. Auerdem knnten wir uns vormerken zu prfen, ob die negativen Werte korrekt behandelt werden. bung 6.25 Aufgerufene Methode
Anfangszustand clear zifferGetippt(3) plus zifferGetippt(4) gleich anzeigewert linkerOperand letzterOperator

0 0 3 0 4 7

0 0 0 3 3 0

'' '' '' '+' '+' '+'

bung 6.26 Nein. Die Methode gleich prft nicht explizit den Wert von letzterOperator, wenn dieser '-' ist. Daher resultiert alles andere als ein '+'-Zeichen in einer Subtraktion.

bung 6.27 Aufgerufene Methode


Anfangszustand clear zifferGetippt(3) plus zifferGetippt(4) gleich clear anzeigewert linkerOperand letzterOperator

0 0 3 0 4 7 0

0 0 0 3 3 0 0

'' '' '' '+' '+' '+' '+'

Die Recheneinheit befindet sich nicht in demselben Zustand wie nach dem letzten Aufruf von clear() (letzterOperator weicht ab). Dies knnte sich stark auf folgende Aufrufe auswirken und ist hchstwahrscheinlich der Grund fr das inkonsistente Ergebnis, das wir in bung 6.22 erhielten. bung 6.28 Zwei Dinge sind uns whrend der manuellen Ausfhrung aufgefallen: 1. gleich() testet nicht explizit auf den Wert '-' von letzterOperator. 2. clear() leert nicht alle Datenfelder. Die Methode clear sollte folgendermaen gendert werden:
public void clear() { anzeigewert = 0; linkerOperand = 0; letzterOperator = ' '; }

Die Methode gleich sollte folgendermaen gendert werden:


public void gleich() { if(letzterOperator == '+') { anzeigewert = linkerOperand + anzeigewert; } if(letzterOperator == '-') { anzeigewert = linkerOperand - anzeigewert; } else { //nichts tun } linkerOperand = 0; }

bung 6.29 Aufgerufene Methode


Anfangszustand clear zifferGetippt(9) plus zifferGetippt(1) minus zifferGetippt(4) gleich anzeigewert linkerOperand letzterOperator

0 0 9 0 1 0 4 6

0 0 0 9 9 10 10 0

'' '' '' '+' '+' '-' '-' '-'

Das Ergebnis sollte 6 sein. Dies entspricht tatschlich dem anzeigewert am Ende der manuellen Ausfhrung. bung 6.31 Ja. Die Ausgabe liefert dieselben Informationen, die wir auch aus den Tabellen in den vorangegangenen bungen haben. bung 6.33 Die Ausgabeanweisungen mssen wieder entfernt werden. Die Ausgabeanweisungen knnten weniger fehleranfllig sein als eine manuelle Ausfhrung. Die Ausgabeanweisungen sind mglicherweise einfacher zu schreiben (das ist eher subjektiv). Die Ausgabeanweisungen lassen sich leichter verwenden, wenn Sie eine Korrektur verifizieren mssen. Die Aktivitt der manuellen Ausfhrung vermittelt unter Umstnden ein besseres Verstndnis des Programms. bung 6.34 Siehe das Projekt auf der CD: Rechner-komplett

bung 6.35 Die Bugs in dem Projekt Ziegelsteine sind folgende: Klasse Ziegelstein:
gibOberflaeche() seite1 wird zweimal bei der Berechnung von total addiert, seite2 hingegen nicht (dieser Fehler ist leider bei der deutschen bersetzung des

Projektes versehentlich behoben worden!) gibGewicht() 1000 sollte 1000.0 sein Klasse Palette:
gibHoehe() das % sollte ein * sein gibGewicht() + GRUNDGEWICHT fehlt

Kapitel 7
bung 7.1 a) Was tut diese Anwendung? "Die Welt von Zuul" ist ein sehr einfaches, textbasiertes Abenteuerspiel. Die Anwender knnen in einer virtuellen Umgebung umherwandern. Das ist alles. b) Welche Befehle akzeptiert das Spiel?
help quit go "Richtung"

c) Was bewirken die einzelnen Befehle? help: Liefert Informationen ber die zur Verfgung stehenden Befehle. quit: Beendet das Spiel. go "Richtung": Lsst den Spieler durch die Tr in die gewhlte Richtung gehen. Folgende Richtungen knnen gewhlt werden: north, east, south und west. d) Wie viele Rume gibt es in der virtuellen Umgebung? Es gibt fnf Rume. e) Zeichnen Sie eine Karte der existierenden Rume. (Grafik noch unbersetzt: Campus Pub -> Cafeteria, Main Entrance -> Haupteingang, Lecture Theatre -> Vorlesungssaal, Computing Lab -> Rechnerraum, Computing Admin- .> Verwaltungsbro)

bung 7.2 Die folgenden Beschreibungen wurden der Dokumentation der Klassen-Quelltexte entnommen. Parser: Dieser Parser liest Benutzereingaben und wandelt sie in Befehle fr das AdventureGame um. Bei jedem Aufruf liest er eine Zeile von der Konsole und versucht, diese als einen Befehl aus bis zu zwei Wrtern zu interpretieren. Er liefert den Befehl als ein Objekt der Klasse Befehl zurck.

Der Parser verfgt ber einen Satz an bekannten Befehlen. Er vergleicht die Eingabe mit diesen Befehlen. Wenn die Eingabe keinen bekannten Befehl enthlt, dann liefert der Parser ein als unbekannter Befehl gekennzeichnetes Objekt zurck. Spiel: Dies ist die Hauptklasse der Anwendung "Die Welt von Zuul". "Die Welt von Zuul" ist ein sehr einfaches, textbasiertes Adventure-Game. Ein Spieler kann sich in einer Umgebung bewegen, mehr nicht. Das Spiel sollte auf jeden Fall ausgebaut werden, damit es interessanter wird! Zum Spielen muss eine Instanz dieser Klasse erzeugt werden und an ihr die Methode "spielen" aufgerufen werden. Diese Instanz erzeugt und initialisiert alle anderen Objekte der Anwendung: Sie legt alle Rume und einen Parser an und startet das Spiel. Sie wertet auch die Befehle aus, die der Parser liefert, und sorgt fr ihre Ausfhrung. Befehl: Objekte dieser Klasse halten Informationen ber Befehle, die der Benutzer eingegeben hat. Ein Befehl besteht momentan aus zwei Zeichenketten: einem Befehlswort und einem zweiten Wort. Beim Befehl "nimm karte" beispielsweise sind die beiden Zeichenketten "nimm" und "karte". Befehle werden von Benutzern dieser Klasse auf Gltigkeit berprft. Wenn ein Spieler einen ungltigen Befehl eingegeben hat (ein unbekanntes Befehlswort), dann ist das Befehlswort <null>. Wenn der Befehl aus nur einem Wort besteht, ist das zweite Wort <null>. Befehlswoerter: Diese Klasse enthlt eine Aufzhlung aller Befehlswrter, die dem Spiel bekannt sind. Mit ihrer Hilfe werden eingetippte Befehle erkannt. Raum: Ein "Raum" reprsentiert einen Ort innerhalb der virtuellen Landschaft des Spiels. Ein Raum ist ber Ausgnge mit anderen Rumen verbunden. Mgliche Ausgnge liegen im Norden, Osten, Sden und Westen. Fr jede Richtung hlt ein Raum eine Referenz auf den benachbarten Raum. bung 7.5 Fgen Sie die Methode rauminfoAusgeben() von Seite 254 zu der Klasse Spiel hinzu. Dann ersetzen Sie die entsprechenden Zeilen aus den Methoden willkommenstextAusgeben() und wechsleRaum() durch einenAufruf der Methode rauminfoAusgeben().

bung 7.6 Siehe Seite 258/259. bung 7.7 Fgen Sie diese Methode zu der Klasse Raum hinzu:
/** * Liefere eine Beschreibung der Ausgnge dieses Raumes * beispielsweise "Ausgnge: north west". */ public String gibAusgaengeAlsString() { String returnString = "Ausgnge: "; if(nordausgang != null) returnString += " north "; if(ostausgang != null) returnString += "east "; if(suedausgang != null) returnString += "south "; if(westausgang != null) returnString += "west "; return returnString; }

Modifizieren Sie rauminfoAusgeben in der Klasse Spiel folgendermaen:


private void rauminfoAusgeben() { System.out.println("Sie sind " + aktuellerRaum.gibBeschreibung()); System.out.print(aktuellerRaum.gibAusgaengeAlsString()); System.out.println(); }

bung 7.8 Siehe das Projekt Zuul-besser auf der CD. bung 7.9 bersetzter Auszug aus http://java.sun.com: Sie liefert als eine Menge die Schlssel, die in dieser Abbildung enthalten sind. Die Menge ist mit der Abbildung gekoppelt, daher werden Vernderungen der Abbildung in der Menge sichtbar und umgekehrt. Die Menge untersttzt das Entfernen von Elementen, wodurch die entsprechende Zuordnung aus dieser Abbildung mittels Iterator.remove, Set.remove, removeAll, retainAll und clear-Operationen entfernt wird. Sie untersttzt nicht die Operationen add oder addAll.

bung 7.10 Zuerst wird ein String mit dem Namen "ergebnis" und dem Anfangsinhalt "Ausgnge:" erzeugt. Wir fgen dann die Namen der Ausgnge zu diesem String hinzu und geben ihn schlielich zurck. Die Namen der verfgbaren Ausgnge werden hinzugefgt, indem die Menge der Schlssel aus der HashMap, in der sich die Ausgnge befinden, abgefragt wird. Dann iterieren wir ber diese Schlssel-Menge und hngen in jeder Iteration den Namen des jeweiligen Ausgangs an den returnString an. bung 7.11 Siehe das Projekt Zuul-besser auf der CD. bung 7.12
Die Objekte sind: spiel1:Spiel -->parser:Parser --> befehle:Befehlswoerter -->draussen:Raum -->hoersaal:Raum -->labor:Raum -->buero:Raum -->cafeteria:Raum

bung 7.13 Die Referenz in spiel1:Spiel auf draussen:Raum wird auf den neuen Raum gendert, in den wir uns bewegt haben. Wenn wir den Befehl "go east" verwenden, wird die Referenz zu hoersaal:Raum gendert. bung 7.14 Siehe Seite 267 fr Einzelheiten zur Implementierung. bung 7.15 hnlich wie 7.14. bung 7.16 Siehe Seite 268-269. bung 7.17 Nein, Sie mssen die Klasse Spiel nicht ndern. Die Liste der ausgegebenen Befehle wird von dem Array gueltigeBefehle erzeugt und enthlt daher automatisch alle neuen Befehle, die zu diesem Array hinzugefgt wurden.

bung 7.18 Modifizieren Sie die Methode hilfstextAusgeben in Spiel so, dass die letzte Zeile lautet:
System.out.println(parser.gibBefehlsliste());

Fgen Sie folgende Methode zum Parser hinzu:


public String gibBefehlsliste() { return befehle.gibBefehlsliste(); }

und entfernen Sie das nunmehr berflssige zeigeBefehle() aus dem Parser (falls Sie es in bung 7.16 implementiert haben). In Befehlswoerter fgen Sie diese Methode hinzu:
public String gibBefehlsliste() { String befehlsliste = ""; for(int i = 0; i < gueltigeBefehle.length; i++) { befehlsliste += gueltigeBefehle[i] + " "; } return befehlsliste; }

und entfernen Sie das nunmehr berflssige zeigeBefehle() aus Befehlswoerter (falls Sie es in bung 7.16 implementiert haben). bung 7.19 Informationen ber das Entwurfsmuster Model-View-Controller (MVC) finden Sie hier: http://www.enode.com/x/markup/tutorial/mvc.html Ein einfaches Beispiel fr ein Java-Programm, das MVC benutzt: http://csis.pace.edu/~bergin/mvc/mvcgui.html Weitere Beispiele fr das MVC-Entwurfsmuster finden Sie im Rahmen der Java Swing-Implementierung, die das MVC-Entwurfsmuster stark nutzt. Das MVC-Entwurfsmuster steht in Beziehung zu der in diesem Kapitel gefhrten Diskussion, weil es sich hierbei um ein Muster handelt, das Objekte in drei Objekttypen entkoppelt: Modellobjekte, die die Daten reprsentieren, Anzeigeobjekte, welche die Darstellung bernehmen, und Kontrollobjekte, die Ereignisse abwickeln, die ihrerseits die Anzeigeobjekte oder Modellobjekte verndern. In diesem Kapitel haben wir nur die Trennung von Darstellung und Modell diskutiert. Das Hinzufgen einer weiteren Entkopplungsebene macht das Design noch flexibler.

Um das MVC-Entwurfsmuster auf das Spiel Zuul anzuwenden, mssen wir die Anwendung in Modell-, Anzeige- und Kontrollobjekte aufteilen. Wir knnen beispielsweise so vorgehen: Model: Die Klassen Spiel und Raum reprsentieren das Modell. Wir knnen die Klasse Spiel in zwei Klassen unterteilen: eine, die das Modell reprsentiert und eine weitere, die alles andere bernimmt. Die Vernderung, die wir an dem Modell vornehmen, whrend wir das Spiel spielen, ist das ndern der Referenz auf den aktuellen Raum. Wann immer wir diese Referenz verndern, sollte das Modell ein Aktualisieren-Signal an alle registrierten Zuhrer (die Anzeigeobjekte) verschicken. View: Wir sollten eine neue Klasse erstellen, die die Darstellung des Modells bernimmt, d.h. den Text auf dem Bildschirm ausgibt, sobald ein Aktualisieren vom Modell empfangen wurde. Controller: In seinem jetzigen Zustand wird das Spiel von der Klasse Spiel in den Methoden spielen() und verarbeiteBefehl(Befehl befehl) kontrolliert. Ein englisches Beispiel von Zuul, in dem das MVC-Entwurfsmuster umgesetzt ist, kann hier heruntergeladen werden: zuul-mvc.zip bung 7.20 Siehe bung 7.22. (In der die Rume allerdings mehrere Gegenstnde enthalten knnen). bung 7.21 a) Wie sollten die textuellen Informationen ber einen Gegenstand in einem Raum erzeugt werden? Die Gegenstnde befinden sich in den Rumen. Daher sollte der jeweilige Raum die Informationen ber die dort vorhandenen Gegenstnde erzeugen. b) Welche Klasse sollte die Zeichenkette erzeugen, die den Gegenstand beschreibt? Die Klasse Gegenstand sollte die Zeichenkette erzeugen. c) Welche Klasse sollte diese ausgeben? Die Klasse Spiel ist fr die Ausgabe zustndig und sollte deshalb auch die Beschreibung eines Gegenstandes ausgeben. Es ist jedoch nicht notwendig, eine ausdrckliche Beschreibung des Gegenstandes in der Klasse Spiel auszugeben, wenn die Beschreibung des Raums bereits die Beschreibung des Gegenstandes in diesem Raum enthlt. bung 7.22 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-withitems.zip herunter.

bung 7.23 Ergnzen Sie Befehlswoerter um den Befehl "back". Die restlichen nderungen erfolgen in der Klasse Spiel: Fgen Sie folgendes Datenfeld hinzu:
private Raum vorherigerRaum;

In der Methode verarbeiteBefehl fgen Sie Folgendes hinzu:


else if (befehlswort.equals("back")) { geheZurueck(befehl); }

Fhren Sie eine neue Methode betreteRaum ein, die vorherigerRaum speichert. Aktualisieren Sie die Methode wechsleRaum() so, dass sie diese Methode benutzt.
/** * Betrete den gegebenen Raum und gib seine Beschreibung aus. */ private void betreteRaum(Raum naechsterRaum) { vorherigerRaum = aktuellerRaum; aktuellerRaum = naechsterRaum; System.out.println(aktuellerRaum.gibLangeBeschreibung()); }

Fgen Sie diese Methode hinzu:


/** * Gehe zurck in den vorherigen Raum. */ private void geheZurueck(Befehl befehl) { if(befehl.hatZweitesWort()) { System.out.println("Zurck wohin?"); return; } if (vorherigerRaum == null) System.out.println("Sie knnen nicht zurck nach nirgendwo gehen!"); else { betreteRaum(vorherigerRaum); } }

bung 7.24 Wenn ein zweites Wort nach "back" getippt wird, wird eine Fehlermeldung ausgegeben: "Zurck wohin?" Eine weitere Mglichkeit des negativen Testens: Wenn das Spiel gerade gestartet wurde, gibt es keinen vorherigen Raum. In der oben genannten Implementierung wird dies so gehandhabt, dass eine Nachricht an den Spieler ausgegeben wird: "Sie knnen nicht zurck nach nirgendwo gehen!" bung 7.25 Wenn "back" zweimal eingetippt wird, landen Sie in demselben Raum, in dem Sie waren, als Sie "back" das erste Mal eingegeben haben. Dies macht zwar Sinn, aber es wre womglich viel ntzlicher, wenn man mehrere Schritte zurckgehen knnte siehe die nchste bung. bung 7.26 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-back.zip herunter. bung 7.27 Es sind viele Tests fr das Zuul-Projekt mglich. Es ist wichtig, sowohl positive als auch negative Tests einzubeziehen. Einige der Tests knnten sein: - testen, ob die Rume richtig miteinander verbunden sind. - testen, ob alle Befehle erkannt werden und so funktionieren, wie sie es sollen. - den Befehl "back" zu testen (wie erlutert in bung 7.24). bung 7.28 Um Tests fr Programme zu automatisieren, die interaktive Eingaben verwenden, gibt es zwei Mglichkeiten: - Verwenden Sie eine Art von Eingabeerfassungsprogramm, das die Eingabe reproduzieren kann. - gestalten Sie Ihr Programm so, dass es mglich ist, die Eingabe aus einer anderen Quelle zu beziehen. Wenn die letztgenannte Option gewhlt wird, sollte es mglich sein, eine Testklasse zu erstellen, die die Eingabe aus einer Textdatei liest und die Ergebnisse verifiziert. Um solch eine nderung in dem Zuul-Projekt vorzunehmen, mssten wir die Klasse Spiel modifizieren, damit sie einen anderen Parser verwendet und den neuen Parser derart schreiben, dass er die Eingabe aus einer Textdatei anstelle von der Tastatur abruft. Des Weiteren mssten wir das Ergebnis jedes einzelnen Befehls prfen. Zu diesem Zweck wre es erforderlich, den jeweiligen Zustand des Spiels zu testen (aktueller Raum, Gegenstnde in den Rumen, Geschichte der Rume etc.).

bung 7.29 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuulrefactored.zip herunter. bung 7.30 - 7.34 All die Modifikationen, die in den bungen 7.30 bis 7.34 vorgeschlagen werden, wurden in diesem (leider momentan nur englisch verfgbaren) Projekt implementiert: zuul-with-player.zip. bung 7.36 Fgen Sie dies zu Spiel.verarbeiteBefehl hinzu:
else if (befehlswort == befehlswort.LOOK) { look(); }

und fgen Sie diese Methode zu Spiel hinzu:


private void look() { System.out.println(aktuellerRaum.langeBeschreibung()); }

Zum Schluss modifizieren Sie Befehlswort so, dass es den neuen Wert LOOK enthlt:
public enum Befehlswort { // Ein Wert fr jedes Befehlswort plus eines fr unbekannte // Befehle. GO, QUIT, HELP, LOOK, UNKNOWN; }

Vergessen Sie nicht, den Text festzulegen, der mit dem Befehl im Konstruktor Befehlswoerter assoziiert ist:
gueltigeBefehle.put("look", Befehlswort.LOOK);

bung 7.37 Die Verwendung anderer Befehlswrter erfordert lediglich nderungen in der Klasse Befehlswoerter. bung 7.38 Wenn der Hilfe-Befehl von "help" bersetzt wird, wird er NICHT auch im Willkommenstext gendert.

bung 7.39
public enum Position { OBEN, MITTE, UNTEN }

bung 7.40 Fast. Sie mssen auch seine Funktionalitt zu der Klasse Spiel hinzufgen. Im Vergleich zu bung 7.36 mssen Sie in dieser bung eine Klasse weniger modifizieren. bung 7.41 Ja. Es verwendet nur die Enumeration selbst: Befehlswort.HELP. Dieses liefert den Befehls-String zurck, da toString() in Befehlswort berschrieben wurde. bung 7.42 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-withtimelimit.zip herunter. bung 7.43 Um eine Falltr zu implementieren (oder eine andere Art von Tr, die nur in eine Richtung durchschritten werden kann), entfernen Sie einfach einen der Ausgnge. Beispielsweise knnen Sie den Ausgang der Cafeteria nach drauen entfernen, indem Sie diese Zeile lschen:
cafeteria.setzeAusgang("east", draussen);

bung 7.44 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-withbeamer.zip herunter. bung 7.45 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-withdoors.zip herunter. bung 7.46 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-withtransporter.zip herunter. bung 7.47 Laden Sie sich die (leider momentan nur englisch verfgbare Fassung) zuul-evenbetter.zip herunter.

bung 7.50 Die Signatur der Methode lautet: static int max(int a, int b); bung 7.51 Die Methoden in der Klasse Math sind statisch, weil sie an den einfachen Typen operieren und kein Objekt bentigen. Es ist auerdem komfortabler, dass Sie vor dem Aufruf der Methode kein Objekt erzeugen mssen. Ja, sie knnten auch als Instanzenmethoden geschrieben werden, aber bevor Sie die Methoden nutzen knnten, mssten Sie erst eine Instanz der Klasse Math erzeugen. bung 7.52
public static long testLoopTime() { long start = System.currentTimeMillis(); for(int i = 0; i<100; i++); long end = System.currentTimeMillis(); return (end-start); }

bung 7.53 Die main-Methode knnte folgendermaen aussehen:


public static void main(String args[]) { Spiel spiel = new Spiel(); spiel.spielen(); }

bung 7.56 a) Ja, Sie knnen eine statische Methode in einer Instanzmethode aufrufen. b) Nein, Sie knnen eine Instanzmethode nicht in einer statischen Methode aufrufen (zumindest nicht, ohne vorher ein Objekt zum Aufrufen erzeugt zu haben). c) Ja, Sie knnen eine statische Methode in einer statischen Methode aufrufen.

bung 7.57 Ja, Sie knnen den Konstruktor/die Konstruktoren der Klasse benutzen, um die Anzahl der Instanzen zu zhlen. Wenn Sie mehr als einen Konstruktor haben, mssen Sie den Zhler in jedem der Konstruktoren erhhen. Dies ist ein Weg, dies zu tun:
public class Test { private static int instanzzaehler; public Test() { instanzzaehler++; } public Test(String irgendetwas) { instanzzaehler++; } public static int anzahlInstanzen() { return instanzzaehler; } }

Es ist tatschlich mglich, das Erhhen des Zhlers in jedem einzelnen Konstruktor zu umgehen. Sie knnen einen initialiser block verwenden, der vor dem Aufruf des Konstruktors aufgerufen wird. Dies ist kein Konstrukt, das sehr hufig benutzt wird, und Sie sollten Ihren Studenten vielleicht besser nichts davon erzhlen. Falls Sie aber jemand danach fragen sollte so sieht es aus:
public class Test { private static int instanzzaehler; { instanzzaehler ++; } public Test() { } public Test(String something) { } public static int anzahlInstanzen() { return instanzzaehler; } }

Teil 2: Anwendungsstrukturen
Kapitel 8
bung 8.2 Nachdem ein Kommentar zu dem CD-Objekt erzeugt wurde, wird dieser auch angezeigt, wenn der Inhalt der Datenbank aufgelistet wird, obwohl die CD in die Datenbank eingegeben wurde, bevor der Kommentar hinzukam. Das liegt daran, dass die Datenbank eine Referenz zu dem CD-Objekt besitzt und diese benutzt, um jedes Mal, wenn die Liste ausgegeben wird, Informationen ber das Objekt abzurufen. Wenn stattdessen das CD-Objekt in die Datenbank hineinkopiert wrde, wrde der vernderte Kommentar nicht in der Auflistung der Datenbank wiedergegeben werden. bung 8.4 Wenn die Wrter "extends Medium" aus dem Quelltext der Klasse Video entfernt werden, verschwindet der Pfeil, der die Vererbungsbeziehung kennzeichnet, aus dem Diagramm. bung 8.5 Ja, es ist mglich, geerbte Methoden ber das Untermen "geerbt von Medium" aufzurufen. bung 8.6 Zunchst bringt uns die Schaltflche Schritt hinein zum Konstruktor der Superklasse, der beim wiederholten Drcken von Schritt hinein die Datenfelder initialisiert: titel, spielzeit, habIch und kommentar. Dann springt er zurck zum CDKonstruktor und initialisiert die lezten zwei Felder: kuenstler und titelanzahl. bung 8.7 Das Videospiel:
/** * Die Klasse Videospiel reprsentiert ein Videospiel-Objekt. * Informationen ber das Videospiel werden gespeichert und * knnen wieder abgerufen werden. * * @author Poul Henriksen * @version 2005-10-03 */ public class Videospiel extends Medium { private String plattform; private int maxSpieleranzahl;

/** * Konstruktor fr Objekte der Klasse Video */ public Videospiel(String derTitel, String plattform, int maxSpieleranzahl, int spielzeit) { super(derTitel, spielzeit); this.plattform = plattform; this.maxSpieleranzahl = maxSpieleranzahl; } /** * Liefert die Plattform, auf der dieses Spiel luft. */ public String gibPlattform() { return plattform; } /** * Liefert die maximale Spielerzahl fr dieses Spiel. */ public int gibMaxSpieleranzahl() { return maxSpieleranzahl; } }

bung 8.8. Eine mgliche Hierarchie:

bung 8.9 Ein Touchpad und eine Maus sind beides Eingabegerte fr einen Computer. Sie sind sich sehr hnlich und knnten entweder eine gemeinsame Superklasse (EingabeGeraet) haben oder eines knnte die Superklasse des anderen sein.

bung 8.10 Argument dafr, dass Quadrat eine Subklasse von Rechteck ist: - Ein Quadrat ist auch nur ein Rechteck, bei dem die Seiten der Restriktion unterliegen, gleich lang sein zu mssen. Argumente dafr, dass Rechteck eine Subklasse von Quadrat ist: - Ein Rechteck ist ein Quadrat, das noch ein zustzliches Attribut hat: das Grenverhltnis von Breite und Hhe. bung 8.11 Welche der folgenden Zuweisungen sind zugelassen und warum? a) Person p1 = new Student(); - Dies ist zulssig, weil Student eine Subklasse von Person ist. b) Person p2 = new Promotionsstudent(); - Dies ist zulssig, weil Promotionsstudent eine Subklasse von Person ist (weil Promotionsstudent eine Subklasse von Student ist, die wiederum eine Subklasse von Person ist). c) Promotionsstudent pro1 = new Student(); - Dies ist nicht zulssig, weil Student keine Subklasse von Promotionsstudent ist. d) Dozent d1 = new Person(); - Dies ist nicht zulssig, weil Person keine Subklasse von Dozent ist. e) Student s1 = new Promotionsstudent; - Dies ist zulssig, weil Promotionsstudent eine Subklasse von Student ist. Gehen Sie davon aus, dass die zwei oben genannten, nicht zulssigen Zeilen gendert werden in:
Promotionsstudent pro1;// = new Student(); Dozent d1;// = new Person();

f) s1 = p1 - Dies ist nicht zulssig, weil Person keine Subklasse von Student ist. Der Compiler kennt nur den statischen Typ von p1, welcher Person ist. Er kennt nicht den dynamischen Typ, der Student ist.

g) s1 = p2 - Dies ist nicht zulssig, weil Person keine Subklasse von Student ist (dieselbe Begrndung wie bei f). h) p1 = s1 - Dies ist zulssig, weil Student eine Subklasse von Person ist. i) d1 = s1 - Dies ist nicht zulssig, weil Student keine Subklasse von Dozent ist. j) s1 = pro1 - Dies ist zulssig, weil Promotionsstudent eine Subklasse von Student ist. k) pro1 = s1 - Dies ist nicht zulssig, weil Student keine Subklasse von Promotionsstudent ist.

bung 8.13 Nichts muss in der Klasse Datenbank gendert werden, wenn wir eine neue Subklasse von Medium hinzufgen. Das liegt daran, dass die Datenbank sich nicht mit der eigentlichen Subklasse befasst, sondern alle Objekte als Medium behandelt. bung 8.14 Aus der Dokumentation zu JDK 1.5.0 knnen die folgenden Vererbungshierarchien geschlossen werden:

bung 8.15 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung labclasses8.15.zip herunter. bung 8.16 Ein Beispiel fr eine Vererbungshierarchie von einigen der Komponenten in einem Computer:

Oder vielleicht so:

bung 8.17 Die legalen Zuweisungen sagen Folgendes aus: a) m=t Dies sagt uns, dass T eine Subklasse von M ist. b) m=x Dies sagt uns, dass X eine Subklasse von M ist. c) o=t Dies sagt uns, dass T eine Subklasse von O ist. Aber T war auch eine Subklasse von M, und Java gestattet keine Mehrfachvererbung. Daher muss M eine Subklasse von O sein oder umgekehrt. Die illegalen Zuweisungen sagen Folgendes aus: d) o=m M ist keine Subklasse von O. Daher lsst sich aus c) schlieen, dass O eine Subklasse von M ist. e) o=x X ist keine Subklasse von O. f) x=o O ist keine Subklasse von X.

Aus dieser Information knnen wir sicher folgern, dass die folgenden Beziehungen existieren:

bung 8.18 Siehe das Diagramm in der Lsung zu bung 8.14.

Kapitel 9
bung 9.1 Das Projekt lsst sich nicht mehr bersetzen. Die Methode ausgeben versucht auf die privaten Datenfelder der Klasse Medium zuzugreifen, die von den Subklassen aus nicht zugnglich ist. Dies kann korrigiert werden, indem stattdessen sondierende Methoden erzeugt und eingesetzt werden. Wenn wir nach diesen Modifikationen versuchen zu bersetzen, funktioniert es immer noch nicht. Diesmal schlgt die Kompilierung bei der Klasse Datenbank fehl, da diese versucht, die Methode ausgeben an einer Variablen vom Typ Medium aufzurufen. Allerdings hat Medium nicht lnger eine Methode namens ausgeben, weshalb das bersetzen fehlschlgt. bung 9.2 Die Methode ausgeben in der Klasse Medium wird nicht aufgerufen. Wenn das Objekt eine CD ist, wird die Methode ausgeben der Klasse CD aufgerufen. Falls es sich bei dem Objekt um ein Video handelt, wird die Methode ausgeben der Klasse Video aufgerufen. Das liegt daran, dass die dynamischen Typen der Medien verwendet werden. bung 9.3 Ja, die Anwendung verhlt sich erwartungsgem, indem sie zuerst die Methode ausgeben in der Klasse Medium aufruft und anschlieend die Methode ausgeben in der eigentlichen Klasse (dynamischer Typ). Ein Problem ist, dass man den Aufruf der Methode ausgeben aus der Superklasse nicht erzwingen kann. Das bedeutet, dass Sie daran denken mssen, super.ausgeben() aufzurufen, wenn Sie neue Subklassen erzeugen wollen. Ein weiteres Problem ist, dass Sie die Reihenfolge, in der verschiedene Dinge ausgegeben werden, nicht verndern knnen. Dies wird eingehender in bung 9.8 diskutiert. bung 9.4 Fgen Sie diese Zeile am Anfang von Methode ausgeben in der Klasse Video hinzu:
System.out.print("Video: ");

Fgen Sie diese Zeile am Anfang der Klasse CD hinzu:


System.out.print("CD: ");

bung 9.5 Die Methode toString finden Sie in der Klasse Object. Sie hat keine Parameter und der Rckgabetyp ist String. bung 9.7 Die Methode ausgeben in der Klasse CD:
public void ausgeben() { System.out.print("CD: " + kuenstler + ": "); super.ausgeben(); System.out.println(" Titel: " + titelanzahl); }

Die Methode ausgeben in der Klasse Medium:


public void ausgeben() { System.out.print(titel); if(habIch) { System.out.println("*"); } else { System.out.println(); } System.out.println(" " + spielzeit + " Minuten"); System.out.println(" " + kommentar); }

bung 9.8 ndern Sie alle Datenfelder in der Klasse Medium von privaten Datenfeldern in solche mit der Zugriffsstufe protected. Dann modifizieren Sie die Methode in der Klasse CD wie folgt:
public void ausgeben() { System.out.print("CD: " + kuenstler + ": "); System.out.print(titel); if(habIch) { System.out.println("*"); } else { System.out.println(); } System.out.print(" " + titelanzahl + " Titel, "); System.out.println(" " + spielzeit + " Minuten"); System.out.println(" " + kommentar); }

bung 9.9 Laden Sie sich die (leider momentan nur in Englisch verfgbare) Fassung zuul-withtransporter.zip herunter.

bung 9.10 Um eine Monster- und eine Spielerklasse in dem Zuul-Projekt zu implementieren, wre es wahrscheinlich sinnvoll, eine gemeinsame Superklasse (z.B. mit dem Namen Figur) zu haben, die die blichen Verhaltensweisen beider Klassen enthlt. bung 9.11 Kommt drauf an man knnte fr alle Vererbungsbeziehungen argumentieren. Welche Sie whlen, hngt von der derzeitigen Implementierung ab und davon (falls Sie das schon wissen), welche Features Sie in naher Zukunft implementieren mchten. Wenn Gegenstand eine Superklasse von Figur ist, wrde Ihnen dieser Umstand gestatten, alle Figuren als Gegenstnde zu behandeln. Das bedeutet, dass eine Figur eine andere Figur aufheben kann, was fr einige Szenarien sinnvoll wre. Wenn Figur eine Superklasse von Gegenstand ist, knnen Sie alle Gegenstnde als Figuren behandeln. Wenn wir Figuren als etwas definieren, das sich bewegen kann, wre es auch mglich, dass Gegenstnde sich bewegen, falls das erwnscht ist. Wenn es sich bei den zwei Klassen um Geschwisterklassen handeln wrde und sie eine gemeinsame Superklasse (Ding?) htten, knnten Sie eine Kombination der o.g. Lsungen erstellen. Diese wrde einer Figur erlauben Dinge aufzuheben (was bedeutet, dass Sie sowohl Gegenstnde als auch Figuren aufheben knnten), und es wrde dazu fhren, dass alle Dinge beweglich sind (auch das trifft auf Gegenstand und Figur zu). Wenn Sie nicht davon ausgehen, dass Gegenstand und Figur irgendetwas gemeinsam haben, dann knnen auch keine Vererbungsbeziehungen zwischen Gegenstand und Charakter existieren. bung 9.12 Da die Typprfung am statischen Typ von geraet (also Geraet) erfolgt, muss die Methode gibName in Geraet definiert werden. bung 9.13 Um eine Methode tatschlich auszufhren wird die dynamische Methodensuche eingesetzt. Das bedeutet, dass die Methode der Klasse Drucker aufgerufen wird, weil der dynamische Typ von geraet Drucker ist. bung 9.14 Ja, sie lassen sich bersetzen.
toString wird in der Klasse Object aus der Java-Bibliothek implementiert. Die Klasse Object ist immer eine Superklasse aller anderen Klassen. Wenn sie die Zeilen

ausfhren, wird daher die toString-Methode der Klasse Object aufgerufen und das Ergebnis wird der Variablen s vom Typ String zugewiesen. bung 9.15 Ja, sie lassen sich bersetzen. Die Methode System.out.println kann ein Object als Argument annehmen und, wie in bung 9.14 erlutert, ist Student eine Subklasse von Object. bung 9.16 Ja, sie lassen sich bersetzen. Es werden alle Namen der Studenten in der Liste ausgegeben. Es werden alle Eintrge in der Liste durchlaufen und die Methode System.out.println(it.next())aufgerufen. Diese Methode ruft toString an dem Eintrag auf, was wiederum bewirkt, dass aufgrund der dynamischen Methodensuche die Methode toString der Klasse Student aufgerufen wird. bung 9.17
D muss eine Subklasse von T sein. T x = new D();

Kapitel 10
bung 10.1 Ja, die Zahl der Fchse ndert sich. bung 10.2 Ja, die Anzahl ndert sich jedes Mal, wenn simuliereEinenSchritt aufgerufen wird. Manchmal nimmt die Anzahl zu und manchmal ab. Wahrscheinlich werden die Geburten und Tode von Fchsen simuliert. bung 10.3 Nein. bung 10.4 Die Anzahl der Fchse und Hasen schwankt. bung 10.5 Nein, der zweite Simulationslauf ist nicht identisch mit dem ersten. Ja, es zeigen sich hnliche Muster. bung 10.6 Nein, es macht nicht den Eindruck, als ob die Fchse oder Hasen jemals komplett aussterben. Warum das nicht geschieht? Nun, es sieht ganz so aus, als ob die Parameter der Simulation derart abgestimmt sind, dass ein Gleichgewicht zwischen der Anzahl der Fchse und Hasen erzeugt wird. bung 10.9 Wenn die Gebrwahrscheinlichkeit der Hasen stark herabgesetzt wird, fhrt dies dazu, dass die Fchse rasch aussterben, weil sie nicht mehr genug Nahrung haben. Wird die Gebrwahrscheinlichkeit der Hasen erhht, breiten sie sich schneller aus. bung 10.11 Ein heraufgesetztes Maximalalter fr die Fchse scheint keine starken Auswirkungen auf die Anzahl der Fchse zu haben. bung 10.12 Ja, bei einigen Einstellungen werden die Fchse oder Hasen komplett ausgelscht.

bung 10.13 Ja, die Feldgre wirkt sich auf die berlebenswahrscheinlichkeit der Spezies aus. Anhand eines kleinen Felds (10x10) lsst sich dies leicht beobachten. In einigen Fllen sterben die Fchse aus und in anderen die Hasen. bung 10.14 Die modifizierte Methode findeNahrung:
/** * Suche nach Nahrung (Hasen) in den Nachbarpositionen. * @param feld das Feld, in dem gesucht werden soll. * @param position wo im Feld sich die Nahrung befindet. * @return die Position mit Nahrung, oder null, wenn keine vorhanden. */ private Position findeNahrung(Feld feld, Position position) { Iterator<Position> nachbarPositionen = feld.nachbarPositionen(position); Position pos = null; while(nachbarPositionen.hasNext()) { pos = nachbarPositionen.next(); Object tier = feld.gibObjektAn(pos); if(tier instanceof Hase) { Hase hase = (Hase) tier; if(hase.istLebendig()) { hase.setzeGefressen(); futterLevel = HASEN_NAEHRWERT; } } } return pos; }

Diese nderung scheint keine starke Auswirkung zu haben. bung 10.15 Um die vorgeschlagenen nderungen zu implementieren, bentigen wir ein Feld mit dem maximalen Nhrwert:
private static final int MAX_NAEHRWERT = 20;

Auerdem bentigen wir die modifizierte Methode:


private Position findeNahrung(Feld feld, Position position) { Iterator<Position> nachbarPositionen = feld.nachbarPositionen(position); Position pos = null; while(nachbarPositionen.hasNext()) { pos = nachbarPositionen.next(); Object tier = feld.gibObjektAn(pos); if(tier instanceof Hase) { Hase hase = (Hase) tier; if(hase.istLebendig()) { hase.setzeGefressen(); futterLevel = futterLevel + HASE_NAEHRWERT; if(futterLevel > MAX_NAEHRWERT) { futterLevel = MAX_NAEHRWERT; } } } } return pos; }

Je nach dem maximalen Nhrwert scheinen die Fchse lnger zu berleben. bung 10.16 Nein, es scheint nicht zu einer Katastrophe zu kommen. bung 10.17 Ja, nach einer Weile scheint sich die Simulation genau wie ihre Originalversion zu verhalten. Die relative Gre der Anfangspopulationen hat keine signifikanten Auswirkungen auf das Ergebnis der Simulation. bung 10.18 Die Auswirkung auf die Fuchspopulation ist, dass sie nach einer Weile komplett ausstirbt, wenn es zu viele Hasen gibt. Nein, die Einschrnkung gilt nicht fr neu geborene Hasen. bung 10.19 Nein.

bung 10.20 Die gemeinsamen Datenfelder der beiden Klassen sind:


private private private private private static static static static static final final final final final int GEBAER_ALTER = 5; int MAX_ALTER = 50; double GEBAER_WAHRSCHEINLICHKEIT = 0.15; int MAX_WURFGROESSE = 5; Random rand = new Random();

Die Klasse Fuchs hat ein zustzliches Datenfeld:


private static final int HASE_NAEHRWERT = 4;

Die gemeinsamen Datenfelder sind:


private int alter; private boolean lebendig; private Position position;

Die Klasse Fuchs hat ein zustzliches Datenfeld in der Instanz:


private int futterLevel;

Die Konstruktoren hneln sich, allerdings initialisiert der Konstruktor Fuchs auch seinen futterLevel. Die gemeinsamen Methoden sind:
private void alterErhoehen() //auer fr die Werte in den statischen Feldern private int geburten() //auer fr die Werte in den statischen Feldern private boolean kannGebaeren() //auer fr die Werte in den statischen Feldern public boolean istLebendig() public void setzePosition(int zeile, int spalte) public void setzePosition(Position position)

Die Klasse Hase hat folgende Methoden, die die Klasse Fuchs nicht hat:
public void laufe(Feld naechstesFeld, List<Hase> neueHasen) public void setzeGefressen()

Die Klasse Fuchs hat folgende Methoden, die die Klasse Hase nicht hat:
public void jage(Feld aktuellesFeld, Feld naechstesFeld, List<Fuchs> neueFuechse) private void hungerErhoehen() private Position findeNahrung(Feld feld, Position position)

bung 10.21 Die wirklich identischen Methoden sind:


public boolean istLebendig() public void setzePosition(int reihe, int spalte) public void setzePosition(Position position)

bung 10.22 In diesem Fall nicht, weil es sehr wahrscheinlich ist, dass wir die Werte fr Fuchs und Hase in Zukunft verndern wollen. Grundstzlich hngt das von dem jeweiligen Datenfeld ab. Wenn es sich tatschlich um ein Datenfeld handelt, das stets denselben Wert sowohl fr den Hasen als auch fr den Fuchs haben wird, ist es sinnvoll Methoden in Betracht zu ziehen, die dieses Datenfeld als gleichbleibend verwenden. In diesem Fall wren das die Methoden: kannGebaeren und geburten. Aber es wrde hier mehr Sinn machen sie als separate Methoden beizubehalten, weil es wahrscheinlich eher ein Zufall ist, dass die Werte gleich sind. bung 10.23 Eine gute Idee wre es, eine Reihe von Modultests zu erstellen, die den Teil des Programms testen, der wahrscheinlich von den nderungen betroffen ist. Dies knnte geschehen, indem eine JUnit-Testklasse fr Fuchs und Hase erstellt wird. Nach jeder geringfgigen nderung des Programms sollten wir die Modultests durchfhren um zu sehen, ob das Programm sich immer noch erwartungsgem verhlt. Das Programm auszufhren ist ebenfalls eine gute Art, dieses Programm zu testen, weil es aufgrund der visuellen Ausgabe einfach ist, schwere Fehler zu entdecken. bung 10.24 Siehe das Projekt Fuechse-und-Hasen-V2 auf der CD. bung 10.25 Wir haben die Duplizierung von Quelltext vermieden. Die Klassen Fuchs und Hase sind kleiner. Falls wir in Zukunft neue Tiere hinzufgen wollen, haben wir bereits einiges an Funktionalitt in der Klasse Tier parat.

bung 10.26 Wir knnen die Tiere nicht als Objekte behandeln, weil Object nicht die Methode agiere definiert, die wir benutzen mssen. bung 10.27 Ja, eine Klasse muss als abstrakt erklrt werden, wenn sie abstrakte Methoden hat. bung 10.28 Ja, eine Klasse kann als abstrakt erklrt werden, selbst wenn sie keine abstrakten Methoden enthlt. bung 10.29 Wenn Sie die Instantiierung einer Klasse unterbinden wollen, mssen Sie diese als abstrakt deklarieren. Selbst wenn Sie wissen, dass die Klasse niemals instantiiert wird, hilft es anderen Programmierern den Quelltext zu verstehen, wenn Sie diese Klasse als abstrakt deklarieren. bung 10.30
AbstractCollection, AbstractSet, AbstractMap, AbstractList, AbstractSequentialList.

Sie knnen an einer weiteren Stelle der Dokumentation sehen, dass eine Klasse abstrakt ist. Die erste Zeile unterhalb der berschrift sagt ungefhr so etwas aus:
public abstract class AbstractCollection

Um herauszufinden, welche konkreten Klassen sie erweitern, sehen Sie sich bitte das Klassendiagramm in der Lsung zu bung 8.14 an. bung 10.31 Ja, Sie knnen aus der API-Dokumentation ersehen, welche ihrer Methoden abstrakt sind, z.B. in der linken Spalte der Methodenzusammenfassung. Wir mssen das wissen, wenn wir eine abstrakte Klasse mit einer konkreten Klasse erweitern wollen. So erfahren wir, welche Methoden wir als Minimum implementieren mssen. bung 10.32 Keine der anderen Klassen geht speziell mit den Klassen Fuchs und Tier um.

bung 10.33 Weil wir abstrakte Methoden in der Klasse Tier verwenden, die in den beiden Subklassen Hase und Fuchs berschrieben werden. Um dieses Verhalten verstehen zu knnen, mssen wir begreifen, wie das berschreiben von Methoden funktioniert. bung 10.34 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung foxes-andrabbits-10.34.zip herunter. bung 10.35 Die Methoden kannGebaeren wurden nicht verschoben, weil sie unterschiedliche Werte fr das statische Feld GEBAER_ALTER verwendeten. Wenn die Methoden in die Klasse Tier verschoben werden, lassen sie sich nicht mehr bersetzen, weil sie keinen Zugriff mehr auf das statische Feld GEBAER_ALTER haben. Wenn wir sie lediglich bersetzen wollen, knnen wir GEBAER_ALTER von der Klasse Fuchs oder Hase in die Klasse tier verschieben. Allerdings knnen wir dann keine unterschiedlichen Gebralter fr Fchse und Hasen vorgeben. Das liegt daran, dass Datenfelder nicht berschrieben werden knnen. Um die Mglichkeit zu schaffen, unterschiedliche Gebralter fr Hasen und Fchse vorzugeben, knnten wir eine abstrakte Methode in der Klasse Tier namens gibGebaerAlter anlegen. In der Methode kannGebaeren rufen wir dann diese Methode auf, um das Gebralter zu erhalten. Die Methode gibGebaerAltersollte dann in Fuchs und Hase berschrieben werden, um den korrekten Wert zu liefern. Dies wird in Abschnitt 10.4 behandelt. bung 10.36 Wir mssen auch die Definition von gibGebaerAlter in der Klasse Tier hinterlegen:
protected abstract int gibGebaerAlter();

Eine Implementierung hiervon kann in der nchsten bung heruntergeladen werden. bung 10.37 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung foxes-andrabbits-10.37.zip herunter.

bung 10.38 Ja, die Methode gebaereNachwuchs kann in die Klasse Tier verschoben werden. Wir mssen dann auch Methoden erzeugen, mit denen wir auf die beiden statischen Felder GEBAER_WAHRSCHEINLICHKEIT und MAX_WURFGROESSE zugreifen knnen, so wie wir es in den zwei vorangegangenen bungen taten. bung 10.40 Die nderungen, die wir an den Klassen Tier, Hase und Fuchs vornahmen, erforderten nicht, dass wir andere Klassen auer der Klasse Simulator modifizieren (abgesehen von bung 10.34, wo wir die Klasse PopulationGenerator erstellten). Daran erkennen wir, dass das Originalprogramm nur eine geringe Anzahl von Abhngigkeiten (Kopplung) besa und eine gute Kapselung. bung 10.41 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung foxes-andrabbits-10.41.zip herunter. bung 10.42 Sie mssen eine import-Anweisung fr java.util.List in die Klassendefinition von Akteur einfgen, aber das ist es dann auch schon. Selbstverstndlich mssen wir auch deklarieren, dass die Klasse Tier die Klasse Akteur erweitert. Des Weiteren sollten wir das Datenfeld dahingehend aktualisieren, dass es Akteure statt Tiere verwendet. bung 10.43 Ja, die Simulation lsst sich bersetzen und ausfhren. bung 10.44 Es handelt sich um statische und ffentliche Datenfelder. Interfaces erlauben nur Datenfelder mit den Eigenschaften public, static und final. bung 10.45 In diesem Programm sind drei Fehler: - Das Datenfeld OBERGRENZE ist als private deklariert, was nicht zulssig ist. - Es ist nicht zulssig, Konstruktoren in Interfaces zu haben. - Es gibt eine Implementierung von gibObergrenze Implementierungen in Interfaces sind nicht zulssig.

bung 10.46 Laden Sie sich die (momentan leider nur englisch verfgbare) Fassung foxes-andrabbits-10.46.zip herunter. Die Anzahl der Jger variiert. Das liegt daran, dass die neu geborenen Tiere einfach auf einem Feld platziert werden, ohne dass vorher geprft wird, ob dieses Feld bereits durch einen Akteur besetzt ist. Nur wenige nderungen sind in den anderen Klassen erforderlich: - Eine neue Methode muss in die Klasse Feld eingefhrt werden:
gibZufaelligePosition - Die Methode bevoelkere muss aktualisiert werden, damit sie auch Jger erzeugt.

bung 10.47
ArrayList: ensureCapacity removeRange trimToSize LinkedList: addFirst addLast getFirst getLast removeFirst removeLast

Diese Methoden sind nicht im Interface List definiert, weil nicht allen Listen diese Methoden gemeinsam sind, sondern diese spezifisch sind fr den jeweiligen Typ der Implementierung von List. bung 10.48 Die folgenden Interfaces werden erwhnt:
- List - Comparator - Comparable

bung 10.49 Eine Implementierung einer Klasse, die das Interface Comparable implementiert:
/** * Eine Klasse, die Kaffeesorten reprsentiert. */ public class Kaffee implementiert Comparable { // Die Strke des Kaffees private int staerke;

/** * Erstellt eine neue Kaffeesorte mit der gegebenen Strke */ public Kaffee(int staerke) { this.staerke = staerke; } public int compareTo(Object o) { int jeneStaerke = ((Kaffee) o).staerke; if (staerke > jeneStaerke) { return 1; } else if (staerke < jeneStaerke) { return -1; } else { return 0; } } public boolean equals(Object o) { if (o instanceof Kaffee) { return ((Kaffee) o).staerke == staerke; } else { return false; } } public int hashCode() { return staerke; } public String toString() { return "Kaffee" + staerke; } }

Und hier eine Klasse um zu testen, dass die Sortierung korrekt ist:
import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; public class Test { public void testComparable() { List<Kaffee> kaffees = new ArrayList<Kaffee>(); kaffees.add(new Kaffee(10)); kaffees.add(new Kaffee(2)); kaffees.add(new Kaffee(10)); kaffees.add(new Kaffee(20)); kaffees.add(new Kaffee(5)); Collections.sort(kaffees); for (Kaffee kaffee : kaffees) { System.out.println(kaffee); } } }

bung 10.50 Laden Sie sich die (momentan leider nur englisch verfgbare) Fassung foxes-andrabbits-10.50.zip herunter. bung 10.51 Laden Sie sich die (momentan leider nur englisch verfgbare) Fassung foxes-andrabbits-10.51.zip herunter. bung 10.52 In dem nachfolgend genannten Programm haben wir eine Liste von Ansichten angelegt, die alle aktualisiert werden, wenn das erforderlich ist. Das haben wir auf eine Art und Weise gemacht, die uns erlaubt, eine beliebige Anzahl von Ansichten hinzuzufgen. Um zu vermeiden, dass zahlreiche nderungen der Klasse Simulator notwendig werden, haben wir eine neue Art von Ansicht namens MultiView geschaffen, die die Methodenaufrufe an verschiedene andere Ansichten delegieren kann. Laden Sie sich die (momentan leider nur englisch verfgbare) Fassung foxes-andrabbits-10.52.zip herunter. bung 10.53 a) Ja, eine abstrakte Klasse kann konkrete Methoden haben. Wenn sie keine konkreten Methoden haben knnte, wre sie nahezu identisch mit einem Java-Interface.

b) Nein, eine konkrete Klasse kann keine abstrakten Methoden haben. Wenn sie welche haben knnte, wre es nicht mglich, ein Objekt dieser Klasse zu erzeugen. Welche Implementierung sollte ausgefhrt werden, wenn Sie versuchen, eine abstrakte Methode aufzurufen, die nicht implementiert ist? c) Ja, Sie knnen eine abstrakte Klasse ohne jegliche abstrakte Methoden definieren. Siehe bung 10.29. bung 10.54 All diese Typen knnten Interfaces sein. Da G und X beide Superklassen fr U sind (zulssig: g=u, x=u) und zwischen ihnen keinerlei Beziehung besteht (nicht zulssig: g=x, x=g), muss wenigstens eine von G oder X ein Interface sein.

bung 10.55 Es knnten verschiedene mgliche Hierarchien erzeugt werden. Dies ist nur ein Beispiel (leider ist die Grafik momentan noch unbersetzt):

bung 10.56 Diese Adapter-Klassen stellen lediglich eine Arbeitserleichterung fr Programmierer dar. Wenn der Programmierer wei, dass nur wenige der Methoden eines Interfaces verwendet werden, ist es immer noch notwendig, eine Implementierung fr alle Methoden in dem Interface zu schreiben. Wenn stattdessen die Adapter-Klasse eingesetzt wird, kann der Programmierer einfach die wenigen Methoden, die bentigt werden, berschreiben. Eine gngige Verwendung von Adapter-Klassen ist beispielsweise der MouseAdapter. Das Interface MouseListener enthlt fnf Methoden, mit denen auf Mausereignisse gelauscht werden knnen. Wenn Sie nur auf Mausklicks reagieren wollten, dann mssten Sie in etwa das Folgende mit dem Interface tun:
import java.awt.event.MouseListener; import java.awt.event.MouseEvent; public class KlickAnzeiger implements MouseListener { public void mouseClicked(MouseEvent e) { System.out.println("Maus geklickt"); } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { }

public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } }

Mit dem MouseAdapter wrde es wie folgt aussehen:


import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class KlickAnzeiger extends MouseAdapter { public void mouseClicked(MouseEvent e) { System.out.println("Maus geklickt"); } }

bung 10.57 Wir mssen der Klasse TreeSet ein Mittel geben, um die Elemente sortieren zu knnen. Dies kann auf zwei Wegen geschehen: Entweder lassen wir Person das Interface Comparable implementieren, oder wir erstellen eine neue Klasse, die das Interface Comparator implementiert und in der Lage ist, Personen zu vergleichen. In bung 10.49, wo wir das Interface Comparable eingesetzt haben, sind wir hnlich vorgegangen. Also versuchen wir es diesmal mit Comparator. Die Klasse Person:
public class Person { private int alter; public Person(int alter) { this.alter = alter; } public int gibAlter() { return alter; } public boolean equals(Object jene) { if(jene instanceof Person) { return this.alter == ((Person) jene).alter; } else { return false; } } public int hashCode() { return alter; }

public String toString() { return "" + alter; } }

Die Klasse PersonComparator:


import java.util.Comparator; public class PersonComparator implements Comparator<Person> { public int compare(Person o1, Person o2) { if(p1.gibAlter() < p2. gibAlter()) { return -1; } else if(p1. gibAlter() == p2. gibAlter()) { return 0; } else { // (p1. gibAlter() > p2. gibAlter()) return 1; } } }

Eine Testklasse:
import java.util.Set; import java.util.TreeSet; import java.util.Iterator; public class Test { public static void runTest() { Set persons = new TreeSet(new PersonComparator()); persons.add(new Person(32)); persons.add(new Person(17)); persons.add(new Person(13)); persons.add(new Person(35)); persons.add(new Person(27)); Iterator iter = persons.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } } }

Kapitel 11
bung 11.1 Der Text ist stets vertikal mittig ausgerichtet. bung 11.2 Der Parameter wird als Titel des Rahmens verwendet. bung 11.3 Der Quelltext fr die Erzeugung eines Knopfs:
JButton knopf = new JButton("Ich bin ein Knopf. Ich kann einen Text haben. Sie knnen mich auch anklicken."); contentPane.add(knopf);

bung 11.4 Der Quelltext fr die Erzeugung eines weiteren Knopfs:


JButton knopf2 = new JButton("Ich bin auch ein Knopf."); contentPane.add(knopf2);

Nur der letzte Knopf ist sichtbar. Es sieht so aus, als htte er den ersten Knopf, der hinzugefgt wurde, ersetzt. bung 11.5 Nichts passiert, wenn Sie einen Meneintrag selektieren. bung 11.6 Die Methode zur Erzeugung der Menzeile sieht jetzt so aus:
private void menuezeileErzeugen() { JMenuBar menuezeile = new JMenuBar(); fenster.setJMenuBar(menuezeile); JMenu dateimenue = new JMenu("Datei"); menuezeile.add(dateimenue); JMenuItem oeffnenEintrag = new JMenuItem("ffnen"); dateimenue.add(oeffnenEintrag); JMenuItem beendenEintrag = new JMenuItem("Beenden"); dateimenue.add(beendenEintrag); JMenu hilfemenue = new JMenu("Hilfe"); menuezeile.add(hilfemenue); JMenuItem ueber = new JMenuItem("ber Bildbetrachter"); hilfemenue.add(ueber); }

bung 11.15 Wenn die Fenstergre verndert wird, nachdem das Bild bereits geladen ist, wird nicht die Gre des Bildes verndert, sondern nur dessen Rahmen. Ein Verndern der Fenstergre und anschlieendes ffnen eines Bildes hat keine Auswirkungen, da beim Laden eines Bildes die Gre des Rahmens so angepasst wird, dass sie der des neuen Bildes entspricht. bung 11.16 Das Fenster zeigt jetzt nur das Label mit der Versionsnummer an. Es wird kein Bild dargestellt. bung 11.17 Das Projekt Rechner-GUI verwendet BorderLayout und GridLayout. bung 11.18 Das Editorfenster in BlueJ ist mithilfe von BorderLayout und BoxLayout erstellt. BorderLayout wird fr das Hauptpanel verwendet. Die Werkzeugleiste benutzt BoxLayout und das Statuspanel BorderLayout. bung 11.19 Der Dialog Klasse aus Bibliothek verwenden benutzt BorderLayout und FlowLayout. bung 11.22 Lsungen zu bungen, die Programmierung erfordern, finden Sie in den Projekten auf der CD (Bildbetrachter1-0, Bildbetrachter2-0...). bung 11.23 Die Methode fenster.repaint aktualisiert die Anzeige des Bildes, nachdem wir den Bildinhalt verndert haben. bung 11.25 Die folgende Meldung wird in dem Statuslabel angezeigt: Kein Bild geladen. bung 11.26 Die Methode abdunkeln besorgt sich die Breite und Hhe des Bildes und verndert dann Pixel fr Pixel die Farbe der Bildpunkte. Hierbei kommt die Methode darker, die zu der Klasse OFImage gehrt, zum Einsatz.

bung 11.31 static void showMessageDialog(Component parentComponent, Object message) ffnet einen Dialog "Message" mit einer Informationsmeldung. static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) ffnet einen Dialog mit einer Meldung, welche ein vom Parameter messageType vorgegebenes Standard-Icon anzeigt. static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) ffnet einen Dialog, der eine Meldung anzeigt und fr den alle Parameter im Aufruf bestimmt werden. Wir sollten die zweite Methode verwenden, da diese es uns gestattet, einen richtigen Titel fr den Dialog festzulegen. bung 11.33 Die Dokumentation fr JTextArea: http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTextField.html Ein ActionListener wird benachrichtigt, sobald die Eingabetaste gedrckt wird. Mit der Methode setEditable(boolean b) lsst sich unterbinden, dass der Anwender in das Textfeld hineinschreiben kann. bung 11.49 Creating a GUI with JFC/Swing bung 11.50
BorderLayout BoxLayout CardLayout FlowLayout GridBagLayout GridLayout SpringLayout OverlayLayout

bung 11.51 Siehe How to Use Sliders bung 11.52 Siehe How to Use Tabbed Panes

bung 11.53 Siehe JSpinner documentation bung 11.54 Siehe ProgressBarDemo.java bung 11.55 Siehe ProgressBarDemo.java bung 11.67-11.72 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung soundplayer.zip herunter. bung 11.73 Laden Sie sich die (leider momentan nur englisch verfgbare) Fassung zuul-withimages.zip herunter.